Repository: brewfactory/BrewMobile Branch: master Commit: 0b8e359d7866 Files: 926 Total size: 3.8 MB Directory structure: gitextract_trattway/ ├── .gitignore ├── BrewMobile/ │ ├── AppDelegate.swift │ ├── BrewManager.swift │ ├── ContentParser.swift │ ├── Images.xcassets/ │ │ ├── AppIcon.appiconset/ │ │ │ └── Contents.json │ │ ├── DesignerIcon.imageset/ │ │ │ └── Contents.json │ │ ├── HopIcon.imageset/ │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage/ │ │ └── Contents.json │ ├── Info.plist │ ├── Model/ │ │ ├── BrewPhase.swift │ │ └── BrewState.swift │ ├── RACUtils/ │ │ └── RAC.swift │ ├── View/ │ │ ├── BrewCell.swift │ │ ├── BrewCell.xib │ │ ├── BrewDesignerViewController.swift │ │ ├── BrewDesignerViewController.xib │ │ ├── BrewNewPhaseViewController.swift │ │ ├── BrewNewPhaseViewController.xib │ │ ├── BrewViewController.swift │ │ ├── BrewViewController.xib │ │ ├── PhaseCell.swift │ │ └── PhaseCell.xib │ └── ViewModel/ │ ├── BrewDesignerViewModel.swift │ └── BrewViewModel.swift ├── BrewMobile.xcodeproj/ │ ├── project.pbxproj │ ├── project.xcworkspace/ │ │ └── contents.xcworkspacedata │ └── xcshareddata/ │ └── xcschemes/ │ └── BrewMobile.xcscheme ├── BrewMobile.xcworkspace/ │ └── contents.xcworkspacedata ├── BrewMobileTests/ │ ├── BrewPhaseTestCase.swift │ ├── BrewStateTestCase.swift │ ├── ContentParserTestCase.swift │ └── Info.plist ├── Cartfile ├── Cartfile.resolved ├── Carthage/ │ └── Checkouts/ │ ├── ReactiveCocoa/ │ │ ├── .gitignore │ │ ├── .gitmodules │ │ ├── .travis.yml │ │ ├── CHANGELOG.md │ │ ├── CONTRIBUTING.md │ │ ├── Cartfile │ │ ├── Cartfile.private │ │ ├── Cartfile.resolved │ │ ├── Carthage/ │ │ │ └── Checkouts/ │ │ │ ├── Nimble/ │ │ │ │ ├── .gitignore │ │ │ │ ├── .travis.yml │ │ │ │ ├── CONTRIBUTING.md │ │ │ │ ├── LICENSE.md │ │ │ │ ├── Nimble/ │ │ │ │ │ ├── Adapters/ │ │ │ │ │ │ ├── AdapterProtocols.swift │ │ │ │ │ │ ├── AssertionDispatcher.swift │ │ │ │ │ │ ├── AssertionRecorder.swift │ │ │ │ │ │ ├── NimbleEnvironment.swift │ │ │ │ │ │ └── NimbleXCTestHandler.swift │ │ │ │ │ ├── DSL+Wait.swift │ │ │ │ │ ├── DSL.swift │ │ │ │ │ ├── Expectation.swift │ │ │ │ │ ├── Expression.swift │ │ │ │ │ ├── FailureMessage.swift │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── Matchers/ │ │ │ │ │ │ ├── AllPass.swift │ │ │ │ │ │ ├── BeAKindOf.swift │ │ │ │ │ │ ├── BeAnInstanceOf.swift │ │ │ │ │ │ ├── BeCloseTo.swift │ │ │ │ │ │ ├── BeEmpty.swift │ │ │ │ │ │ ├── BeGreaterThan.swift │ │ │ │ │ │ ├── BeGreaterThanOrEqualTo.swift │ │ │ │ │ │ ├── BeIdenticalTo.swift │ │ │ │ │ │ ├── BeLessThan.swift │ │ │ │ │ │ ├── BeLessThanOrEqual.swift │ │ │ │ │ │ ├── BeLogical.swift │ │ │ │ │ │ ├── BeNil.swift │ │ │ │ │ │ ├── BeginWith.swift │ │ │ │ │ │ ├── Contain.swift │ │ │ │ │ │ ├── EndWith.swift │ │ │ │ │ │ ├── Equal.swift │ │ │ │ │ │ ├── HaveCount.swift │ │ │ │ │ │ ├── Match.swift │ │ │ │ │ │ ├── MatcherProtocols.swift │ │ │ │ │ │ ├── RaisesException.swift │ │ │ │ │ │ ├── SatisfyAnyOf.swift │ │ │ │ │ │ └── ThrowError.swift │ │ │ │ │ ├── Nimble.h │ │ │ │ │ ├── ObjCExpectation.swift │ │ │ │ │ ├── Utils/ │ │ │ │ │ │ ├── Async.swift │ │ │ │ │ │ ├── Functional.swift │ │ │ │ │ │ ├── SourceLocation.swift │ │ │ │ │ │ └── Stringers.swift │ │ │ │ │ ├── Wrappers/ │ │ │ │ │ │ ├── AsyncMatcherWrapper.swift │ │ │ │ │ │ ├── MatcherFunc.swift │ │ │ │ │ │ └── ObjCMatcher.swift │ │ │ │ │ └── objc/ │ │ │ │ │ ├── DSL.h │ │ │ │ │ ├── DSL.m │ │ │ │ │ ├── NMBExceptionCapture.h │ │ │ │ │ └── NMBExceptionCapture.m │ │ │ │ ├── Nimble.podspec │ │ │ │ ├── Nimble.xcodeproj/ │ │ │ │ │ ├── project.pbxproj │ │ │ │ │ └── xcshareddata/ │ │ │ │ │ └── xcschemes/ │ │ │ │ │ ├── Nimble-OSX.xcscheme │ │ │ │ │ ├── Nimble-iOS.xcscheme │ │ │ │ │ └── Nimble-tvOS.xcscheme │ │ │ │ ├── NimbleTests/ │ │ │ │ │ ├── AsynchronousTest.swift │ │ │ │ │ ├── Helpers/ │ │ │ │ │ │ ├── ObjectWithLazyProperty.swift │ │ │ │ │ │ └── utils.swift │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── Matchers/ │ │ │ │ │ │ ├── AllPassTest.swift │ │ │ │ │ │ ├── BeAKindOfTest.swift │ │ │ │ │ │ ├── BeAnInstanceOfTest.swift │ │ │ │ │ │ ├── BeCloseToTest.swift │ │ │ │ │ │ ├── BeEmptyTest.swift │ │ │ │ │ │ ├── BeGreaterThanOrEqualToTest.swift │ │ │ │ │ │ ├── BeGreaterThanTest.swift │ │ │ │ │ │ ├── BeIdenticalToObjectTest.swift │ │ │ │ │ │ ├── BeIdenticalToTest.swift │ │ │ │ │ │ ├── BeLessThanOrEqualToTest.swift │ │ │ │ │ │ ├── BeLessThanTest.swift │ │ │ │ │ │ ├── BeLogicalTest.swift │ │ │ │ │ │ ├── BeNilTest.swift │ │ │ │ │ │ ├── BeginWithTest.swift │ │ │ │ │ │ ├── ContainTest.swift │ │ │ │ │ │ ├── EndWithTest.swift │ │ │ │ │ │ ├── EqualTest.swift │ │ │ │ │ │ ├── HaveCountTest.swift │ │ │ │ │ │ ├── MatchTest.swift │ │ │ │ │ │ ├── RaisesExceptionTest.swift │ │ │ │ │ │ ├── SatisfyAnyOfTest.swift │ │ │ │ │ │ └── ThrowErrorTest.swift │ │ │ │ │ ├── SynchronousTests.swift │ │ │ │ │ ├── UserDescriptionTest.swift │ │ │ │ │ └── objc/ │ │ │ │ │ ├── Nimble-OSXTests-Bridging-Header.h │ │ │ │ │ ├── NimbleSpecHelper.h │ │ │ │ │ ├── NimbleTests-Bridging-Header.h │ │ │ │ │ ├── ObjCAllPassTest.m │ │ │ │ │ ├── ObjCAsyncTest.m │ │ │ │ │ ├── ObjCBeAnInstanceOfTest.m │ │ │ │ │ ├── ObjCBeCloseToTest.m │ │ │ │ │ ├── ObjCBeEmptyTest.m │ │ │ │ │ ├── ObjCBeFalseTest.m │ │ │ │ │ ├── ObjCBeFalsyTest.m │ │ │ │ │ ├── ObjCBeGreaterThanOrEqualToTest.m │ │ │ │ │ ├── ObjCBeGreaterThanTest.m │ │ │ │ │ ├── ObjCBeIdenticalToTest.m │ │ │ │ │ ├── ObjCBeKindOfTest.m │ │ │ │ │ ├── ObjCBeLessThanOrEqualToTest.m │ │ │ │ │ ├── ObjCBeLessThanTest.m │ │ │ │ │ ├── ObjCBeNilTest.m │ │ │ │ │ ├── ObjCBeTrueTest.m │ │ │ │ │ ├── ObjCBeTruthyTest.m │ │ │ │ │ ├── ObjCBeginWithTest.m │ │ │ │ │ ├── ObjCContainTest.m │ │ │ │ │ ├── ObjCEndWithTest.m │ │ │ │ │ ├── ObjCEqualTest.m │ │ │ │ │ ├── ObjCHaveCount.m │ │ │ │ │ ├── ObjCMatchTest.m │ │ │ │ │ ├── ObjCRaiseExceptionTest.m │ │ │ │ │ ├── ObjCSatisfyAnyOfTest.m │ │ │ │ │ ├── ObjCSyncTest.m │ │ │ │ │ └── ObjCUserDescriptionTest.m │ │ │ │ ├── README.md │ │ │ │ ├── circle.yml │ │ │ │ ├── script/ │ │ │ │ │ └── release │ │ │ │ └── test │ │ │ ├── Quick/ │ │ │ │ ├── .gitignore │ │ │ │ ├── .gitmodules │ │ │ │ ├── .travis.yml │ │ │ │ ├── CONTRIBUTING.md │ │ │ │ ├── Documentation/ │ │ │ │ │ ├── ArrangeActAssert.md │ │ │ │ │ ├── BehavioralTesting.md │ │ │ │ │ ├── ConfiguringQuick.md │ │ │ │ │ ├── InstallingFileTemplates.md │ │ │ │ │ ├── InstallingQuick.md │ │ │ │ │ ├── MoreResources.md │ │ │ │ │ ├── NimbleAssertions.md │ │ │ │ │ ├── QuickExamplesAndGroups.md │ │ │ │ │ ├── QuickInObjectiveC.md │ │ │ │ │ ├── README.md │ │ │ │ │ ├── SettingUpYourXcodeProject.md │ │ │ │ │ ├── SharedExamples.md │ │ │ │ │ └── TestingApps.md │ │ │ │ ├── Externals/ │ │ │ │ │ └── Nimble/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── .travis.yml │ │ │ │ │ ├── CONTRIBUTING.md │ │ │ │ │ ├── LICENSE.md │ │ │ │ │ ├── Nimble/ │ │ │ │ │ │ ├── Adapters/ │ │ │ │ │ │ │ ├── AdapterProtocols.swift │ │ │ │ │ │ │ ├── AssertionDispatcher.swift │ │ │ │ │ │ │ ├── AssertionRecorder.swift │ │ │ │ │ │ │ └── NimbleXCTestHandler.swift │ │ │ │ │ │ ├── DSL+Wait.swift │ │ │ │ │ │ ├── DSL.swift │ │ │ │ │ │ ├── Expectation.swift │ │ │ │ │ │ ├── Expression.swift │ │ │ │ │ │ ├── FailureMessage.swift │ │ │ │ │ │ ├── Info.plist │ │ │ │ │ │ ├── Matchers/ │ │ │ │ │ │ │ ├── AllPass.swift │ │ │ │ │ │ │ ├── BeAKindOf.swift │ │ │ │ │ │ │ ├── BeAnInstanceOf.swift │ │ │ │ │ │ │ ├── BeCloseTo.swift │ │ │ │ │ │ │ ├── BeEmpty.swift │ │ │ │ │ │ │ ├── BeGreaterThan.swift │ │ │ │ │ │ │ ├── BeGreaterThanOrEqualTo.swift │ │ │ │ │ │ │ ├── BeIdenticalTo.swift │ │ │ │ │ │ │ ├── BeLessThan.swift │ │ │ │ │ │ │ ├── BeLessThanOrEqual.swift │ │ │ │ │ │ │ ├── BeLogical.swift │ │ │ │ │ │ │ ├── BeNil.swift │ │ │ │ │ │ │ ├── BeginWith.swift │ │ │ │ │ │ │ ├── Contain.swift │ │ │ │ │ │ │ ├── EndWith.swift │ │ │ │ │ │ │ ├── Equal.swift │ │ │ │ │ │ │ ├── HaveCount.swift │ │ │ │ │ │ │ ├── Match.swift │ │ │ │ │ │ │ ├── MatcherProtocols.swift │ │ │ │ │ │ │ ├── RaisesException.swift │ │ │ │ │ │ │ └── ThrowError.swift │ │ │ │ │ │ ├── Nimble.h │ │ │ │ │ │ ├── ObjCExpectation.swift │ │ │ │ │ │ ├── Utils/ │ │ │ │ │ │ │ ├── Functional.swift │ │ │ │ │ │ │ ├── Poll.swift │ │ │ │ │ │ │ ├── SourceLocation.swift │ │ │ │ │ │ │ └── Stringers.swift │ │ │ │ │ │ ├── Wrappers/ │ │ │ │ │ │ │ ├── AsyncMatcherWrapper.swift │ │ │ │ │ │ │ ├── MatcherFunc.swift │ │ │ │ │ │ │ └── ObjCMatcher.swift │ │ │ │ │ │ └── objc/ │ │ │ │ │ │ ├── DSL.h │ │ │ │ │ │ ├── DSL.m │ │ │ │ │ │ ├── NMBExceptionCapture.h │ │ │ │ │ │ └── NMBExceptionCapture.m │ │ │ │ │ ├── Nimble.podspec │ │ │ │ │ ├── Nimble.xcodeproj/ │ │ │ │ │ │ ├── project.pbxproj │ │ │ │ │ │ └── xcshareddata/ │ │ │ │ │ │ └── xcschemes/ │ │ │ │ │ │ ├── Nimble-OSX.xcscheme │ │ │ │ │ │ ├── Nimble-iOS.xcscheme │ │ │ │ │ │ └── Nimble-tvOS.xcscheme │ │ │ │ │ ├── NimbleTests/ │ │ │ │ │ │ ├── AsynchronousTest.swift │ │ │ │ │ │ ├── Helpers/ │ │ │ │ │ │ │ ├── ObjectWithLazyProperty.swift │ │ │ │ │ │ │ └── utils.swift │ │ │ │ │ │ ├── Info.plist │ │ │ │ │ │ ├── Matchers/ │ │ │ │ │ │ │ ├── AllPassTest.swift │ │ │ │ │ │ │ ├── BeAKindOfTest.swift │ │ │ │ │ │ │ ├── BeAnInstanceOfTest.swift │ │ │ │ │ │ │ ├── BeCloseToTest.swift │ │ │ │ │ │ │ ├── BeEmptyTest.swift │ │ │ │ │ │ │ ├── BeGreaterThanOrEqualToTest.swift │ │ │ │ │ │ │ ├── BeGreaterThanTest.swift │ │ │ │ │ │ │ ├── BeIdenticalToObjectTest.swift │ │ │ │ │ │ │ ├── BeIdenticalToTest.swift │ │ │ │ │ │ │ ├── BeLessThanOrEqualToTest.swift │ │ │ │ │ │ │ ├── BeLessThanTest.swift │ │ │ │ │ │ │ ├── BeLogicalTest.swift │ │ │ │ │ │ │ ├── BeNilTest.swift │ │ │ │ │ │ │ ├── BeginWithTest.swift │ │ │ │ │ │ │ ├── ContainTest.swift │ │ │ │ │ │ │ ├── EndWithTest.swift │ │ │ │ │ │ │ ├── EqualTest.swift │ │ │ │ │ │ │ ├── HaveCountTest.swift │ │ │ │ │ │ │ ├── MatchTest.swift │ │ │ │ │ │ │ ├── RaisesExceptionTest.swift │ │ │ │ │ │ │ └── ThrowErrorTest.swift │ │ │ │ │ │ ├── SynchronousTests.swift │ │ │ │ │ │ ├── UserDescriptionTest.swift │ │ │ │ │ │ └── objc/ │ │ │ │ │ │ ├── Nimble-OSXTests-Bridging-Header.h │ │ │ │ │ │ ├── NimbleSpecHelper.h │ │ │ │ │ │ ├── NimbleTests-Bridging-Header.h │ │ │ │ │ │ ├── ObjCAllPassTest.m │ │ │ │ │ │ ├── ObjCAsyncTest.m │ │ │ │ │ │ ├── ObjCBeAnInstanceOfTest.m │ │ │ │ │ │ ├── ObjCBeCloseToTest.m │ │ │ │ │ │ ├── ObjCBeEmptyTest.m │ │ │ │ │ │ ├── ObjCBeFalseTest.m │ │ │ │ │ │ ├── ObjCBeFalsyTest.m │ │ │ │ │ │ ├── ObjCBeGreaterThanOrEqualToTest.m │ │ │ │ │ │ ├── ObjCBeGreaterThanTest.m │ │ │ │ │ │ ├── ObjCBeIdenticalToTest.m │ │ │ │ │ │ ├── ObjCBeKindOfTest.m │ │ │ │ │ │ ├── ObjCBeLessThanOrEqualToTest.m │ │ │ │ │ │ ├── ObjCBeLessThanTest.m │ │ │ │ │ │ ├── ObjCBeNilTest.m │ │ │ │ │ │ ├── ObjCBeTrueTest.m │ │ │ │ │ │ ├── ObjCBeTruthyTest.m │ │ │ │ │ │ ├── ObjCBeginWithTest.m │ │ │ │ │ │ ├── ObjCContainTest.m │ │ │ │ │ │ ├── ObjCEndWithTest.m │ │ │ │ │ │ ├── ObjCEqualTest.m │ │ │ │ │ │ ├── ObjCHaveCount.m │ │ │ │ │ │ ├── ObjCMatchTest.m │ │ │ │ │ │ ├── ObjCRaiseExceptionTest.m │ │ │ │ │ │ ├── ObjCSyncTest.m │ │ │ │ │ │ └── ObjCUserDescriptionTest.m │ │ │ │ │ ├── README.md │ │ │ │ │ ├── circle.yml │ │ │ │ │ ├── script/ │ │ │ │ │ │ └── release │ │ │ │ │ └── test │ │ │ │ ├── LICENSE │ │ │ │ ├── Quick/ │ │ │ │ │ ├── Callsite.swift │ │ │ │ │ ├── Configuration/ │ │ │ │ │ │ ├── Configuration.swift │ │ │ │ │ │ ├── QuickConfiguration.h │ │ │ │ │ │ └── QuickConfiguration.m │ │ │ │ │ ├── DSL/ │ │ │ │ │ │ ├── DSL.swift │ │ │ │ │ │ ├── QCKDSL.h │ │ │ │ │ │ ├── QCKDSL.m │ │ │ │ │ │ ├── World+DSL.h │ │ │ │ │ │ └── World+DSL.swift │ │ │ │ │ ├── Example.swift │ │ │ │ │ ├── ExampleGroup.swift │ │ │ │ │ ├── ExampleMetadata.swift │ │ │ │ │ ├── Filter.swift │ │ │ │ │ ├── Hooks/ │ │ │ │ │ │ ├── Closures.swift │ │ │ │ │ │ ├── ExampleHooks.swift │ │ │ │ │ │ └── SuiteHooks.swift │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── NSString+QCKSelectorName.h │ │ │ │ │ ├── NSString+QCKSelectorName.m │ │ │ │ │ ├── Quick.h │ │ │ │ │ ├── QuickSpec.h │ │ │ │ │ ├── QuickSpec.m │ │ │ │ │ ├── World.h │ │ │ │ │ └── World.swift │ │ │ │ ├── Quick Templates/ │ │ │ │ │ ├── Quick Configuration Class.xctemplate/ │ │ │ │ │ │ ├── Objective-C/ │ │ │ │ │ │ │ ├── ___FILEBASENAME___.h │ │ │ │ │ │ │ └── ___FILEBASENAME___.m │ │ │ │ │ │ ├── Swift/ │ │ │ │ │ │ │ └── ___FILEBASENAME___.swift │ │ │ │ │ │ ├── TemplateIcon.icns │ │ │ │ │ │ └── TemplateInfo.plist │ │ │ │ │ └── Quick Spec Class.xctemplate/ │ │ │ │ │ ├── Objective-C/ │ │ │ │ │ │ └── ___FILEBASENAME___.m │ │ │ │ │ ├── Swift/ │ │ │ │ │ │ └── ___FILEBASENAME___.swift │ │ │ │ │ ├── TemplateIcon.icns │ │ │ │ │ └── TemplateInfo.plist │ │ │ │ ├── Quick.podspec │ │ │ │ ├── Quick.xcodeproj/ │ │ │ │ │ ├── project.pbxproj │ │ │ │ │ └── xcshareddata/ │ │ │ │ │ └── xcschemes/ │ │ │ │ │ ├── Quick-OSX.xcscheme │ │ │ │ │ ├── Quick-iOS.xcscheme │ │ │ │ │ └── Quick-tvOS.xcscheme │ │ │ │ ├── QuickFocusedTests/ │ │ │ │ │ ├── FocusedTests+ObjC.m │ │ │ │ │ ├── FocusedTests.swift │ │ │ │ │ └── Info.plist │ │ │ │ ├── QuickTests/ │ │ │ │ │ ├── Fixtures/ │ │ │ │ │ │ └── FunctionalTests_SharedExamplesTests_SharedExamples.swift │ │ │ │ │ ├── FunctionalTests/ │ │ │ │ │ │ ├── AfterEachTests+ObjC.m │ │ │ │ │ │ ├── AfterEachTests.swift │ │ │ │ │ │ ├── AfterSuiteTests+ObjC.m │ │ │ │ │ │ ├── AfterSuiteTests.swift │ │ │ │ │ │ ├── BeforeEachTests+ObjC.m │ │ │ │ │ │ ├── BeforeEachTests.swift │ │ │ │ │ │ ├── BeforeSuiteTests+ObjC.m │ │ │ │ │ │ ├── BeforeSuiteTests.swift │ │ │ │ │ │ ├── Configuration/ │ │ │ │ │ │ │ ├── AfterEach/ │ │ │ │ │ │ │ │ ├── Configuration+AfterEach.swift │ │ │ │ │ │ │ │ └── Configuration+AfterEachTests.swift │ │ │ │ │ │ │ └── BeforeEach/ │ │ │ │ │ │ │ ├── Configuration+BeforeEach.swift │ │ │ │ │ │ │ └── Configuration+BeforeEachTests.swift │ │ │ │ │ │ ├── FailureTests+ObjC.m │ │ │ │ │ │ ├── FailureUsingXCTAssertTests+ObjC.m │ │ │ │ │ │ ├── ItTests+ObjC.m │ │ │ │ │ │ ├── ItTests.swift │ │ │ │ │ │ ├── PendingTests+ObjC.m │ │ │ │ │ │ ├── PendingTests.swift │ │ │ │ │ │ ├── SharedExamples+BeforeEachTests+ObjC.m │ │ │ │ │ │ ├── SharedExamples+BeforeEachTests.swift │ │ │ │ │ │ ├── SharedExamplesTests+ObjC.m │ │ │ │ │ │ └── SharedExamplesTests.swift │ │ │ │ │ ├── Helpers/ │ │ │ │ │ │ ├── QCKSpecRunner.h │ │ │ │ │ │ ├── QCKSpecRunner.m │ │ │ │ │ │ ├── QuickTestsBridgingHeader.h │ │ │ │ │ │ └── XCTestObservationCenter+QCKSuspendObservation.h │ │ │ │ │ ├── Info.plist │ │ │ │ │ └── QuickConfigurationTests.m │ │ │ │ ├── README.md │ │ │ │ ├── Rakefile │ │ │ │ ├── circle.yml │ │ │ │ └── script/ │ │ │ │ └── release │ │ │ ├── Result/ │ │ │ │ ├── .gitignore │ │ │ │ ├── .travis.yml │ │ │ │ ├── CONTRIBUTING.md │ │ │ │ ├── LICENSE │ │ │ │ ├── Package.swift │ │ │ │ ├── README.md │ │ │ │ ├── Result/ │ │ │ │ │ ├── Info.plist │ │ │ │ │ ├── Result.h │ │ │ │ │ ├── Result.swift │ │ │ │ │ └── ResultType.swift │ │ │ │ ├── Result.podspec │ │ │ │ ├── Result.xcodeproj/ │ │ │ │ │ ├── project.pbxproj │ │ │ │ │ └── xcshareddata/ │ │ │ │ │ └── xcschemes/ │ │ │ │ │ ├── Result-Mac.xcscheme │ │ │ │ │ ├── Result-iOS.xcscheme │ │ │ │ │ ├── Result-tvOS.xcscheme │ │ │ │ │ └── Result-watchOS.xcscheme │ │ │ │ └── Tests/ │ │ │ │ ├── Info.plist │ │ │ │ └── ResultTests.swift │ │ │ └── xcconfigs/ │ │ │ ├── .gitignore │ │ │ ├── Base/ │ │ │ │ ├── Common.xcconfig │ │ │ │ ├── Configurations/ │ │ │ │ │ ├── Debug.xcconfig │ │ │ │ │ ├── Profile.xcconfig │ │ │ │ │ ├── Release.xcconfig │ │ │ │ │ └── Test.xcconfig │ │ │ │ └── Targets/ │ │ │ │ ├── Application.xcconfig │ │ │ │ ├── Framework.xcconfig │ │ │ │ └── StaticLibrary.xcconfig │ │ │ ├── Mac OS X/ │ │ │ │ ├── Mac-Application.xcconfig │ │ │ │ ├── Mac-Base.xcconfig │ │ │ │ ├── Mac-DynamicLibrary.xcconfig │ │ │ │ ├── Mac-Framework.xcconfig │ │ │ │ └── Mac-StaticLibrary.xcconfig │ │ │ ├── README.md │ │ │ ├── iOS/ │ │ │ │ ├── iOS-Application.xcconfig │ │ │ │ ├── iOS-Base.xcconfig │ │ │ │ ├── iOS-Framework.xcconfig │ │ │ │ └── iOS-StaticLibrary.xcconfig │ │ │ ├── tvOS/ │ │ │ │ ├── tvOS-Application.xcconfig │ │ │ │ ├── tvOS-Base.xcconfig │ │ │ │ ├── tvOS-Framework.xcconfig │ │ │ │ └── tvOS-StaticLibrary.xcconfig │ │ │ └── watchOS/ │ │ │ ├── watchOS-Application.xcconfig │ │ │ ├── watchOS-Base.xcconfig │ │ │ ├── watchOS-Framework.xcconfig │ │ │ └── watchOS-StaticLibrary.xcconfig │ │ ├── Documentation/ │ │ │ ├── BasicOperators.md │ │ │ ├── DebuggingTechniques.md │ │ │ ├── DesignGuidelines.md │ │ │ ├── FrameworkOverview.md │ │ │ ├── Legacy/ │ │ │ │ ├── BasicOperators.md │ │ │ │ ├── DesignGuidelines.md │ │ │ │ ├── FrameworkOverview.md │ │ │ │ ├── MemoryManagement.md │ │ │ │ └── README.md │ │ │ ├── ObjectiveCBridging.md │ │ │ └── README.md │ │ ├── Instruments/ │ │ │ ├── Disposable Growth.tracetemplate │ │ │ ├── README.md │ │ │ └── Signal Events.tracetemplate │ │ ├── LICENSE.md │ │ ├── Logo/ │ │ │ └── README.md │ │ ├── README.md │ │ ├── ReactiveCocoa/ │ │ │ ├── Info.plist │ │ │ ├── Objective-C/ │ │ │ │ ├── MKAnnotationView+RACSignalSupport.h │ │ │ │ ├── MKAnnotationView+RACSignalSupport.m │ │ │ │ ├── NSArray+RACSequenceAdditions.h │ │ │ │ ├── NSArray+RACSequenceAdditions.m │ │ │ │ ├── NSControl+RACCommandSupport.h │ │ │ │ ├── NSControl+RACCommandSupport.m │ │ │ │ ├── NSControl+RACTextSignalSupport.h │ │ │ │ ├── NSControl+RACTextSignalSupport.m │ │ │ │ ├── NSData+RACSupport.h │ │ │ │ ├── NSData+RACSupport.m │ │ │ │ ├── NSDictionary+RACSequenceAdditions.h │ │ │ │ ├── NSDictionary+RACSequenceAdditions.m │ │ │ │ ├── NSEnumerator+RACSequenceAdditions.h │ │ │ │ ├── NSEnumerator+RACSequenceAdditions.m │ │ │ │ ├── NSFileHandle+RACSupport.h │ │ │ │ ├── NSFileHandle+RACSupport.m │ │ │ │ ├── NSIndexSet+RACSequenceAdditions.h │ │ │ │ ├── NSIndexSet+RACSequenceAdditions.m │ │ │ │ ├── NSInvocation+RACTypeParsing.h │ │ │ │ ├── NSInvocation+RACTypeParsing.m │ │ │ │ ├── NSNotificationCenter+RACSupport.h │ │ │ │ ├── NSNotificationCenter+RACSupport.m │ │ │ │ ├── NSObject+RACAppKitBindings.h │ │ │ │ ├── NSObject+RACAppKitBindings.m │ │ │ │ ├── NSObject+RACDeallocating.h │ │ │ │ ├── NSObject+RACDeallocating.m │ │ │ │ ├── NSObject+RACDescription.h │ │ │ │ ├── NSObject+RACDescription.m │ │ │ │ ├── NSObject+RACKVOWrapper.h │ │ │ │ ├── NSObject+RACKVOWrapper.m │ │ │ │ ├── NSObject+RACLifting.h │ │ │ │ ├── NSObject+RACLifting.m │ │ │ │ ├── NSObject+RACPropertySubscribing.h │ │ │ │ ├── NSObject+RACPropertySubscribing.m │ │ │ │ ├── NSObject+RACSelectorSignal.h │ │ │ │ ├── NSObject+RACSelectorSignal.m │ │ │ │ ├── NSOrderedSet+RACSequenceAdditions.h │ │ │ │ ├── NSOrderedSet+RACSequenceAdditions.m │ │ │ │ ├── NSSet+RACSequenceAdditions.h │ │ │ │ ├── NSSet+RACSequenceAdditions.m │ │ │ │ ├── NSString+RACKeyPathUtilities.h │ │ │ │ ├── NSString+RACKeyPathUtilities.m │ │ │ │ ├── NSString+RACSequenceAdditions.h │ │ │ │ ├── NSString+RACSequenceAdditions.m │ │ │ │ ├── NSString+RACSupport.h │ │ │ │ ├── NSString+RACSupport.m │ │ │ │ ├── NSText+RACSignalSupport.h │ │ │ │ ├── NSText+RACSignalSupport.m │ │ │ │ ├── NSURLConnection+RACSupport.h │ │ │ │ ├── NSURLConnection+RACSupport.m │ │ │ │ ├── NSUserDefaults+RACSupport.h │ │ │ │ ├── NSUserDefaults+RACSupport.m │ │ │ │ ├── RACArraySequence.h │ │ │ │ ├── RACArraySequence.m │ │ │ │ ├── RACBehaviorSubject.h │ │ │ │ ├── RACBehaviorSubject.m │ │ │ │ ├── RACBlockTrampoline.h │ │ │ │ ├── RACBlockTrampoline.m │ │ │ │ ├── RACChannel.h │ │ │ │ ├── RACChannel.m │ │ │ │ ├── RACCommand.h │ │ │ │ ├── RACCommand.m │ │ │ │ ├── RACCompoundDisposable.h │ │ │ │ ├── RACCompoundDisposable.m │ │ │ │ ├── RACCompoundDisposableProvider.d │ │ │ │ ├── RACDelegateProxy.h │ │ │ │ ├── RACDelegateProxy.m │ │ │ │ ├── RACDisposable.h │ │ │ │ ├── RACDisposable.m │ │ │ │ ├── RACDynamicPropertySuperclass.h │ │ │ │ ├── RACDynamicPropertySuperclass.m │ │ │ │ ├── RACDynamicSequence.h │ │ │ │ ├── RACDynamicSequence.m │ │ │ │ ├── RACDynamicSignal.h │ │ │ │ ├── RACDynamicSignal.m │ │ │ │ ├── RACEagerSequence.h │ │ │ │ ├── RACEagerSequence.m │ │ │ │ ├── RACEmptySequence.h │ │ │ │ ├── RACEmptySequence.m │ │ │ │ ├── RACEmptySignal.h │ │ │ │ ├── RACEmptySignal.m │ │ │ │ ├── RACErrorSignal.h │ │ │ │ ├── RACErrorSignal.m │ │ │ │ ├── RACEvent.h │ │ │ │ ├── RACEvent.m │ │ │ │ ├── RACGroupedSignal.h │ │ │ │ ├── RACGroupedSignal.m │ │ │ │ ├── RACImmediateScheduler.h │ │ │ │ ├── RACImmediateScheduler.m │ │ │ │ ├── RACIndexSetSequence.h │ │ │ │ ├── RACIndexSetSequence.m │ │ │ │ ├── RACKVOChannel.h │ │ │ │ ├── RACKVOChannel.m │ │ │ │ ├── RACKVOProxy.h │ │ │ │ ├── RACKVOProxy.m │ │ │ │ ├── RACKVOTrampoline.h │ │ │ │ ├── RACKVOTrampoline.m │ │ │ │ ├── RACMulticastConnection+Private.h │ │ │ │ ├── RACMulticastConnection.h │ │ │ │ ├── RACMulticastConnection.m │ │ │ │ ├── RACObjCRuntime.h │ │ │ │ ├── RACObjCRuntime.m │ │ │ │ ├── RACPassthroughSubscriber.h │ │ │ │ ├── RACPassthroughSubscriber.m │ │ │ │ ├── RACQueueScheduler+Subclass.h │ │ │ │ ├── RACQueueScheduler.h │ │ │ │ ├── RACQueueScheduler.m │ │ │ │ ├── RACReplaySubject.h │ │ │ │ ├── RACReplaySubject.m │ │ │ │ ├── RACReturnSignal.h │ │ │ │ ├── RACReturnSignal.m │ │ │ │ ├── RACScheduler+Private.h │ │ │ │ ├── RACScheduler+Subclass.h │ │ │ │ ├── RACScheduler.h │ │ │ │ ├── RACScheduler.m │ │ │ │ ├── RACScopedDisposable.h │ │ │ │ ├── RACScopedDisposable.m │ │ │ │ ├── RACSequence.h │ │ │ │ ├── RACSequence.m │ │ │ │ ├── RACSerialDisposable.h │ │ │ │ ├── RACSerialDisposable.m │ │ │ │ ├── RACSignal+Operations.h │ │ │ │ ├── RACSignal+Operations.m │ │ │ │ ├── RACSignal.h │ │ │ │ ├── RACSignal.m │ │ │ │ ├── RACSignalProvider.d │ │ │ │ ├── RACSignalSequence.h │ │ │ │ ├── RACSignalSequence.m │ │ │ │ ├── RACStream+Private.h │ │ │ │ ├── RACStream.h │ │ │ │ ├── RACStream.m │ │ │ │ ├── RACStringSequence.h │ │ │ │ ├── RACStringSequence.m │ │ │ │ ├── RACSubject.h │ │ │ │ ├── RACSubject.m │ │ │ │ ├── RACSubscriber+Private.h │ │ │ │ ├── RACSubscriber.h │ │ │ │ ├── RACSubscriber.m │ │ │ │ ├── RACSubscriptingAssignmentTrampoline.h │ │ │ │ ├── RACSubscriptingAssignmentTrampoline.m │ │ │ │ ├── RACSubscriptionScheduler.h │ │ │ │ ├── RACSubscriptionScheduler.m │ │ │ │ ├── RACTargetQueueScheduler.h │ │ │ │ ├── RACTargetQueueScheduler.m │ │ │ │ ├── RACTestScheduler.h │ │ │ │ ├── RACTestScheduler.m │ │ │ │ ├── RACTuple.h │ │ │ │ ├── RACTuple.m │ │ │ │ ├── RACTupleSequence.h │ │ │ │ ├── RACTupleSequence.m │ │ │ │ ├── RACUnarySequence.h │ │ │ │ ├── RACUnarySequence.m │ │ │ │ ├── RACUnit.h │ │ │ │ ├── RACUnit.m │ │ │ │ ├── RACValueTransformer.h │ │ │ │ ├── RACValueTransformer.m │ │ │ │ ├── ReactiveCocoa-Bridging-Header.h │ │ │ │ ├── UIActionSheet+RACSignalSupport.h │ │ │ │ ├── UIActionSheet+RACSignalSupport.m │ │ │ │ ├── UIAlertView+RACSignalSupport.h │ │ │ │ ├── UIAlertView+RACSignalSupport.m │ │ │ │ ├── UIBarButtonItem+RACCommandSupport.h │ │ │ │ ├── UIBarButtonItem+RACCommandSupport.m │ │ │ │ ├── UIButton+RACCommandSupport.h │ │ │ │ ├── UIButton+RACCommandSupport.m │ │ │ │ ├── UICollectionReusableView+RACSignalSupport.h │ │ │ │ ├── UICollectionReusableView+RACSignalSupport.m │ │ │ │ ├── UIControl+RACSignalSupport.h │ │ │ │ ├── UIControl+RACSignalSupport.m │ │ │ │ ├── UIControl+RACSignalSupportPrivate.h │ │ │ │ ├── UIControl+RACSignalSupportPrivate.m │ │ │ │ ├── UIDatePicker+RACSignalSupport.h │ │ │ │ ├── UIDatePicker+RACSignalSupport.m │ │ │ │ ├── UIGestureRecognizer+RACSignalSupport.h │ │ │ │ ├── UIGestureRecognizer+RACSignalSupport.m │ │ │ │ ├── UIImagePickerController+RACSignalSupport.h │ │ │ │ ├── UIImagePickerController+RACSignalSupport.m │ │ │ │ ├── UIRefreshControl+RACCommandSupport.h │ │ │ │ ├── UIRefreshControl+RACCommandSupport.m │ │ │ │ ├── UISegmentedControl+RACSignalSupport.h │ │ │ │ ├── UISegmentedControl+RACSignalSupport.m │ │ │ │ ├── UISlider+RACSignalSupport.h │ │ │ │ ├── UISlider+RACSignalSupport.m │ │ │ │ ├── UIStepper+RACSignalSupport.h │ │ │ │ ├── UIStepper+RACSignalSupport.m │ │ │ │ ├── UISwitch+RACSignalSupport.h │ │ │ │ ├── UISwitch+RACSignalSupport.m │ │ │ │ ├── UITableViewCell+RACSignalSupport.h │ │ │ │ ├── UITableViewCell+RACSignalSupport.m │ │ │ │ ├── UITableViewHeaderFooterView+RACSignalSupport.h │ │ │ │ ├── UITableViewHeaderFooterView+RACSignalSupport.m │ │ │ │ ├── UITextField+RACSignalSupport.h │ │ │ │ ├── UITextField+RACSignalSupport.m │ │ │ │ ├── UITextView+RACSignalSupport.h │ │ │ │ ├── UITextView+RACSignalSupport.m │ │ │ │ └── extobjc/ │ │ │ │ ├── EXTKeyPathCoding.h │ │ │ │ ├── EXTRuntimeExtensions.h │ │ │ │ ├── EXTRuntimeExtensions.m │ │ │ │ ├── EXTScope.h │ │ │ │ └── metamacros.h │ │ │ ├── ReactiveCocoa.h │ │ │ └── Swift/ │ │ │ ├── Action.swift │ │ │ ├── Atomic.swift │ │ │ ├── Bag.swift │ │ │ ├── Disposable.swift │ │ │ ├── Event.swift │ │ │ ├── Flatten.swift │ │ │ ├── FoundationExtensions.swift │ │ │ ├── ObjectiveCBridging.swift │ │ │ ├── Observer.swift │ │ │ ├── Optional.swift │ │ │ ├── Property.swift │ │ │ ├── Scheduler.swift │ │ │ ├── Signal.swift │ │ │ ├── SignalProducer.swift │ │ │ └── TupleExtensions.swift │ │ ├── ReactiveCocoa.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ └── xcshareddata/ │ │ │ └── xcschemes/ │ │ │ ├── ReactiveCocoa-Mac.xcscheme │ │ │ ├── ReactiveCocoa-iOS.xcscheme │ │ │ ├── ReactiveCocoa-tvOS.xcscheme │ │ │ └── ReactiveCocoa-watchOS.xcscheme │ │ ├── ReactiveCocoaTests/ │ │ │ ├── Info.plist │ │ │ ├── Objective-C/ │ │ │ │ ├── NSControllerRACSupportSpec.m │ │ │ │ ├── NSEnumeratorRACSequenceAdditionsSpec.m │ │ │ │ ├── NSNotificationCenterRACSupportSpec.m │ │ │ │ ├── NSObjectRACAppKitBindingsSpec.m │ │ │ │ ├── NSObjectRACDeallocatingSpec.m │ │ │ │ ├── NSObjectRACLiftingSpec.m │ │ │ │ ├── NSObjectRACPropertySubscribingExamples.h │ │ │ │ ├── NSObjectRACPropertySubscribingExamples.m │ │ │ │ ├── NSObjectRACPropertySubscribingSpec.m │ │ │ │ ├── NSObjectRACSelectorSignalSpec.m │ │ │ │ ├── NSStringRACKeyPathUtilitiesSpec.m │ │ │ │ ├── NSURLConnectionRACSupportSpec.m │ │ │ │ ├── NSUserDefaultsRACSupportSpec.m │ │ │ │ ├── RACBlockTrampolineSpec.m │ │ │ │ ├── RACChannelExamples.h │ │ │ │ ├── RACChannelExamples.m │ │ │ │ ├── RACChannelSpec.m │ │ │ │ ├── RACCommandSpec.m │ │ │ │ ├── RACCompoundDisposableSpec.m │ │ │ │ ├── RACControlCommandExamples.h │ │ │ │ ├── RACControlCommandExamples.m │ │ │ │ ├── RACDelegateProxySpec.m │ │ │ │ ├── RACDisposableSpec.m │ │ │ │ ├── RACEventSpec.m │ │ │ │ ├── RACKVOChannelSpec.m │ │ │ │ ├── RACKVOProxySpec.m │ │ │ │ ├── RACKVOWrapperSpec.m │ │ │ │ ├── RACMulticastConnectionSpec.m │ │ │ │ ├── RACPropertySignalExamples.h │ │ │ │ ├── RACPropertySignalExamples.m │ │ │ │ ├── RACSchedulerSpec.m │ │ │ │ ├── RACSequenceAdditionsSpec.m │ │ │ │ ├── RACSequenceExamples.h │ │ │ │ ├── RACSequenceExamples.m │ │ │ │ ├── RACSequenceSpec.m │ │ │ │ ├── RACSerialDisposableSpec.m │ │ │ │ ├── RACSignalSpec.m │ │ │ │ ├── RACStreamExamples.h │ │ │ │ ├── RACStreamExamples.m │ │ │ │ ├── RACSubclassObject.h │ │ │ │ ├── RACSubclassObject.m │ │ │ │ ├── RACSubjectSpec.m │ │ │ │ ├── RACSubscriberExamples.h │ │ │ │ ├── RACSubscriberExamples.m │ │ │ │ ├── RACSubscriberSpec.m │ │ │ │ ├── RACSubscriptingAssignmentTrampolineSpec.m │ │ │ │ ├── RACTargetQueueSchedulerSpec.m │ │ │ │ ├── RACTestExampleScheduler.h │ │ │ │ ├── RACTestExampleScheduler.m │ │ │ │ ├── RACTestObject.h │ │ │ │ ├── RACTestObject.m │ │ │ │ ├── RACTestSchedulerSpec.m │ │ │ │ ├── RACTestUIButton.h │ │ │ │ ├── RACTestUIButton.m │ │ │ │ ├── RACTupleSpec.m │ │ │ │ ├── UIActionSheetRACSupportSpec.m │ │ │ │ ├── UIAlertViewRACSupportSpec.m │ │ │ │ ├── UIBarButtonItemRACSupportSpec.m │ │ │ │ ├── UIButtonRACSupportSpec.m │ │ │ │ └── UIImagePickerControllerRACSupportSpec.m │ │ │ ├── Swift/ │ │ │ │ ├── ActionSpec.swift │ │ │ │ ├── AtomicSpec.swift │ │ │ │ ├── BagSpec.swift │ │ │ │ ├── DisposableSpec.swift │ │ │ │ ├── FlattenSpec.swift │ │ │ │ ├── FoundationExtensionsSpec.swift │ │ │ │ ├── ObjectiveCBridgingSpec.swift │ │ │ │ ├── PropertySpec.swift │ │ │ │ ├── SchedulerSpec.swift │ │ │ │ ├── SignalLifetimeSpec.swift │ │ │ │ ├── SignalProducerLiftingSpec.swift │ │ │ │ ├── SignalProducerNimbleMatchers.swift │ │ │ │ ├── SignalProducerSpec.swift │ │ │ │ ├── SignalSpec.swift │ │ │ │ └── TestError.swift │ │ │ └── test-data.json │ │ └── script/ │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── bootstrap │ │ ├── cibuild │ │ ├── schemes.awk │ │ ├── targets.awk │ │ ├── xcodebuild.awk │ │ └── xctool.awk │ ├── Result/ │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── CONTRIBUTING.md │ │ ├── LICENSE │ │ ├── Package.swift │ │ ├── README.md │ │ ├── Result/ │ │ │ ├── Info.plist │ │ │ ├── Result.h │ │ │ ├── Result.swift │ │ │ └── ResultType.swift │ │ ├── Result.podspec │ │ ├── Result.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace/ │ │ │ │ └── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ └── xcschemes/ │ │ │ ├── Result-Mac.xcscheme │ │ │ ├── Result-iOS.xcscheme │ │ │ ├── Result-tvOS.xcscheme │ │ │ └── Result-watchOS.xcscheme │ │ └── Tests/ │ │ ├── Info.plist │ │ └── ResultTests.swift │ ├── SIOSocket/ │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── SIOSocket.podspec │ │ ├── SocketIO/ │ │ │ ├── Info.plist │ │ │ ├── SocketIO.m │ │ │ └── Source/ │ │ │ ├── SIOSocket.h │ │ │ ├── SIOSocket.m │ │ │ └── socket.io.js.h │ │ ├── SocketIO.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace/ │ │ │ │ └── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ └── xcschemes/ │ │ │ ├── SocketIOFramework.xcscheme │ │ │ └── SocketIOHost.xcscheme │ │ ├── SocketIOFramework/ │ │ │ ├── Info.plist │ │ │ └── SocketIOFramework.h │ │ ├── SocketIOHost/ │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── Base.lproj/ │ │ │ │ └── Main.storyboard │ │ │ ├── Images.xcassets/ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ └── Contents.json │ │ │ │ └── LaunchImage.launchimage/ │ │ │ │ └── Contents.json │ │ │ ├── Info.plist │ │ │ ├── ViewController.h │ │ │ ├── ViewController.m │ │ │ └── main.m │ │ └── socket_tester/ │ │ └── app.js │ ├── SwiftyJSON/ │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── CHANGELOG.md │ │ ├── Example/ │ │ │ ├── Example/ │ │ │ │ ├── AppDelegate.swift │ │ │ │ ├── Base.lproj/ │ │ │ │ │ ├── LaunchScreen.xib │ │ │ │ │ └── Main.storyboard │ │ │ │ ├── Images.xcassets/ │ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── LaunchImage.launchimage/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Info.plist │ │ │ │ ├── SwiftyJSONTests.json │ │ │ │ └── ViewController.swift │ │ │ ├── Example.xcodeproj/ │ │ │ │ ├── project.pbxproj │ │ │ │ └── project.xcworkspace/ │ │ │ │ └── contents.xcworkspacedata │ │ │ └── Playground.playground/ │ │ │ ├── Contents.swift │ │ │ ├── contents.xcplayground │ │ │ └── timeline.xctimeline │ │ ├── LICENSE │ │ ├── Package.swift │ │ ├── README.md │ │ ├── Source/ │ │ │ ├── Info-OSX.plist │ │ │ ├── Info-iOS.plist │ │ │ ├── Info-tvOS.plist │ │ │ ├── Info-watchOS.plist │ │ │ ├── SwiftyJSON.h │ │ │ └── SwiftyJSON.swift │ │ ├── SwiftyJSON.podspec │ │ ├── SwiftyJSON.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace/ │ │ │ │ └── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ └── xcschemes/ │ │ │ ├── SwiftyJSON OSX.xcscheme │ │ │ ├── SwiftyJSON iOS.xcscheme │ │ │ ├── SwiftyJSON tvOS.xcscheme │ │ │ └── SwiftyJSON watchOS.xcscheme │ │ ├── SwiftyJSON.xcworkspace/ │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ └── WorkspaceSettings.xcsettings │ │ ├── Tests/ │ │ │ ├── ArrayTests.swift │ │ │ ├── BaseTests.swift │ │ │ ├── ComparableTests.swift │ │ │ ├── DictionaryTests.swift │ │ │ ├── Info-OSX.plist │ │ │ ├── Info-iOS.plist │ │ │ ├── Info-tvOS.plist │ │ │ ├── LiteralConvertibleTests.swift │ │ │ ├── NumberTests.swift │ │ │ ├── PerformanceTests.swift │ │ │ ├── PrintableTests.swift │ │ │ ├── RawRepresentableTests.swift │ │ │ ├── RawTests.swift │ │ │ ├── SequenceTypeTests.swift │ │ │ ├── StringTests.swift │ │ │ ├── SubscriptTests.swift │ │ │ └── Tests.json │ │ └── scripts/ │ │ └── ci.sh │ ├── iso-8601-date-formatter/ │ │ ├── .gitignore │ │ ├── .hgtags │ │ ├── .travis.yml │ │ ├── AppledocSettings.plist │ │ ├── ISO8601DateFormatter.h │ │ ├── ISO8601DateFormatter.m │ │ ├── ISO8601ForCocoa/ │ │ │ ├── ISO8601DateFormatter/ │ │ │ │ ├── ISO8601.h │ │ │ │ └── Info.plist │ │ │ ├── ISO8601ForCocoa/ │ │ │ │ └── ISO8601ForCocoa-Prefix.pch │ │ │ ├── ISO8601ForCocoa.xcodeproj/ │ │ │ │ ├── project.pbxproj │ │ │ │ ├── project.xcworkspace/ │ │ │ │ │ └── contents.xcworkspacedata │ │ │ │ └── xcshareddata/ │ │ │ │ └── xcschemes/ │ │ │ │ ├── ISO8601DateFormatter.xcscheme │ │ │ │ ├── ISO8601ForCocoa.xcscheme │ │ │ │ └── ISO8601ForCocoaTouch.xcscheme │ │ │ ├── ISO8601ForCocoaTests/ │ │ │ │ ├── ISO8601ForCocoaCalendarDateTests.h │ │ │ │ ├── ISO8601ForCocoaCalendarDateTests.m │ │ │ │ ├── ISO8601ForCocoaTests-Info.plist │ │ │ │ ├── ISO8601ForCocoaTimeOnlyTests.h │ │ │ │ ├── ISO8601ForCocoaTimeOnlyTests.m │ │ │ │ ├── ISO8601ForCocoaWeekDateTests.h │ │ │ │ ├── ISO8601ForCocoaWeekDateTests.m │ │ │ │ ├── ISO8601Testing.h │ │ │ │ ├── ISO8601Testing.m │ │ │ │ ├── MBMockLocale.h │ │ │ │ ├── MBMockLocale.m │ │ │ │ ├── NSLocale+UnitTestSwizzling.h │ │ │ │ ├── NSLocale+UnitTestSwizzling.m │ │ │ │ ├── PRHNamedCharacter.h │ │ │ │ └── en.lproj/ │ │ │ │ └── InfoPlist.strings │ │ │ ├── ISO8601ForCocoaTouch/ │ │ │ │ └── ISO8601ForCocoaTouch-Prefix.pch │ │ │ └── ISO8601ForCocoaTouchTests/ │ │ │ ├── ISO8601ForCocoaTouchTests-Info.plist │ │ │ ├── ISO8601MemoryWarningTests.h │ │ │ ├── ISO8601MemoryWarningTests.m │ │ │ └── en.lproj/ │ │ │ └── InfoPlist.strings │ │ ├── LICENSE.txt │ │ ├── Makefile │ │ ├── README.md │ │ ├── test_files/ │ │ │ ├── 2005-2006.txt │ │ │ ├── 2005.txt │ │ │ ├── 2006.txt │ │ │ ├── 2009-2010.txt │ │ │ ├── januaries.txt │ │ │ └── januaries3.txt │ │ ├── testparser.m │ │ ├── testparser.sh.in │ │ ├── testparser.sh.py │ │ ├── testunparser.sh │ │ ├── testunparsewithtime.m │ │ ├── timetrial.m │ │ ├── unparse-date.m │ │ ├── unparse-ordinaldate.m │ │ └── unparse-weekdate.m │ └── socket.io-client-swift/ │ ├── .gitignore │ ├── .travis.yml │ ├── LICENSE │ ├── Package.swift │ ├── README.md │ ├── Socket.IO-Client-Swift.podspec │ ├── Socket.IO-Test-Server/ │ │ ├── TestCases.js │ │ ├── acknowledgementEvents.js │ │ ├── emitEvents.js │ │ ├── main.js │ │ ├── package.json │ │ └── socketEventRegister.js │ ├── SocketIO-Mac/ │ │ ├── Info.plist │ │ └── SocketIO-Mac.h │ ├── SocketIO-MacTests/ │ │ ├── Info.plist │ │ ├── SocketAckManagerTest.swift │ │ ├── SocketBasicPacketTest.swift │ │ ├── SocketEngineTest.swift │ │ ├── SocketNamespacePacketTest.swift │ │ ├── SocketParserTest.swift │ │ └── SocketSideEffectTest.swift │ ├── SocketIO-iOS/ │ │ ├── Info.plist │ │ └── SocketIO-iOS.h │ ├── SocketIO-iOSTests/ │ │ └── Info.plist │ └── Source/ │ ├── SocketAckEmitter.swift │ ├── SocketAckManager.swift │ ├── SocketAnyEvent.swift │ ├── SocketClientSpec.swift │ ├── SocketEngine.swift │ ├── SocketEngineClient.swift │ ├── SocketEnginePacketType.swift │ ├── SocketEnginePollable.swift │ ├── SocketEngineSpec.swift │ ├── SocketEngineWebsocket.swift │ ├── SocketEventHandler.swift │ ├── SocketFixUTF8.swift │ ├── SocketIOClient.swift │ ├── SocketIOClientOption.swift │ ├── SocketIOClientStatus.swift │ ├── SocketLogger.swift │ ├── SocketPacket.swift │ ├── SocketParsable.swift │ ├── SocketStringReader.swift │ ├── SocketTypes.swift │ ├── SwiftRegex.swift │ └── WebSocket.swift └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ ## Build generated build/ DerivedData ## Various settings *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata ## Other *.xccheckout *.moved-aside *.xcuserstate *.xcscmblueprint ## Obj-C/Swift specific *.hmap *.ipa # Carthage Carthage/Build ================================================ FILE: BrewMobile/AppDelegate.swift ================================================ // // AppDelegate.swift // BrewMobile // // Created by Ágnes Vásárhelyi on 19/08/14. // Copyright (c) 2014 Ágnes Vásárhelyi. All rights reserved. // import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? var brewDesignerNavigationController: UINavigationController! var brewTabBarController: UITabBarController! func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool { brewTabBarController = UITabBarController() brewDesignerNavigationController = UINavigationController() let brewManager = BrewManager() let brewViewModel = BrewViewModel(brewManager: brewManager) let brewDesignerViewModel = BrewDesignerViewModel(brewManager: brewManager) let brewViewController = BrewViewController(brewViewModel: brewViewModel) let brewDesignerViewController = BrewDesignerViewController(brewDesignerViewModel: brewDesignerViewModel) brewDesignerNavigationController.pushViewController(brewDesignerViewController, animated: false) brewTabBarController.setViewControllers([brewViewController, brewDesignerNavigationController], animated: false) window = UIWindow(frame: UIScreen.mainScreen().bounds) window!.rootViewController = brewTabBarController window!.makeKeyAndVisible() return true } func applicationWillResignActive(application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } func applicationDidEnterBackground(application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } func applicationWillEnterForeground(application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } func applicationDidBecomeActive(application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } func applicationWillTerminate(application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } } ================================================ FILE: BrewMobile/BrewManager.swift ================================================ // // BrewManager.swift // BrewMobile // // Created by Agnes Vasarhelyi on 03/01/15. // Copyright (c) 2015 Ágnes Vásárhelyi. All rights reserved. // import Foundation import SwiftyJSON import ReactiveCocoa import Result import SocketIOClientSwift let tempChangedEvent = "temperature_changed" let brewChangedEvent = "brew_changed" let pwmChangedEvent = "pwm_changed" let host = "https://brewcore-demo.herokuapp.com/" class BrewManager : NSObject { var syncBrewAction: Action! var stopBrewAction: Action! var socket: SocketIOClient let temp = MutableProperty(0.0) let brew = MutableProperty(BrewState()) let pwm = MutableProperty(0.0) override init() { socket = SocketIOClient(socketURL:NSURL(string: host)!) super.init() syncBrewAction = Action { brewState in if let jsonData:AnyObject = BrewState.encode(brewState).value { let requestResult = self.requestWithBody("api/brew", method: "POST", body: JSON(jsonData)) if let requestResultValue = requestResult.value { return NSURLSession.sharedSession().rac_dataWithRequest(requestResultValue) .map { data, URLResponse in return data } } } fatalError("jsonData is nil") } stopBrewAction = Action { brewState in if let request = self.requestWithBody("api/brew/stop", method: "PATCH", body: "").value { return NSURLSession.sharedSession().rac_dataWithRequest(request) .map { data, URLResponse in return data } } fatalError("request is nil") } } //Mark: HTTP private func requestWithBody(path: String, method: String, body: JSON) -> Result { let request : NSMutableURLRequest = NSMutableURLRequest() request.URL = NSURL(string: host + path) request.HTTPMethod = method if method == "POST" { do { request.HTTPBody = try body.rawData(options: .PrettyPrinted) } catch let error as NSError { return Result(error: error) } } return Result(request) } // MARK: WebSocket func connectToHost() { socket.connect() socket.on(tempChangedEvent) { data, ack in if (data.count > 0) { if let temp = data[0] as? NSNumber { self.temp.value = temp.floatValue } } } socket.on(brewChangedEvent) { data, ack in if (data.count > 0) { self.brew.value = ContentParser.parseBrewState(JSON(data[0])) } } socket.on(pwmChangedEvent) { data, ack in if (data.count > 0) { if let pwm = data[0] as? NSNumber { self.pwm.value = pwm.floatValue } } } socket.on("connect") { data, ack in print("Connected to \(host)") } socket.on("disconnect") { data, ack in print("Disconnected from \(host)") } } } ================================================ FILE: BrewMobile/ContentParser.swift ================================================ // // ContentParser.swift // BrewMobile // // Created by Ágnes Vásárhelyi on 19/08/14. // Copyright (c) 2014 Ágnes Vásárhelyi. All rights reserved. // import Foundation import ISO8601 import SwiftyJSON import Result // MARK: JSONDecodable protocol JSONDecodable { static func decode(json: JSON) -> Result } // MARK: JSONEncodable protocol JSONEncodable { static func encode(object: Self) -> Result } typealias PhaseArray = [BrewPhase] class ContentParser { class func parseBrewState(brewJSON: JSON) -> BrewState { return BrewState.decode(brewJSON).value! } class func parseBrewPhase(brewPhaseJSON: JSON) -> BrewPhase { return BrewPhase.decode(brewPhaseJSON).value! } class func formatDate(dateString: String) -> String { if dateString.characters.count > 0 { let isoDateFormatter = ISO8601DateFormatter() let formattedDate = isoDateFormatter.dateFromString(dateString) let dateStringFormatter = NSDateFormatter() dateStringFormatter.dateFormat = "HH:mm" let formattedDateString = dateStringFormatter.stringFromDate(formattedDate!) return formattedDateString } return "" } } ================================================ FILE: BrewMobile/Images.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "size" : "29x29", "idiom" : "iphone", "filename" : "icon58.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "iphone_spotlight@2x.png", "scale" : "2x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "iphone_app_icon@2x.png", "scale" : "2x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "icon180.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: BrewMobile/Images.xcassets/DesignerIcon.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x", "filename" : "edit-disabled-2.png" }, { "idiom" : "universal", "scale" : "2x", "filename" : "edit-disabled-1.png" }, { "idiom" : "universal", "scale" : "3x", "filename" : "edit-disabled.png" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: BrewMobile/Images.xcassets/HopIcon.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x", "filename" : "hops-disabled2-2.png" }, { "idiom" : "universal", "scale" : "2x", "filename" : "hops-disabled2-1.png" }, { "idiom" : "universal", "scale" : "3x", "filename" : "hops-disabled2.png" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: BrewMobile/Images.xcassets/LaunchImage.launchimage/Contents.json ================================================ { "images" : [ { "orientation" : "portrait", "idiom" : "iphone", "extent" : "full-screen", "minimum-system-version" : "7.0", "filename" : "splash@2x.png", "scale" : "2x" }, { "extent" : "full-screen", "idiom" : "iphone", "subtype" : "retina4", "filename" : "splash-568h@2x.png", "minimum-system-version" : "7.0", "orientation" : "portrait", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: BrewMobile/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName brewfactory CFBundlePackageType APPL CFBundleShortVersionString 2.0.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: BrewMobile/Model/BrewPhase.swift ================================================ // // BrewPhase.swift // BrewMobile // // Created by Ágnes Vásárhelyi on 14/09/14. // Copyright (c) 2014 Ágnes Vásárhelyi. All rights reserved. // import Foundation import UIKit import Result import SwiftyJSON enum State: Int { case INACTIVE = 0 case HEATING case ACTIVE case FINISHED func stateDescription() -> String { switch self { case .INACTIVE: return "" case .HEATING: return "heating" case .ACTIVE: return "active" case .FINISHED: return "finished" } } func bgColor() -> UIColor { switch self { case .INACTIVE: return UIColor(red: 245.0 / 255.0, green:245.0 / 255.0, blue:245.0 / 255.0, alpha: 1.0) case .HEATING: return UIColor(red: 240.0 / 255.0, green:173.0 / 255.0, blue:78.0 / 255.0, alpha: 1.0) case .ACTIVE: return UIColor(red: 66.0 / 255.0, green:139.0 / 255.0, blue:202.0 / 255.0, alpha: 1.0) case .FINISHED: return UIColor(red: 92.0 / 255.0, green:184.0 / 255.0, blue:92.0 / 255.0, alpha: 1.0) } } } // MARK: Equatable func == (left: BrewPhase, right: BrewPhase) -> Bool { return (left.jobEnd == right.jobEnd) && (left.min == right.min) && (left.temp == right.temp) && (left.tempReached == right.tempReached) && (left.inProgress == right.inProgress) } final class BrewPhase: Equatable, JSONDecodable, JSONEncodable { var jobEnd: String var min: Int var temp: Float var tempReached: Bool var state: State var inProgress: Bool init() { jobEnd = "" min = 0 temp = 0 tempReached = false state = State.INACTIVE inProgress = false } init(jobEnd: String, min: Int, temp: Float, tempReached: Bool, inProgress: Bool) { self.jobEnd = jobEnd self.min = min self.temp = temp self.tempReached = tempReached self.state = { () -> State in switch (inProgress, tempReached) { case (true, false): return State.HEATING case (true, true): return State.ACTIVE case (false, true): return State.FINISHED case (false, false): fallthrough default: return State.INACTIVE } } () self.inProgress = inProgress } // MARK: JSONDecodable class func decode(json: JSON) -> Result { return Result(BrewPhase( jobEnd: ContentParser.formatDate(json["jobEnd"].stringValue), min: json["min"].intValue, temp: json["temp"].floatValue, tempReached: json["tempReached"].boolValue, inProgress: json["inProgress"].boolValue) ) } // MARK: JSONEncodable class func encode(object: BrewPhase) -> Result { var phase = [String: AnyObject]() phase["min"] = Int(object.min) phase["temp"] = Float(object.temp) return Result(phase) } } ================================================ FILE: BrewMobile/Model/BrewState.swift ================================================ // // BrewState.swift // BrewMobile // // Created by Ágnes Vásárhelyi on 14/09/14. // Copyright (c) 2014 Ágnes Vásárhelyi. All rights reserved. // import Foundation import ReactiveCocoa import Result import SwiftyJSON // MARK: Equatable func == (left: BrewState, right: BrewState) -> Bool { let phasesAreIdentical = { () -> Bool in for i in 0...left.phases.value.count - 1 { if left.phases.value[i] != right.phases.value[i] { return false } } return true }() return (left.name.value == right.name.value) && (left.startTime.value == right.startTime.value) && phasesAreIdentical && (left.paused.value == right.paused.value) && (left.inProgress.value == right.inProgress.value) } final class BrewState: Equatable, JSONDecodable, JSONEncodable { var name: MutableProperty var startTime: MutableProperty var phases: MutableProperty var paused: MutableProperty var inProgress: MutableProperty init() { name = MutableProperty("") startTime = MutableProperty("") phases = MutableProperty(PhaseArray()) paused = MutableProperty(false) inProgress = MutableProperty(false) } init(name: String, startTime: String, phases: PhaseArray, paused: Bool, inProgress: Bool) { self.name = MutableProperty(name) self.startTime = MutableProperty(startTime) self.phases = MutableProperty(phases) self.paused = MutableProperty(paused) self.inProgress = MutableProperty(inProgress) } init(name: MutableProperty, startTime: MutableProperty, phases: MutableProperty, paused: Bool, inProgress: Bool) { self.name = name self.startTime = startTime self.phases = phases self.paused = MutableProperty(paused) self.inProgress = MutableProperty(inProgress) } // MARK: JSONDecodable class func decode(json: JSON) -> Result { return Result(BrewState( name: json["name"].stringValue, startTime: ContentParser.formatDate(json["startTime"].stringValue), phases: json["phases"].arrayValue.map { (JSON rawPhase) -> BrewPhase in return ContentParser.parseBrewPhase(rawPhase) }, paused: json["paused"].boolValue, inProgress: json["inProgress"].boolValue) ) } // MARK: JSONEncodable class func encode(object: BrewState) -> Result { var brew = [String: AnyObject]() brew["name"] = object.name.value brew["startTime"] = object.startTime.value brew["phases"] = object.phases.value.map { (BrewPhase phase) -> AnyObject in return BrewPhase.encode(phase).value! } return Result(brew) } } ================================================ FILE: BrewMobile/RACUtils/RAC.swift ================================================ // // RAC.swift // // Created by Colin Eberhardt on 15/07/2014. // Copyright (c) 2014 Colin Eberhardt. All rights reserved. // // Original source can be found at: // https://github.com/ColinEberhardt/ReactiveTwitterSearch/blob/master/ReactiveTwitterSearch/Util/UIKitExtensions.swift // import Foundation import ReactiveCocoa import UIKit // see https://github.com/ReactiveCocoa/ReactiveCocoa/issues/2704 import enum Result.NoError public typealias NoError = Result.NoError struct AssociationKey { static var hidden: UInt8 = 1 static var date: UInt8 = 2 static var text: UInt8 = 3 } func lazyAssociatedProperty(host: AnyObject, key: UnsafePointer, factory: ()->T) -> T { return objc_getAssociatedObject(host, key) as? T ?? { let associatedProperty = factory() objc_setAssociatedObject(host, key, associatedProperty, .OBJC_ASSOCIATION_RETAIN) return associatedProperty }() } func lazyMutableProperty(host: AnyObject, key: UnsafePointer, setter: T -> (), getter: () -> T) -> MutableProperty { return lazyAssociatedProperty(host, key: key) { let property = MutableProperty(getter()) property.producer .startWithNext { newValue in setter(newValue) } return property } } extension UIView { public var rac_hidden: MutableProperty { return lazyMutableProperty(self, key: &AssociationKey.hidden, setter: { self.hidden = $0 }, getter: { self.hidden }) } } extension UILabel { public var rac_text: MutableProperty { return lazyMutableProperty(self, key: &AssociationKey.text, setter: { self.text = $0 }, getter: { self.text ?? "" }) } } extension UITextField { func rac_textSignalProducer() -> SignalProducer { return self.rac_textSignal().toSignalProducer() .map { $0 as! String } .flatMapError { _ in SignalProducer.empty } } } extension UITextField { public var rac_text: MutableProperty { return lazyAssociatedProperty(self, key: &AssociationKey.text) { self.addTarget(self, action: "changed", forControlEvents: UIControlEvents.EditingChanged) let property = MutableProperty(self.text ?? "") property.producer .startWithNext { newValue in self.text = newValue } return property } } func changed() { rac_text.value = self.text! } } ================================================ FILE: BrewMobile/View/BrewCell.swift ================================================ // // BrewCell.swift // BrewMobile // // Created by Agnes Vasarhelyi on 04/01/15. // Copyright (c) 2015 Ágnes Vásárhelyi. All rights reserved. // import UIKit class BrewCell: UITableViewCell { @IBOutlet weak var minLabel: UILabel! @IBOutlet weak var statusLabel: UILabel! func setTextColorForAllLabels(color: UIColor) { minLabel.textColor = color statusLabel.textColor = color } } ================================================ FILE: BrewMobile/View/BrewCell.xib ================================================ ================================================ FILE: BrewMobile/View/BrewDesignerViewController.swift ================================================ // // BrewDesignerViewController.swift // BrewMobile // // Created by Ágnes Vásárhelyi on 07/11/14. // Copyright (c) 2014 Ágnes Vásárhelyi. All rights reserved. // import UIKit import ISO8601 import ReactiveCocoa class BrewDesignerViewController : UIViewController, UITableViewDataSource, UITableViewDelegate, UIGestureRecognizerDelegate { @IBOutlet weak var nameTextField: UITextField! @IBOutlet weak var startTimeTextField: UITextField! @IBOutlet weak var phasesTableView: UITableView! @IBOutlet weak var startTimePicker: UIDatePicker! @IBOutlet weak var pickerBgView: UIView! @IBOutlet weak var editButton: UIButton! @IBOutlet weak var syncButton: UIButton! @IBOutlet weak var trashButton: UIButton! @IBOutlet weak var addButton: UIButton! @IBOutlet weak var tapGestureRecognizer: UITapGestureRecognizer! let brewDesignerViewModel: BrewDesignerViewModel let brewManager: BrewManager var cocoaActionTrash: CocoaAction! var cocoaActionEdit: CocoaAction! var cocoaActionAdd: CocoaAction! let tableViewEditing = MutableProperty(false) init(brewDesignerViewModel: BrewDesignerViewModel) { self.brewDesignerViewModel = brewDesignerViewModel self.brewManager = brewDesignerViewModel.brewManager super.init(nibName:"BrewDesignerViewController", bundle: nil) self.tabBarItem = UITabBarItem(title: "Designer", image: UIImage(named: "DesignerIcon"), tag: 0) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() let nib = UINib(nibName: "PhaseCell", bundle: nil) phasesTableView.registerNib(nib, forCellReuseIdentifier: "PhaseCell") let addAction = Action { if let navigationController = self.navigationController { navigationController.pushViewController(BrewNewPhaseViewController(brewDesignerViewModel: self.brewDesignerViewModel), animated: true) } return SignalProducer.empty } let editAction = Action(enabledIf: self.brewDesignerViewModel.hasPhases, { self.phasesTableView.editing = !self.phasesTableView.editing self.editButton.setTitle(self.phasesTableView.editing ? "Done" : "Edit", forState: .Normal) return SignalProducer.empty }) let trashAction = Action(enabledIf: self.brewDesignerViewModel.hasPhases, { self.brewDesignerViewModel.phases.value = PhaseArray() self.nameTextField.text = "" self.phasesTableView.reloadData() return SignalProducer.empty }) cocoaActionTrash = CocoaAction(trashAction, input: ()) cocoaActionEdit = CocoaAction(editAction, input: ()) cocoaActionAdd = CocoaAction(addAction, input: ()) syncButton.addTarget(self.brewDesignerViewModel.cocoaActionSync, action: CocoaAction.selector, forControlEvents: .TouchUpInside) trashButton.addTarget(cocoaActionTrash, action: CocoaAction.selector, forControlEvents: .TouchUpInside) editButton.addTarget(cocoaActionEdit, action: CocoaAction.selector, forControlEvents: .TouchUpInside) addButton.addTarget(cocoaActionAdd, action: CocoaAction.selector, forControlEvents: .TouchUpInside) self.brewManager.syncBrewAction.errors .observeOn(UIScheduler()) .observeNext { error in UIAlertView(title: "Error creating brew", message: error.localizedDescription, delegate: nil, cancelButtonTitle: "OK").show() } self.brewDesignerViewModel.hasPhases.producer .observeOn(UIScheduler()) .startWithNext { hasPhases in if !self.phasesTableView.editing { self.phasesTableView.reloadData() } if !(hasPhases as Bool) { self.phasesTableView.editing = false } } self.brewDesignerViewModel.name <~ self.nameTextField.rac_textSignalProducer() let startTimeTextFieldSignalProducer = self.startTimeTextField.rac_signalForControlEvents(.EditingDidBegin).toSignalProducer() startTimeTextFieldSignalProducer .startWithNext { _ in self.dismissKeyboards() } self.pickerBgView.rac_hidden <~ startTimeTextFieldSignalProducer .map { _ in false } .flatMapError { _ in SignalProducer.empty } let pickerDateSignalProducer = self.startTimePicker.rac_signalForControlEvents(.ValueChanged).toSignalProducer() .map { picker in if let datePicker = picker as? UIDatePicker { return datePicker.date } fatalError("this should not happen") } .flatMapError { _ in SignalProducer.empty } let nowDate = NSDate() self.startTimeTextField.rac_text.value = self.formatDateToShow(nowDate) self.brewDesignerViewModel.startTime.value = self.formatDateToUpdate(nowDate) self.startTimeTextField.rac_text <~ pickerDateSignalProducer .map { self.formatDateToShow($0) } .flatMapError { _ in SignalProducer.empty } self.brewDesignerViewModel.startTime <~ pickerDateSignalProducer .map { date in return self.formatDateToUpdate(date) } .flatMapError { _ in SignalProducer.empty } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } func dismissKeyboards() { self.view.endEditing(true) self.pickerBgView.hidden = true } func formatDateToShow(date: NSDate) -> String { let dateFormatter = NSDateFormatter() dateFormatter.dateFormat = "YYYY.MM.dd. HH:mm" return dateFormatter.stringFromDate(date as NSDate) } func formatDateToUpdate(date: NSDate) -> String { let isoDateFormatter = ISO8601DateFormatter() isoDateFormatter.defaultTimeZone = NSTimeZone.defaultTimeZone() isoDateFormatter.includeTime = true return isoDateFormatter.stringFromDate(date) } // MARK: UITableViewDataSource func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.brewDesignerViewModel.phases.value.count } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { if let cell = tableView.dequeueReusableCellWithIdentifier("PhaseCell", forIndexPath: indexPath) as? PhaseCell { if self.brewDesignerViewModel.phases.value.count > indexPath.row { let phase = self.brewDesignerViewModel.phases.value[indexPath.row] cell.phaseLabel.text = "\(indexPath.row + 1). \(phase.min) min \(phase.temp) ˚C" } return cell } fatalError("every cell must be a PhaseCell") } func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return "Phases" } func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { return true } func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool { return true } func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { if editingStyle == UITableViewCellEditingStyle.Delete { if self.brewDesignerViewModel.phases.value.count > indexPath.row { var newPhases = self.brewDesignerViewModel.phases.value newPhases.removeAtIndex(indexPath.row) self.brewDesignerViewModel.phases.value = newPhases tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic) } } } func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) { let destinationPhase = self.brewDesignerViewModel.phases.value[destinationIndexPath.row] var newPhases = self.brewDesignerViewModel.phases.value newPhases[destinationIndexPath.row] = newPhases[sourceIndexPath.row] newPhases[sourceIndexPath.row] = destinationPhase self.brewDesignerViewModel.phases.value = newPhases tableView.reloadData() } //MARK: UIGestureRecognizerDelegate func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool { if !touch.view!.isDescendantOfView(nameTextField) && !touch.view!.isDescendantOfView(pickerBgView) { dismissKeyboards() return false } return true } } ================================================ FILE: BrewMobile/View/BrewDesignerViewController.xib ================================================ ================================================ FILE: BrewMobile/View/BrewNewPhaseViewController.swift ================================================ // // BrewNewPhaseViewController.swift // BrewMobile // // Created by Ágnes Vásárhelyi on 08/11/14. // Copyright (c) 2014 Ágnes Vásárhelyi. All rights reserved. // import UIKit import ReactiveCocoa class BrewNewPhaseViewController : UIViewController { @IBOutlet weak var minTextField: UITextField! @IBOutlet weak var tempTextField: UITextField! @IBOutlet weak var minStepper: UIStepper! @IBOutlet weak var tempStepper: UIStepper! @IBOutlet weak var addButton: UIButton! @IBOutlet weak var feedbackLabel: UILabel! let brewDesignerViewModel: BrewDesignerViewModel var cocoaActionAdd: CocoaAction! init(brewDesignerViewModel: BrewDesignerViewModel) { self.brewDesignerViewModel = brewDesignerViewModel super.init(nibName:"BrewNewPhaseViewController", bundle: nil) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() let addAction = Action { let newPhase = BrewPhase(jobEnd:"", min:Int(self.minStepper.value), temp:Float(self.tempStepper.value), tempReached:false, inProgress:false) var newPhases = self.brewDesignerViewModel.phases.value newPhases.append(newPhase) self.brewDesignerViewModel.phases.value = newPhases return SignalProducer.empty } cocoaActionAdd = CocoaAction(addAction, input: ()) addButton.addTarget(cocoaActionAdd, action: CocoaAction.selector, forControlEvents: .TouchUpInside) addAction.executing.producer .on( next: { executing in if executing { self.feedbackLabel.text = "Phase added" UIView.animateWithDuration(0.7, animations: { () -> Void in self.feedbackLabel.alpha = 1.0 }, completion: { (Bool) -> Void in UIView.animateWithDuration(0.7, animations: { () -> Void in self.feedbackLabel.alpha = 0.0 }, completion: nil) }) } }) .start() let minStepperSignalProducer = minStepper.rac_signalForControlEvents(.ValueChanged).toSignalProducer() .map(self.mapStepper) .flatMapError(self.catcher) let tempStepperSignalProducer = tempStepper.rac_signalForControlEvents(.ValueChanged).toSignalProducer() .map(self.mapStepper) .flatMapError(self.catcher) let minTextSignalProducer = minTextField.rac_textSignalProducer() .filter(self.nonEmptyFilter) .map(self.toIntConverter) .flatMapError(self.catcher) let tempTextSignalProducer = tempTextField.rac_textSignalProducer() .filter(self.nonEmptyFilter) .map(self.toIntConverter) .flatMapError(self.catcher) SignalProducer(values: [minStepperSignalProducer, minTextSignalProducer]) .flatten(.Merge) .on( next: { min in self.minStepper.value = Double(Int(min)) self.minTextField.text = String(Int(min)) }) .start() SignalProducer(values: [tempStepperSignalProducer, tempTextSignalProducer]) .flatten(.Merge) .on( next: { temp in self.tempStepper.value = Double(Int(temp)) self.tempTextField.text = String(Int(temp)) }) .start() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } // MARK: helper functions func mapStepper(aStepper: AnyObject?) -> Int { if let stepper = aStepper as? UIStepper { return Int(stepper.value) } fatalError("stepper should be a UIStepper") } func catcher(aInput: E) -> SignalProducer { return SignalProducer.empty } func nonEmptyFilter(aInput: String) -> Bool { return aInput != "" } func toIntConverter(aInput: String) -> Int { return Int(aInput)! } } ================================================ FILE: BrewMobile/View/BrewNewPhaseViewController.xib ================================================ ================================================ FILE: BrewMobile/View/BrewViewController.swift ================================================ // // ViewController.swift // BrewMobile // // Created by Ágnes Vásárhelyi on 19/08/14. // Copyright (c) 2014 Ágnes Vásárhelyi. All rights reserved. // import UIKit import SwiftyJSON import ReactiveCocoa class BrewViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { let brewViewModel: BrewViewModel @IBOutlet weak var tempLabel: UILabel! @IBOutlet weak var pwmLabel: UILabel! @IBOutlet weak var nameLabel: UILabel! @IBOutlet weak var startTimeLabel: UILabel! @IBOutlet weak var phasesTableView: UITableView! @IBOutlet weak var stopButton: UIButton! init(brewViewModel: BrewViewModel) { self.brewViewModel = brewViewModel super.init(nibName:"BrewViewController", bundle: nil) self.tabBarItem = UITabBarItem(title: "Brew", image: UIImage(named: "HopIcon"), tag: 0) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() stopButton.addTarget(self.brewViewModel.cocoaActionStop, action: CocoaAction.selector, forControlEvents: .TouchUpInside) let nib = UINib(nibName: "BrewCell", bundle: nil) phasesTableView.registerNib(nib, forCellReuseIdentifier: "BrewCell") self.tempLabel.rac_text <~ self.brewViewModel.temp.producer .map { temp in return String(format:"%.2f ˚C", temp) } .flatMapError { _ in SignalProducer.empty } self.pwmLabel.rac_text <~ self.brewViewModel.pwm.producer .map { pwm in return String(format:"PWM %g %%", pwm) } .flatMapError { _ in SignalProducer.empty } self.brewViewModel.brew.producer .on (next: { brewState in self.phasesTableView.reloadData() if brewState.phases.value.count > 0 { self.nameLabel.text = "Brewing \(brewState.name.value) at" } else { self.nameLabel.text = "We are not brewing :(\nHow is it possible?" } self.startTimeLabel.text = brewState.phases.value.count > 0 ? "starting \(brewState.startTime.value)" : "" }) .start() } func stateText(brewPhase: BrewPhase) -> String { if self.brewViewModel.brew.value.paused.value { return "paused" } switch brewPhase.state { case State.FINISHED: return "\(brewPhase.state.stateDescription()) at \(brewPhase.jobEnd)" case State.HEATING: if self.brewViewModel.temp.value > brewPhase.temp { return "cooling" } fallthrough default: return brewPhase.state.stateDescription() } } // MARK: UITableViewDataSource func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.brewViewModel.brew.value.phases.value.count } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("BrewCell", forIndexPath: indexPath) as! BrewCell if self.brewViewModel.brew.value.phases.value.count > indexPath.row { let brewPhase = self.brewViewModel.brew.value.phases.value[indexPath.row] let showEnd: Bool = brewPhase.tempReached && brewPhase.inProgress cell.minLabel.text = showEnd ? "\(brewPhase.min) mins - \(Int(brewPhase.temp)) ˚C, ends: \(brewPhase.jobEnd)" : "\(brewPhase.min) mins - \(Int(brewPhase.temp)) ˚C" cell.statusLabel.text = "\(self.stateText(brewPhase))" UIView.animateWithDuration(0.3, animations: { () -> Void in cell.backgroundColor = brewPhase.state.bgColor() cell.setTextColorForAllLabels(brewPhase.state == State.INACTIVE ? UIColor.blackColor() : UIColor.whiteColor()) }) } return cell } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } } ================================================ FILE: BrewMobile/View/BrewViewController.xib ================================================ ================================================ FILE: BrewMobile/View/PhaseCell.swift ================================================ // // PhaseCell.swift // BrewMobile // // Created by Agnes Vasarhelyi on 04/01/15. // Copyright (c) 2015 Ágnes Vásárhelyi. All rights reserved. // import UIKit class PhaseCell: UITableViewCell { @IBOutlet weak var phaseLabel: UILabel! } ================================================ FILE: BrewMobile/View/PhaseCell.xib ================================================ ================================================ FILE: BrewMobile/ViewModel/BrewDesignerViewModel.swift ================================================ // // BrewDesignerViewModel.swift // BrewMobile // // Created by Agnes Vasarhelyi on 01/03/15. // Copyright (c) 2015 Ágnes Vásárhelyi. All rights reserved. // import Foundation import ReactiveCocoa class BrewDesignerViewModel : NSObject { let brewManager: BrewManager var cocoaActionSync: CocoaAction! let phases = MutableProperty(PhaseArray()) let name = MutableProperty("") let startTime = MutableProperty("") let brewState = MutableProperty(BrewState()) let hasPhases = MutableProperty(false) let validName = MutableProperty(false) let validBeer = MutableProperty(false) var newState: BrewState = BrewState() init(brewManager: BrewManager) { self.brewManager = brewManager super.init() brewState.value = (BrewState(name: name, startTime: startTime, phases: self.phases, paused: false, inProgress: false)) hasPhases <~ self.phases.producer .map { $0.count > 0 } validName <~ self.brewState.producer .map{ $0.name.value.characters.count > 0 } validBeer <~ combineLatest(hasPhases.producer, validName.producer) .map { $0 && $1 } cocoaActionSync = CocoaAction(brewManager.syncBrewAction, input: brewState.value) } } ================================================ FILE: BrewMobile/ViewModel/BrewViewModel.swift ================================================ // // BrewViewModel.swift // BrewMobile // // Created by Agnes Vasarhelyi on 04/01/15. // Copyright (c) 2015 Ágnes Vásárhelyi. All rights reserved. // import Foundation import ReactiveCocoa class BrewViewModel : NSObject { var cocoaActionStop: CocoaAction! let temp = MutableProperty(0.0) let brew = MutableProperty(BrewState()) let pwm = MutableProperty(0.0) let brewManager: BrewManager init(brewManager: BrewManager) { self.brewManager = brewManager super.init() self.brewManager.connectToHost() cocoaActionStop = CocoaAction(brewManager.stopBrewAction, input: ()) temp <~ self.brewManager.temp brew <~ self.brewManager.brew pwm <~ self.brewManager.pwm } } ================================================ FILE: BrewMobile.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 0213ADD21A57E6EB0010F9E1 /* BrewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0213ADD11A57E6EB0010F9E1 /* BrewManager.swift */; }; 023A3AD21C65FC3D004AD22E /* SocketIOClientSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 023A3AD01C65FC3D004AD22E /* SocketIOClientSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 0289A94C1A626C2600BD2601 /* ContentParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0289A94B1A626C2600BD2601 /* ContentParser.swift */; }; 0289A94D1A626C2600BD2601 /* ContentParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0289A94B1A626C2600BD2601 /* ContentParser.swift */; }; 0289A9521A62B0FF00BD2601 /* RAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0289A94F1A62B0FF00BD2601 /* RAC.swift */; }; 0289A9531A62B0FF00BD2601 /* RAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0289A94F1A62B0FF00BD2601 /* RAC.swift */; }; 02BDD66B1AA19BE100E44DC3 /* BrewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD6611AA19BE100E44DC3 /* BrewCell.swift */; }; 02BDD66C1AA19BE100E44DC3 /* BrewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD6611AA19BE100E44DC3 /* BrewCell.swift */; }; 02BDD66D1AA19BE100E44DC3 /* BrewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 02BDD6621AA19BE100E44DC3 /* BrewCell.xib */; }; 02BDD66E1AA19BE100E44DC3 /* BrewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 02BDD6621AA19BE100E44DC3 /* BrewCell.xib */; }; 02BDD66F1AA19BE100E44DC3 /* BrewDesignerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD6631AA19BE100E44DC3 /* BrewDesignerViewController.swift */; }; 02BDD6701AA19BE100E44DC3 /* BrewDesignerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD6631AA19BE100E44DC3 /* BrewDesignerViewController.swift */; }; 02BDD6711AA19BE100E44DC3 /* BrewDesignerViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 02BDD6641AA19BE100E44DC3 /* BrewDesignerViewController.xib */; }; 02BDD6721AA19BE100E44DC3 /* BrewDesignerViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 02BDD6641AA19BE100E44DC3 /* BrewDesignerViewController.xib */; }; 02BDD6731AA19BE100E44DC3 /* BrewNewPhaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD6651AA19BE100E44DC3 /* BrewNewPhaseViewController.swift */; }; 02BDD6741AA19BE100E44DC3 /* BrewNewPhaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD6651AA19BE100E44DC3 /* BrewNewPhaseViewController.swift */; }; 02BDD6751AA19BE100E44DC3 /* BrewNewPhaseViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 02BDD6661AA19BE100E44DC3 /* BrewNewPhaseViewController.xib */; }; 02BDD6761AA19BE100E44DC3 /* BrewNewPhaseViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 02BDD6661AA19BE100E44DC3 /* BrewNewPhaseViewController.xib */; }; 02BDD6771AA19BE100E44DC3 /* BrewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD6671AA19BE100E44DC3 /* BrewViewController.swift */; }; 02BDD6781AA19BE100E44DC3 /* BrewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD6671AA19BE100E44DC3 /* BrewViewController.swift */; }; 02BDD6791AA19BE100E44DC3 /* BrewViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 02BDD6681AA19BE100E44DC3 /* BrewViewController.xib */; }; 02BDD67A1AA19BE100E44DC3 /* BrewViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 02BDD6681AA19BE100E44DC3 /* BrewViewController.xib */; }; 02BDD67B1AA19BE100E44DC3 /* PhaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD6691AA19BE100E44DC3 /* PhaseCell.swift */; }; 02BDD67C1AA19BE100E44DC3 /* PhaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD6691AA19BE100E44DC3 /* PhaseCell.swift */; }; 02BDD67D1AA19BE100E44DC3 /* PhaseCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 02BDD66A1AA19BE100E44DC3 /* PhaseCell.xib */; }; 02BDD67E1AA19BE100E44DC3 /* PhaseCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 02BDD66A1AA19BE100E44DC3 /* PhaseCell.xib */; }; 02BDD6841AA19C3800E44DC3 /* BrewPhase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD6801AA19C3800E44DC3 /* BrewPhase.swift */; }; 02BDD6851AA19C3800E44DC3 /* BrewPhase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD6801AA19C3800E44DC3 /* BrewPhase.swift */; }; 02BDD6861AA19C3800E44DC3 /* BrewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD6811AA19C3800E44DC3 /* BrewState.swift */; }; 02BDD6871AA19C3800E44DC3 /* BrewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD6811AA19C3800E44DC3 /* BrewState.swift */; }; 02BDD6881AA19C3800E44DC3 /* BrewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD6831AA19C3800E44DC3 /* BrewViewModel.swift */; }; 02BDD6891AA19C3800E44DC3 /* BrewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD6831AA19C3800E44DC3 /* BrewViewModel.swift */; }; 02BDD68A1AA19C6200E44DC3 /* BrewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0213ADD11A57E6EB0010F9E1 /* BrewManager.swift */; }; 02BDD68C1AA2FF6700E44DC3 /* BrewDesignerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD68B1AA2FF6700E44DC3 /* BrewDesignerViewModel.swift */; }; 02BDD68D1AA2FF6700E44DC3 /* BrewDesignerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDD68B1AA2FF6700E44DC3 /* BrewDesignerViewModel.swift */; }; 02C058C31B6529F7001AC3C1 /* ISO8601.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 02C058B91B652990001AC3C1 /* ISO8601.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 02C058C41B6529F7001AC3C1 /* ReactiveCocoa.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 02C058BA1B652990001AC3C1 /* ReactiveCocoa.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 02C058C51B6529F7001AC3C1 /* Result.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 02C058BB1B652990001AC3C1 /* Result.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 02C058C71B6529F7001AC3C1 /* SwiftyJSON.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 02C058BD1B652990001AC3C1 /* SwiftyJSON.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 692AAA8919A34C8C00224C4D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 692AAA8819A34C8C00224C4D /* AppDelegate.swift */; }; 692AAA9019A34C8C00224C4D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 692AAA8F19A34C8C00224C4D /* Images.xcassets */; }; 69A1102619CB38B900108B46 /* BrewPhaseTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69A1102519CB38B900108B46 /* BrewPhaseTestCase.swift */; }; 69A1102D19CB596700108B46 /* BrewStateTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69A1102C19CB596700108B46 /* BrewStateTestCase.swift */; }; 69EC2A8D19CC3439008108D8 /* ContentParserTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69EC2A8C19CC3439008108D8 /* ContentParserTestCase.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 692AAA9619A34C8C00224C4D /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 692AAA7B19A34C8C00224C4D /* Project object */; proxyType = 1; remoteGlobalIDString = 692AAA8219A34C8C00224C4D; remoteInfo = BrewMobile; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 0213ADC81A57DB480010F9E1 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( 02C058C31B6529F7001AC3C1 /* ISO8601.framework in Embed Frameworks */, 02C058C41B6529F7001AC3C1 /* ReactiveCocoa.framework in Embed Frameworks */, 023A3AD21C65FC3D004AD22E /* SocketIOClientSwift.framework in Embed Frameworks */, 02C058C51B6529F7001AC3C1 /* Result.framework in Embed Frameworks */, 02C058C71B6529F7001AC3C1 /* SwiftyJSON.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 0213ADD11A57E6EB0010F9E1 /* BrewManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrewManager.swift; sourceTree = ""; }; 023A3AD01C65FC3D004AD22E /* SocketIOClientSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SocketIOClientSwift.framework; path = Carthage/Build/iOS/SocketIOClientSwift.framework; sourceTree = ""; }; 0289A94B1A626C2600BD2601 /* ContentParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentParser.swift; sourceTree = ""; }; 0289A94F1A62B0FF00BD2601 /* RAC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RAC.swift; sourceTree = ""; }; 02BDD6611AA19BE100E44DC3 /* BrewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrewCell.swift; sourceTree = ""; }; 02BDD6621AA19BE100E44DC3 /* BrewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BrewCell.xib; sourceTree = ""; }; 02BDD6631AA19BE100E44DC3 /* BrewDesignerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrewDesignerViewController.swift; sourceTree = ""; }; 02BDD6641AA19BE100E44DC3 /* BrewDesignerViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BrewDesignerViewController.xib; sourceTree = ""; }; 02BDD6651AA19BE100E44DC3 /* BrewNewPhaseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrewNewPhaseViewController.swift; sourceTree = ""; }; 02BDD6661AA19BE100E44DC3 /* BrewNewPhaseViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BrewNewPhaseViewController.xib; sourceTree = ""; }; 02BDD6671AA19BE100E44DC3 /* BrewViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrewViewController.swift; sourceTree = ""; }; 02BDD6681AA19BE100E44DC3 /* BrewViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BrewViewController.xib; sourceTree = ""; }; 02BDD6691AA19BE100E44DC3 /* PhaseCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhaseCell.swift; sourceTree = ""; }; 02BDD66A1AA19BE100E44DC3 /* PhaseCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PhaseCell.xib; sourceTree = ""; }; 02BDD6801AA19C3800E44DC3 /* BrewPhase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrewPhase.swift; sourceTree = ""; }; 02BDD6811AA19C3800E44DC3 /* BrewState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrewState.swift; sourceTree = ""; }; 02BDD6831AA19C3800E44DC3 /* BrewViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrewViewModel.swift; sourceTree = ""; }; 02BDD68B1AA2FF6700E44DC3 /* BrewDesignerViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrewDesignerViewModel.swift; sourceTree = ""; }; 02C058B91B652990001AC3C1 /* ISO8601.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ISO8601.framework; path = Carthage/Build/iOS/ISO8601.framework; sourceTree = ""; }; 02C058BA1B652990001AC3C1 /* ReactiveCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReactiveCocoa.framework; path = Carthage/Build/iOS/ReactiveCocoa.framework; sourceTree = ""; }; 02C058BB1B652990001AC3C1 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/iOS/Result.framework; sourceTree = ""; }; 02C058BD1B652990001AC3C1 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/iOS/SwiftyJSON.framework; sourceTree = ""; }; 692AAA8319A34C8C00224C4D /* BrewMobile.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BrewMobile.app; sourceTree = BUILT_PRODUCTS_DIR; }; 692AAA8719A34C8C00224C4D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 692AAA8819A34C8C00224C4D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 692AAA8F19A34C8C00224C4D /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 692AAA9519A34C8C00224C4D /* BrewMobileTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BrewMobileTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 692AAA9A19A34C8C00224C4D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 69A1102519CB38B900108B46 /* BrewPhaseTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrewPhaseTestCase.swift; sourceTree = ""; }; 69A1102C19CB596700108B46 /* BrewStateTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrewStateTestCase.swift; sourceTree = ""; }; 69EC2A8C19CC3439008108D8 /* ContentParserTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentParserTestCase.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 692AAA8019A34C8C00224C4D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 692AAA9219A34C8C00224C4D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 0289A94A1A626C0C00BD2601 /* Helpers */ = { isa = PBXGroup; children = ( 0289A94B1A626C2600BD2601 /* ContentParser.swift */, ); name = Helpers; sourceTree = ""; }; 0289A94E1A62B0FF00BD2601 /* RACUtils */ = { isa = PBXGroup; children = ( 0289A94F1A62B0FF00BD2601 /* RAC.swift */, ); path = RACUtils; sourceTree = ""; }; 02BDD6601AA19BE100E44DC3 /* View */ = { isa = PBXGroup; children = ( 02BDD6611AA19BE100E44DC3 /* BrewCell.swift */, 02BDD6621AA19BE100E44DC3 /* BrewCell.xib */, 02BDD6631AA19BE100E44DC3 /* BrewDesignerViewController.swift */, 02BDD6641AA19BE100E44DC3 /* BrewDesignerViewController.xib */, 02BDD6651AA19BE100E44DC3 /* BrewNewPhaseViewController.swift */, 02BDD6661AA19BE100E44DC3 /* BrewNewPhaseViewController.xib */, 02BDD6671AA19BE100E44DC3 /* BrewViewController.swift */, 02BDD6681AA19BE100E44DC3 /* BrewViewController.xib */, 02BDD6691AA19BE100E44DC3 /* PhaseCell.swift */, 02BDD66A1AA19BE100E44DC3 /* PhaseCell.xib */, ); path = View; sourceTree = ""; }; 02BDD67F1AA19C3800E44DC3 /* Model */ = { isa = PBXGroup; children = ( 02BDD6801AA19C3800E44DC3 /* BrewPhase.swift */, 02BDD6811AA19C3800E44DC3 /* BrewState.swift */, ); path = Model; sourceTree = ""; }; 02BDD6821AA19C3800E44DC3 /* ViewModel */ = { isa = PBXGroup; children = ( 02BDD6831AA19C3800E44DC3 /* BrewViewModel.swift */, 02BDD68B1AA2FF6700E44DC3 /* BrewDesignerViewModel.swift */, ); path = ViewModel; sourceTree = ""; }; 692AAA7A19A34C8B00224C4D = { isa = PBXGroup; children = ( 692AAA8519A34C8C00224C4D /* BrewMobile */, 692AAA9819A34C8C00224C4D /* BrewMobileTests */, 692AAA8419A34C8C00224C4D /* Products */, F3641B66629A474A89086F3F /* Frameworks */, ); sourceTree = ""; }; 692AAA8419A34C8C00224C4D /* Products */ = { isa = PBXGroup; children = ( 692AAA8319A34C8C00224C4D /* BrewMobile.app */, 692AAA9519A34C8C00224C4D /* BrewMobileTests.xctest */, ); name = Products; sourceTree = ""; }; 692AAA8519A34C8C00224C4D /* BrewMobile */ = { isa = PBXGroup; children = ( 02BDD67F1AA19C3800E44DC3 /* Model */, 02BDD6601AA19BE100E44DC3 /* View */, 02BDD6821AA19C3800E44DC3 /* ViewModel */, 0289A94A1A626C0C00BD2601 /* Helpers */, 0289A94E1A62B0FF00BD2601 /* RACUtils */, 0213ADD11A57E6EB0010F9E1 /* BrewManager.swift */, 692AAA8819A34C8C00224C4D /* AppDelegate.swift */, 692AAA8F19A34C8C00224C4D /* Images.xcassets */, 692AAA8619A34C8C00224C4D /* Supporting Files */, ); path = BrewMobile; sourceTree = ""; }; 692AAA8619A34C8C00224C4D /* Supporting Files */ = { isa = PBXGroup; children = ( 692AAA8719A34C8C00224C4D /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; 692AAA9819A34C8C00224C4D /* BrewMobileTests */ = { isa = PBXGroup; children = ( 69A1102519CB38B900108B46 /* BrewPhaseTestCase.swift */, 69A1102C19CB596700108B46 /* BrewStateTestCase.swift */, 69EC2A8C19CC3439008108D8 /* ContentParserTestCase.swift */, 692AAA9919A34C8C00224C4D /* Supporting Files */, ); path = BrewMobileTests; sourceTree = ""; }; 692AAA9919A34C8C00224C4D /* Supporting Files */ = { isa = PBXGroup; children = ( 692AAA9A19A34C8C00224C4D /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; F3641B66629A474A89086F3F /* Frameworks */ = { isa = PBXGroup; children = ( 023A3AD01C65FC3D004AD22E /* SocketIOClientSwift.framework */, 02C058B91B652990001AC3C1 /* ISO8601.framework */, 02C058BA1B652990001AC3C1 /* ReactiveCocoa.framework */, 02C058BB1B652990001AC3C1 /* Result.framework */, 02C058BD1B652990001AC3C1 /* SwiftyJSON.framework */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 692AAA8219A34C8C00224C4D /* BrewMobile */ = { isa = PBXNativeTarget; buildConfigurationList = 692AAA9F19A34C8C00224C4D /* Build configuration list for PBXNativeTarget "BrewMobile" */; buildPhases = ( 692AAA7F19A34C8C00224C4D /* Sources */, 692AAA8019A34C8C00224C4D /* Frameworks */, 692AAA8119A34C8C00224C4D /* Resources */, 027E31821A52B7A700802098 /* Carthage copy frameworks */, 0213ADC81A57DB480010F9E1 /* Embed Frameworks */, ); buildRules = ( ); dependencies = ( ); name = BrewMobile; productName = BrewMobile; productReference = 692AAA8319A34C8C00224C4D /* BrewMobile.app */; productType = "com.apple.product-type.application"; }; 692AAA9419A34C8C00224C4D /* BrewMobileTests */ = { isa = PBXNativeTarget; buildConfigurationList = 692AAAA219A34C8C00224C4D /* Build configuration list for PBXNativeTarget "BrewMobileTests" */; buildPhases = ( 692AAA9119A34C8C00224C4D /* Sources */, 692AAA9219A34C8C00224C4D /* Frameworks */, 692AAA9319A34C8C00224C4D /* Resources */, ); buildRules = ( ); dependencies = ( 692AAA9719A34C8C00224C4D /* PBXTargetDependency */, ); name = BrewMobileTests; productName = BrewMobileTests; productReference = 692AAA9519A34C8C00224C4D /* BrewMobileTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 692AAA7B19A34C8C00224C4D /* Project object */ = { isa = PBXProject; attributes = { LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0700; LastUpgradeCheck = 0700; ORGANIZATIONNAME = "Ágnes Vásárhelyi"; TargetAttributes = { 692AAA8219A34C8C00224C4D = { CreatedOnToolsVersion = 6.0; }; 692AAA9419A34C8C00224C4D = { CreatedOnToolsVersion = 6.0; TestTargetID = 692AAA8219A34C8C00224C4D; }; }; }; buildConfigurationList = 692AAA7E19A34C8C00224C4D /* Build configuration list for PBXProject "BrewMobile" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 692AAA7A19A34C8B00224C4D; productRefGroup = 692AAA8419A34C8C00224C4D /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 692AAA8219A34C8C00224C4D /* BrewMobile */, 692AAA9419A34C8C00224C4D /* BrewMobileTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 692AAA8119A34C8C00224C4D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 02BDD6791AA19BE100E44DC3 /* BrewViewController.xib in Resources */, 02BDD6711AA19BE100E44DC3 /* BrewDesignerViewController.xib in Resources */, 02BDD6751AA19BE100E44DC3 /* BrewNewPhaseViewController.xib in Resources */, 02BDD67D1AA19BE100E44DC3 /* PhaseCell.xib in Resources */, 692AAA9019A34C8C00224C4D /* Images.xcassets in Resources */, 02BDD66D1AA19BE100E44DC3 /* BrewCell.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 692AAA9319A34C8C00224C4D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 02BDD67E1AA19BE100E44DC3 /* PhaseCell.xib in Resources */, 02BDD66E1AA19BE100E44DC3 /* BrewCell.xib in Resources */, 02BDD6761AA19BE100E44DC3 /* BrewNewPhaseViewController.xib in Resources */, 02BDD67A1AA19BE100E44DC3 /* BrewViewController.xib in Resources */, 02BDD6721AA19BE100E44DC3 /* BrewDesignerViewController.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 027E31821A52B7A700802098 /* Carthage copy frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 8; files = ( ); inputPaths = ( "$(SRCROOT)/Carthage/Build/iOS/SocketIOClientSwift.framework", "$(SRCROOT)/Carthage/Build/iOS/ISO8601.framework", "$(SRCROOT)/Carthage/Build/iOS/ReactiveCocoa.framework", "$(SRCROOT)/Carthage/Build/iOS/Result.framework", "$(SRCROOT)/Carthage/Build/iOS/SwiftyJSON.framework", ); name = "Carthage copy frameworks"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 1; shellPath = /bin/sh; shellScript = "/usr/local/bin/carthage copy-frameworks"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 692AAA7F19A34C8C00224C4D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 692AAA8919A34C8C00224C4D /* AppDelegate.swift in Sources */, 02BDD68C1AA2FF6700E44DC3 /* BrewDesignerViewModel.swift in Sources */, 02BDD66B1AA19BE100E44DC3 /* BrewCell.swift in Sources */, 02BDD6731AA19BE100E44DC3 /* BrewNewPhaseViewController.swift in Sources */, 02BDD67B1AA19BE100E44DC3 /* PhaseCell.swift in Sources */, 02BDD6881AA19C3800E44DC3 /* BrewViewModel.swift in Sources */, 02BDD6771AA19BE100E44DC3 /* BrewViewController.swift in Sources */, 0213ADD21A57E6EB0010F9E1 /* BrewManager.swift in Sources */, 0289A9521A62B0FF00BD2601 /* RAC.swift in Sources */, 02BDD66F1AA19BE100E44DC3 /* BrewDesignerViewController.swift in Sources */, 02BDD6861AA19C3800E44DC3 /* BrewState.swift in Sources */, 0289A94C1A626C2600BD2601 /* ContentParser.swift in Sources */, 02BDD6841AA19C3800E44DC3 /* BrewPhase.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 692AAA9119A34C8C00224C4D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 02BDD66C1AA19BE100E44DC3 /* BrewCell.swift in Sources */, 02BDD6741AA19BE100E44DC3 /* BrewNewPhaseViewController.swift in Sources */, 02BDD67C1AA19BE100E44DC3 /* PhaseCell.swift in Sources */, 02BDD6781AA19BE100E44DC3 /* BrewViewController.swift in Sources */, 69EC2A8D19CC3439008108D8 /* ContentParserTestCase.swift in Sources */, 0289A9531A62B0FF00BD2601 /* RAC.swift in Sources */, 02BDD68A1AA19C6200E44DC3 /* BrewManager.swift in Sources */, 02BDD6701AA19BE100E44DC3 /* BrewDesignerViewController.swift in Sources */, 02BDD6891AA19C3800E44DC3 /* BrewViewModel.swift in Sources */, 0289A94D1A626C2600BD2601 /* ContentParser.swift in Sources */, 02BDD6871AA19C3800E44DC3 /* BrewState.swift in Sources */, 69A1102619CB38B900108B46 /* BrewPhaseTestCase.swift in Sources */, 02BDD6851AA19C3800E44DC3 /* BrewPhase.swift in Sources */, 02BDD68D1AA2FF6700E44DC3 /* BrewDesignerViewModel.swift in Sources */, 69A1102D19CB596700108B46 /* BrewStateTestCase.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 692AAA9719A34C8C00224C4D /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 692AAA8219A34C8C00224C4D /* BrewMobile */; targetProxy = 692AAA9619A34C8C00224C4D /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 692AAA9D19A34C8C00224C4D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; 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; IPHONEOS_DEPLOYMENT_TARGET = 8.1; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 692AAA9E19A34C8C00224C4D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; 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; IPHONEOS_DEPLOYMENT_TARGET = 8.1; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; }; name = Release; }; 692AAAA019A34C8C00224C4D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", ); INFOPLIST_FILE = BrewMobile/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.brew.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 692AAAA119A34C8C00224C4D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", ); INFOPLIST_FILE = BrewMobile/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.brew.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 692AAAA319A34C8C00224C4D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/BrewMobile.app/BrewMobile"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, ); INFOPLIST_FILE = BrewMobileTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.brew.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUNDLE_LOADER)"; }; name = Debug; }; 692AAAA419A34C8C00224C4D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/BrewMobile.app/BrewMobile"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", ); HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, ); INFOPLIST_FILE = BrewMobileTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.brew.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUNDLE_LOADER)"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 692AAA7E19A34C8C00224C4D /* Build configuration list for PBXProject "BrewMobile" */ = { isa = XCConfigurationList; buildConfigurations = ( 692AAA9D19A34C8C00224C4D /* Debug */, 692AAA9E19A34C8C00224C4D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 692AAA9F19A34C8C00224C4D /* Build configuration list for PBXNativeTarget "BrewMobile" */ = { isa = XCConfigurationList; buildConfigurations = ( 692AAAA019A34C8C00224C4D /* Debug */, 692AAAA119A34C8C00224C4D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 692AAAA219A34C8C00224C4D /* Build configuration list for PBXNativeTarget "BrewMobileTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 692AAAA319A34C8C00224C4D /* Debug */, 692AAAA419A34C8C00224C4D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 692AAA7B19A34C8C00224C4D /* Project object */; } ================================================ FILE: BrewMobile.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: BrewMobile.xcodeproj/xcshareddata/xcschemes/BrewMobile.xcscheme ================================================ ================================================ FILE: BrewMobile.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: BrewMobileTests/BrewPhaseTestCase.swift ================================================ // // BrewPhaseTestCase.swift // BrewMobile // // Created by Ágnes Vásárhelyi on 18/09/14. // Copyright (c) 2014 Ágnes Vásárhelyi. All rights reserved. // import UIKit import XCTest class BrewPhaseTestCase: XCTestCase { var brewPhase = BrewPhase() override func setUp() { super.setUp() brewPhase = BrewPhase(jobEnd: "09:55", min: 30, temp: 45.0, tempReached: false, inProgress: true) } override func tearDown() { super.tearDown() } func testJobEnd() { XCTAssertNotNil(brewPhase.jobEnd, "should have jobEnd") XCTAssertTrue(brewPhase.jobEnd == "09:55", "expected to be equal") } func testMin() { XCTAssertNotNil(brewPhase.min, "should have min") XCTAssertTrue(brewPhase.min == 30, "expected to be equal") } func testTemp() { XCTAssertNotNil(brewPhase.temp, "should have temp") XCTAssertTrue(brewPhase.temp == 45.0, "expected to be equal") } func testTempReached() { XCTAssertNotNil(brewPhase.tempReached, "should have tempReached") XCTAssertFalse(brewPhase.tempReached, "expected to be false") } func testInProgress() { XCTAssertNotNil(brewPhase.inProgress, "should have inProgress") XCTAssertTrue(brewPhase.inProgress, "expected to be true") } } ================================================ FILE: BrewMobileTests/BrewStateTestCase.swift ================================================ // // BrewStateTestCase.swift // BrewMobile // // Created by Ágnes Vásárhelyi on 18/09/14. // Copyright (c) 2014 Ágnes Vásárhelyi. All rights reserved. // import UIKit import XCTest class BrewStateTestCase: XCTestCase { var brewState = BrewState() var brewPhase = BrewPhase() override func setUp() { super.setUp() brewPhase = BrewPhase(jobEnd: ContentParser.formatDate("2014-08-03T11:55:00.000Z"), min: 10, temp: 70, tempReached: false, inProgress: true) brewState = BrewState(name: "Very IPA", startTime: "10:30", phases: [brewPhase], paused: false, inProgress: true) } override func tearDown() { super.tearDown() } func testName() { XCTAssertNotNil(brewState.name.value, "should have name") XCTAssertTrue(brewState.name.value == "Very IPA", "expected to be equal") } func testStartTime() { XCTAssertNotNil(brewState.startTime.value, "should have startTime") XCTAssertTrue(brewState.startTime.value == "10:30", "expected to be equal") } func testPhases() { XCTAssertEqual(brewState.phases.value[0] as BrewPhase, brewPhase, "expected to be equal") } func testPaused() { XCTAssertNotNil(brewState.paused.value, "should have paused") XCTAssertFalse(brewState.paused.value, "expected to be false") } func testInProgress() { XCTAssertNotNil(brewState.inProgress.value, "should have inProgress") XCTAssertTrue(brewState.inProgress.value, "expected to be true") } } ================================================ FILE: BrewMobileTests/ContentParserTestCase.swift ================================================ // // ContentParserTestCase.swift // BrewMobile // // Created by Ágnes Vásárhelyi on 19/09/14. // Copyright (c) 2014 Ágnes Vásárhelyi. All rights reserved. // import UIKit import XCTest import SwiftyJSON class ContentParserTestCase: XCTestCase { var mockBrewState = BrewState() var mockBrewPhase = BrewPhase() let currentZone = NSTimeZone.defaultTimeZone() override func setUp() { super.setUp() NSTimeZone.setDefaultTimeZone(NSTimeZone(forSecondsFromGMT: +0)) mockBrewPhase = BrewPhase(jobEnd: ContentParser.formatDate("2014-08-03T11:55:00.000Z"), min: 10, temp: 70, tempReached: false, inProgress: true) mockBrewState = BrewState(name: "Very IPA", startTime: ContentParser.formatDate("2014-08-03T09:55:00.000Z"), phases: [mockBrewPhase], paused: false, inProgress: true) } override func tearDown() { NSTimeZone.setDefaultTimeZone(currentZone) super.tearDown() } //MARK: Testing BrewState object parsing func testParseBrewState() { let brewPhaseJSON = ["jobEnd" : "2014-08-03T11:55:00.000Z", "min" : 10, "temp" : 70, "tempReached" : 0, "inProgress" : 1] let brewStateJSON = ["name" : "Very IPA", "startTime" : "2014-08-03T09:55:00.000Z", "phases" : [brewPhaseJSON], "paused" : false, "inProgress" : true] _ = ContentParser.parseBrewState(JSON(brewStateJSON)) } func testParseBrewStateWithEmptyJSON() { let json = ["name" : NSNull(), "startTime" : NSNull(), "phases" : NSNull(), "paused" : NSNull(), "inProgress" : NSNull()] _ = ContentParser.parseBrewState(JSON(json)) } func testParseBrewStateWithUnexpectedJSONStructure() { let json = ["phases" : NSNull(), "paused" : NSNull(), "inProgress" : NSNull()] _ = ContentParser.parseBrewState(JSON(json)) } //MARK: Testing BrewPhase object parsing func testParseBrewPhase() { let json = ["jobEnd" : "2014-08-03T09:55:00.000Z", "min" : "100", "temp" : "76", "tempReached" : 0, "inProgress" : 1] _ = ContentParser.parseBrewState(JSON(json)) } func testParseBrewPhaseWithEmptyJSON() { let json = ["jobEnd" : NSNull(), "min" : NSNull(), "temp" : NSNull(), "tempReached" : NSNull(), "inProgress" : NSNull()] _ = ContentParser.parseBrewPhase(JSON(json)) } func testParseBrewPhaseWithUnexpectedJSONStructure() { let json = ["tempReached" : 0, "inProgress" : 1] _ = ContentParser.parseBrewPhase(JSON(json)) } func testFormatDate() { let originalDateString = "2014-08-03T09:55:00.000Z" let formattedDateString = ContentParser.formatDate(originalDateString) XCTAssertEqual(formattedDateString, "09:55", "expected to be equal") } } ================================================ FILE: BrewMobileTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Cartfile ================================================ github "socketio/socket.io-client-swift" ~> 5.3.3 github "boredzo/iso-8601-date-formatter" "43210ea91f5ea2baff6ba13d699af5dc267ad374" github "ReactiveCocoa/ReactiveCocoa" ~> 4.0.1 github "SwiftyJSON/SwiftyJSON" >= 2.2.1 ================================================ FILE: Cartfile.resolved ================================================ github "antitypical/Result" "1.0.2" github "SwiftyJSON/SwiftyJSON" "2.3.3" github "boredzo/iso-8601-date-formatter" "43210ea91f5ea2baff6ba13d699af5dc267ad374" github "socketio/socket.io-client-swift" "v5.3.3" github "ReactiveCocoa/ReactiveCocoa" "v4.0.1" ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/.gitignore ================================================ # Xcode build/* *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 *.xcworkspace !default.xcworkspace xcuserdata profile *.moved-aside Carthage/Build ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/.gitmodules ================================================ [submodule "Carthage/Checkouts/Nimble"] path = Carthage/Checkouts/Nimble url = https://github.com/Quick/Nimble.git [submodule "Carthage/Checkouts/Quick"] path = Carthage/Checkouts/Quick url = https://github.com/Quick/Quick.git [submodule "Carthage/Checkouts/xcconfigs"] path = Carthage/Checkouts/xcconfigs url = https://github.com/jspahrsummers/xcconfigs.git [submodule "Carthage/Checkouts/Result"] path = Carthage/Checkouts/Result url = https://github.com/antitypical/Result.git ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/.travis.yml ================================================ language: objective-c osx_image: xcode7.1 before_install: true install: true git: submodules: false script: script/cibuild ReactiveCocoa-Mac ReactiveCocoa-iOS notifications: email: false slack: secure: C9QTry5wUG9CfeH3rm3Z19R5rDWqDO7EhHAqHDXBxT6CpGRkTPFliJexpjBYB4sroJ8CiY5ZgTI2sjRBiAdGoE5ZQkfnwSoKQhWXkwo19TnbSnufr3cKO2SZkUhBqOlZcA+mgfjZ7rm2wm7RhpCR/4z8oBXDN4/xv0U5R2fLCLE= ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/CHANGELOG.md ================================================ # 4.0 If you’re new to the Swift API and migrating from RAC 2, start with the [3.0 changes](#30). This section only covers the differences between `3.0` and `4.0`. Just like in `RAC 3`, because Objective-C is still in widespread use, 99% of `RAC 2.x` code will continue to work under `RAC 4.0` without any changes. That is, `RAC 2.x` primitives are still available in `RAC 4.0`. `ReactiveCocoa 4.0` targets **Xcode 7.2.x** and **Swift 2.1.x**, and it supports `iOS 8.0`, `watchOS 2.0`, `tvOS 9.0` and `OS X 10.9`. #### Signal operators are protocol extensions The biggest change from `RAC 3` to `RAC 4` is that `Signal` and `SignalProducer` operators are implemented as **protocol extensions** instead of global functions. This is similar to many of the collection protocol changes in the `Swift 2` standard library. This enables chaining signal operators with normal dot-method calling syntax, which makes autocompleting operators a lot easier. Previously the custom `|>` was required to enable chaining global functions without a mess of nested calls and parenthesis. ```swift /// RAC 3 signal |> filter { $0 % 2 == 0 } |> map { $0 * $0 } |> observe { print($0) } /// RAC 4 signal .filter { $0 % 2 == 0 } .map { $0 * $0 } .observeNext { print($0) } ``` Additionally, this means that `SignalProducer` operators are less “magic”. In RAC 3 the `Signal` operators were implicitly lifted to work on `SignalProducer` via `|>`. This was a point of confusion for some, especially when browsing the source looking for these operators. Now as protocol extensions, the `SignalProducer` operators are explicitly implemented in terms of their `Signal` counterpart when available. #### Removal of `|>` custom operator As already alluded to above, the custom `|>` operator for chaining signals has been removed. Instead standard method calling syntax is used for chaining operators. #### Event cases are no longer boxed The improvements to associated enum values in `Swift 2` mean that `Event` case no longer need to be `Box`ed. In fact, the `Box` dependency has been removed completely from `RAC 4`. #### Replacements for the `start` and `observer` overloads The `observe` and `start` overloads taking `next`, `error`, etc. optional function parameters have been removed. They’ve been replaced with methods taking a single function with the target `Event` case — `observeNext`, `startWithNext`, and the same for `failed` and `completed`. See [#2311](https://github.com/ReactiveCocoa/ReactiveCocoa/issues/2311) and [#2318](https://github.com/ReactiveCocoa/ReactiveCocoa/issues/2318) for more details. #### Renamed `try` and `catch` operators The `try` and `catch` operators were renamed because of the addition of the error handling keywords with the same name. They are now `attempt` and `flatMapError` respectively. Also, `tryMap` was renamed to `attemptMap` for consistency. #### `flatten` and `flatMap` are now possible for all 4 combinations of `Signal`+`SignalProducer` This fills a gap that was missing in `RAC 3`. It’s a common pattern to have signals-of-signals or signals-of-producers. The addition of `flatten` and `flatMap` over these makes it now possible to work with any combination of `Signal`s and `SignalProducer`s. #### Renamed `Event.Error` to `Event.Failed` The `Error` case of `Event` has changed to `Failed`. This aims to help clarify the terminating nature of failure/error events and puts them in the same tense as other terminating cases (`Interrupted` and `Completed`). Likewise, some operations and parameters have been renamed (e.g. `Signal.observeError` is now `Signal.observeFailed`, `Observer.sendError` is now `Observer.sendFailed`). #### Renamed signal generic parameters The generic parameters of `Signal`, `SignalProducer`, and other related types have been renamed to `Value` and `Error` from `T` and `E` respectively. This is in-line with changes to the standard library to give more descriptive names to type parameters for increased clarity. This should have limited impact, only affecting generic, custom signal/producer extensions. #### Added missing `SignalProducer` operators There were some `Signal` operators that were missing `SignalProducer` equivalents: * `takeUntil` * `combineLatestWith` * `sampleOn` * `takeUntilReplacement` * `zipWith` #### Added new operators: * `Signal.on`. * `Signal.merge(signals:)`. * `Signal.empty`. * `skipUntil`. * `replayLazily` ([#2639](https://github.com/ReactiveCocoa/ReactiveCocoa/issues/2639)). #### Renamed `PropertyOf` to `AnyProperty` This is in-line with changes to the standard library in `Swift 2`. #### Enhancements to `PropertyType` `MutableProperty` received 3 new methods, similar to those in `Atomic`: `modify`, `swap`, and `withValue`. Additionally, all `PropertyType`s now have a `signal: Signal` in addition to their existing `producer: SignalProducer` property. #### Publicized `Bag` and `Atomic` `Bag` and `Atomic` are now public. These are useful when creating custom operators for RAC types. #### `SignalProducer.buffer` no longer has a default capacity In order to force users to think about the desired capacity, this no longer defaults to `Int.max`. Prior to this change one could have inadvertently cached every value emitted by the `SignalProducer`. This needs to be specified manually now. #### Added `SignalProducer.replayLazily` for multicasting It’s still recommended to use `SignalProducer.buffer` or `PropertyType` when buffering behavior is desired. However, when you need to compose an existing `SignalProducer` to avoid duplicate side effects, this operator is now available. The full semantics of the operator are documented in the code, and you can see [#2639](https://github.com/ReactiveCocoa/ReactiveCocoa/issues/2639) for full details. # 3.0 ReactiveCocoa 3.0 includes the first official Swift API, which is intended to eventually supplant the Objective-C API entirely. However, because migration is hard and time-consuming, and because Objective-C is still in widespread use, 99% of RAC 2.x code will continue to work under RAC 3.0 without any changes. Since the 3.0 changes are entirely additive, this document will discuss how concepts from the Objective-C API map to the Swift API. For a complete diff of all changes, see [the 3.0 pull request](https://github.com/ReactiveCocoa/ReactiveCocoa/pull/1382). **[Additions](#additions)** 1. [Parameterized types](#parameterized-types) 1. [Interrupted event](#interrupted-event) 1. [Objective-C bridging](#objective-c-bridging) **[Replacements](#replacements)** 1. [Hot signals are now Signals](#hot-signals-are-now-signals) 1. [Cold signals are now SignalProducers](#cold-signals-are-now-signalproducers) 1. [Commands are now Actions](#commands-are-now-actions) 1. [Flattening/merging, concatenating, and switching are now one operator](#flatteningmerging-concatenating-and-switching-are-now-one-operator) 1. [Using PropertyType instead of RACObserve and RAC](#using-propertytype-instead-of-racobserve-and-rac) 1. [Using Signal.pipe instead of RACSubject](#using-signalpipe-instead-of-racsubject) 1. [Using SignalProducer.buffer instead of replaying](#using-signalproducerbuffer-instead-of-replaying) 1. [Using startWithSignal instead of multicasting](#using-startwithsignal-instead-of-multicasting) **[Minor changes](#minor-changes)** 1. [Disposable changes](#disposable-changes) 1. [Scheduler changes](#scheduler-changes) ## Additions ### Parameterized types Thanks to Swift, **it is now possible to express the type of value that a signal can send. RAC also requires that the type of errors be specified.** For example, `Signal` is a signal that may send zero or more integers, and which may send an error of type `NSError`. **If it is impossible for a signal to error out, use the built-in [`NoError`](ReactiveCocoa/Swift/Errors.swift) type** (which can be referred to, but never created) to represent that case—for example, `Signal` is a signal that may send zero or more strings, and which will _not_ send an error under any circumstances. Together, these additions make it much simpler to reason about signal interactions, and protect against several kinds of common bugs that occurred in Objective-C. ### Interrupted event In addition to the `Next`, `Error`, and `Completed` events that have always been part of RAC, version 3.0 [adds another terminating event](https://github.com/ReactiveCocoa/ReactiveCocoa/pull/1735)—called `Interrupted`—that is used to communicate cancellation. Now, **whenever a [producer](#cold-signals-are-now-signalproducers) is disposed of, one final `Interrupted` event will be sent to all consumers,** giving them a chance to react to the cancellation. Similarly, observing a [hot signal](#hot-signals-are-now-signals) that has already terminated will immediately result in an `Interrupted` event, to clearly indicate that no further events are possible. This brings disposal semantics more in line with normal event delivery, where events propagate downstream from producers to consumers. The result is a simpler model for reasoning about non-erroneous, yet unsuccessful, signal terminations. **Note:** Custom `Signal` and `SignalProducer` operators should handle any received `Interrupted` event by forwarding it to their own observers. This ensures that interruption correctly propagates through the whole signal chain. ### Objective-C bridging **To support interoperation between the Objective-C APIs introduced in RAC 2 and the Swift APIs introduced in RAC 3, the framework offers [bridging functions](ReactiveCocoa/Swift/ObjectiveCBridging.swift)** that can convert types back and forth between the two. Because the APIs are based on fundamentally different designs, the conversion is not always one-to-one; however, every attempt has been made to faithfully translate the concepts between the two APIs (and languages). **Common conversions include:** * The `RACSignal.toSignalProducer` method **†** * Converts `RACSignal *` to `SignalProducer` * The `toRACSignal()` function * Converts `SignalProducer` to `RACSignal *` * Converts `Signal` to `RACSignal *` * The `RACCommand.toAction` method **‡** * Converts `RACCommand *` to `Action` * The `toRACCommand` function **‡** * Converts `Action` to `RACCommand *` **†** It is not possible (in the general case) to convert arbitrary `RACSignal` instances to `Signal`s, because any `RACSignal` subscription could potentially involve side effects. To obtain a `Signal`, use `RACSignal.toSignalProducer` followed by `SignalProducer.start`, thereby making those side effects explicit. **‡** Unfortunately, the `executing` properties of actions and commands are not synchronized across the API bridge. To ensure consistency, only observe the `executing` property from the base object (the one passed _into_ the bridge, not retrieved from it), so updates occur no matter which object is used for execution. ## Replacements ### Hot signals are now Signals In the terminology of RAC 2, a “hot” `RACSignal` does not trigger any side effects when a `-subscribe…` method is called upon it. In other words, hot signals are entirely producer-driven and push-based, and consumers (subscribers) cannot have any effect on their lifetime. This pattern is useful for notifying observers about events that will occur _no matter what_. For example, a `loading` boolean might flip between true and false regardless of whether anything is observing it. Concretely, _every_ `RACSubject` is a kind of hot signal, because the events being forwarded are not determined by the number of subscribers on the subject. In RAC 3, **“hot” signals are now solely represented by the [`Signal`](ReactiveCocoa/Swift/Signal.swift) class**, and “cold” signals have been [separated into their own type](#cold-signals-are-now-signalproducers). This reduces complexity by making it clear that no `Signal` object can trigger side effects when observed. ### Cold signals are now SignalProducers In the terminology of RAC 2, a “cold” `RACSignal` performs its work one time for _every_ subscription. In other words, cold signals perform side effects when a `-subscribe…` method is called upon them, and may be able to cancel in-progress work if `-dispose` is called upon the returned `RACDisposable`. This pattern is broadly useful because it minimizes unnecessary work, and allows operators like `take`, `retry`, `concat`, etc. to manipulate when work is started and cancelled. Cold signals are also similar to how [futures and promises](http://en.wikipedia.org/wiki/Futures_and_promises) work, and can be useful for structuring asynchronous code (like network requests). In RAC 3, **“cold” signals are now solely represented by the [`SignalProducer`](ReactiveCocoa/Swift/SignalProducer.swift) class**, which clearly indicates their relationship to [“hot” signals](#hot-signals-are-now-signals). As the name indicates, a signal _producer_ is responsible for creating a [_signal_](#hot-signals-are-now-signals) (when started), and can perform work as part of that process—meanwhile, the signal can have any number of observers without any additional side effects. ### Commands are now Actions Instead of the ambiguously named `RACCommand`, the Swift API offers the [`Action`](ReactiveCocoa/Swift/Action.swift) type—named as such because it’s mainly useful in UI programming—to fulfill the same purpose. Like the rest of the Swift API, actions are [parameterized](#parameterized-types) by the types they use. **An action must indicate the type of input it accepts, the type of output it produces, and what kinds of errors can occur (if any).** This eliminates a few classes of type error, and clarifies intention. Actions are also intended to be simpler overall than their predecessor: * **Unlike commands, actions are not bound to or dependent upon the main thread**, making it easier to reason about when they can be executed and when they will generate notifications. * **Actions also only support serial execution**, because concurrent execution was a rarely used feature of `RACCommand` that added significant complexity to the interface and implementation. Because actions are frequently used in conjunction with AppKit or UIKit, there is also a `CocoaAction` class that erases the type parameters of an `Action`, allowing it to be used from Objective-C. As an example, an action can be wrapped and bound to `UIControl` like so: ```swift self.cocoaAction = CocoaAction(underlyingAction) self.button.addTarget(self.cocoaAction, action: CocoaAction.selector, forControlEvents: UIControlEvents.TouchUpInside) ``` ### Flattening/merging, concatenating, and switching are now one operator RAC 2 offers several operators for transforming a signal-of-signals into one `RACSignal`, including: * `-flatten` * `-flattenMap:` * `+merge:` * `-concat` * `+concat:` * `-switchToLatest` Because `-flattenMap:` is the easiest to use, it was often incorrectly chosen even when concatenation or switching semantics are more appropriate. **RAC 3 distills these concepts down into just two operators, `flatten` and `flatMap`.** Note that these do _not_ have the same behavior as `-flatten` and `-flattenMap:` from RAC 2. Instead, both accept a “strategy” which determines how the producer-of-producers should be integrated, which can be one of: * `.Merge`, which is equivalent to RAC 2’s `-flatten` or `+merge:` * `.Concat`, which is equivalent to `-concat` or `+concat:` * `.Latest`, which is equivalent to `-switchToLatest` This reduces the API surface area, and forces callers to consciously think about which strategy is most appropriate for a given use. **For streams of exactly one value, calls to `-flattenMap:` can be replaced with `flatMap(.Concat)`**, which has the additional benefit of predictable behavior if the input stream is refactored to have more values in the future. ### Using PropertyType instead of RACObserve and RAC To be more Swift-like, RAC 3 de-emphasizes [Key-Value Coding](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueCoding/Articles/KeyValueCoding.html) (KVC) and [Key-Value Observing](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html) (KVO) in favor of a less “magical” representation for properties. **The [`PropertyType` protocol and implementations](ReactiveCocoa/Swift/Property.swift) replace most uses of the `RACObserve()` and `RAC()` macros.** For example, `MutableProperty` can be used to represent a property that can be bound to. If changes to that property should be visible to consumers, it can additionally be wrapped in `PropertyOf` (to hide the mutable bits) and exposed publicly. **If KVC or KVO is required by a specific API**—for example, to observe changes to `NSOperation.executing`—RAC 3 offers a `DynamicProperty` type that can wrap those key paths. Use this class with caution, though, as it can’t offer any type safety, and many APIs (especially in AppKit and UIKit) are not documented to be KVO-compliant. ### Using Signal.pipe instead of RACSubject Since the `Signal` type, like `RACSubject`, is [always “hot”](#hot-signals-are-now-signals), there is a special class method for creating a controllable signal. **The `Signal.pipe` method can replace the use of subjects**, and expresses intent better by separating the observing API from the sending API. To use a pipe, set up observers on the signal as desired, then send values to the sink: ```swift let (signal, sink) = Signal.pipe() signal.observe(next: { value in println(value) }) // Prints each number sendNext(sink, 0) sendNext(sink, 1) sendNext(sink, 2) ``` ### Using SignalProducer.buffer instead of replaying The producer version of [`Signal.pipe`](#using-signalpipe-instead-of-racsubject), **the `SignalProducer.buffer` method can replace replaying** with `RACReplaySubject` or any of the `-replay…` methods. Conceptually, `buffer` creates a (optionally bounded) queue for events, much like `RACReplaySubject`, and replays those events when new `Signal`s are created from the producer. For example, to replay the values of an existing `Signal`, it just needs to be fed into the write end of the buffer: ```swift let signal: Signal let (producer, sink) = SignalProducer.buffer() // Saves observed values in the buffer signal.observe(sink) // Prints each value buffered producer.start(next: { value in println(value) }) ``` ### Using startWithSignal instead of multicasting `RACMulticastConnection` and the `-publish` and `-multicast:` operators were always poorly understood features of RAC 2. In RAC 3, thanks to the `Signal` and `SignalProducer` split, **the `SignalProducer.startWithSignal` method can replace multicasting**. `startWithSignal` allows any number of observers to attach to the created signal _before_ any work is begun—therefore, the work (and any side effects) still occurs just once, but the values can be distributed to multiple interested observers. This fulfills the same purpose of multicasting, in a much clearer and more tightly-scoped way. For example: ```swift let producer = timer(5, onScheduler: QueueScheduler.mainQueueScheduler).take(3) // Starts just one timer, sending the dates to two different observers as they // are generated. producer.startWithSignal { signal, disposable in signal.observe(next: { date in println(date) }) signal.observe(someOtherObserver) } ``` ## Minor changes ### Disposable changes [Disposables](ReactiveCocoa/Swift/Disposable.swift) haven’t changed much overall in RAC 3, besides the addition of a protocol and minor naming tweaks. The biggest change to be aware of is that **setting `SerialDisposable.innerDisposable` will always dispose of the previous value**, which helps prevent resource leaks or logic errors from forgetting to dispose manually. ### Scheduler changes RAC 3 replaces the multipurpose `RACScheduler` class with two protocols, [`SchedulerType` and `DateSchedulerType`](ReactiveCocoa/Swift/Scheduler.swift), with multiple implementations of each. This design indicates and enforces the capabilities of each scheduler using the type system. In addition, **the `mainThreadScheduler` has been replaced with `UIScheduler` and `QueueScheduler.mainQueueScheduler`**. The `UIScheduler` type runs operations as soon as possible on the main thread—even synchronously (if possible), thereby replacing RAC 2’s `-performOnMainThread` operator—while `QueueScheduler.mainQueueScheduler` will always enqueue work after the current run loop iteration, and can be used to schedule work at a future date. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/CONTRIBUTING.md ================================================ We love that you're interested in contributing to this project! To make the process as painless as possible, we have just a couple of guidelines that should make life easier for everyone involved. ## Prefer Pull Requests If you know exactly how to implement the feature being suggested or fix the bug being reported, please open a pull request instead of an issue. Pull requests are easier than patches or inline code blocks for discussing and merging the changes. If you can't make the change yourself, please open an issue after making sure that one isn't already logged. ## Contributing Code Fork this repository, make it awesomer (preferably in a branch named for the topic), send a pull request! All code contributions should match our [coding conventions](https://github.com/github/objective-c-conventions). Thanks for contributing! :boom::camel: ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Cartfile ================================================ github "antitypical/Result" ~> 1.0.2 ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Cartfile.private ================================================ github "jspahrsummers/xcconfigs" "ec5753493605deed7358dec5f9260f503d3ed650" github "Quick/Quick" ~> 0.8 github "Quick/Nimble" ~> 3.1 ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Cartfile.resolved ================================================ github "Quick/Nimble" "v3.1.0" github "Quick/Quick" "v0.8.0" github "antitypical/Result" "1.0.2" github "jspahrsummers/xcconfigs" "ec5753493605deed7358dec5f9260f503d3ed650" ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/.gitignore ================================================ .DS_Store xcuserdata/ build/ .idea DerivedData/ Nimble.framework.zip # Carthage # # Add this line if you want to avoid checking in source code from Carthage dependencies. # Carthage/Checkouts Carthage/Build ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/.travis.yml ================================================ osx_image: xcode7 language: objective-c env: matrix: - NIMBLE_RUNTIME_IOS_SDK_VERSION=9.0 TYPE=ios - NIMBLE_RUNTIME_OSX_SDK_VERSION=10.10 TYPE=osx script: ./test $TYPE ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/CONTRIBUTING.md ================================================ - [Welcome to Nimble!](#welcome-to-nimble!) - [Reporting Bugs](#reporting-bugs) - [Building the Project](#building-the-project) - [Pull Requests](#pull-requests) - [Style Conventions](#style-conventions) - [Core Members](#core-members) - [Code of Conduct](#code-of-conduct) # Welcome to Nimble! We're building a testing framework for a new generation of Swift and Objective-C developers. Nimble should be easy to use and easy to maintain. Let's keep things simple and well-tested. **tl;dr:** If you've added a file to the project, make sure it's included in both the OS X and iOS targets. ## Reporting Bugs Nothing is off-limits. If you're having a problem, we want to hear about it. - See a crash? File an issue. - Code isn't compiling, but you don't know why? Sounds like you should submit a new issue, bud. - Went to the kitchen, only to forget why you went in the first place? Better submit an issue. Be sure to include in your issue: - Your Xcode version (eg - Xcode 7.0.1 7A1001) - Your version of Nimble (eg - v2.0.0 or git sha `20a3f3b4e63cc8d97c92c4164bf36f2a2c9a6e1b`) - What are the steps to reproduce this issue? - What platform are you using? (eg - OS X, iOS, watchOS, tvOS) - If the problem is on a UI Testing Bundle, Unit Testing Bundle, or some other target configuration - Are you using carthage or cocoapods? ## Building the Project - Use `Nimble.xcodeproj` to work on Nimble. ## Pull Requests - Nothing is trivial. Submit pull requests for anything: typos, whitespace, you name it. - Not all pull requests will be merged, but all will be acknowledged. If no one has provided feedback on your request, ping one of the owners by name. - Make sure your pull request includes any necessary updates to the README or other documentation. - Be sure the unit tests for both the OS X and iOS targets of Nimble before submitting your pull request. You can run all the OS X & iOS unit tests using `./test`. - If you've added a file to the project, make sure it's included in both the OS X and iOS targets. - The `master` branch will always support the stable Xcode version. Other branches will point to their corresponding versions they support. - If you're making a configuration change, make sure to edit both the xcode project and the podspec file. ### Style Conventions - Indent using 4 spaces. - Keep lines 100 characters or shorter. Break long statements into shorter ones over multiple lines. - In Objective-C, use `#pragma mark -` to mark public, internal, protocol, and superclass methods. ## Core Members If a few of your pull requests have been merged, and you'd like a controlling stake in the project, file an issue asking for write access to the repository. ### Code of Conduct Your conduct as a core member is your own responsibility, but here are some "ground rules": - Feel free to push whatever you want to master, and (if you have ownership permissions) to create any repositories you'd like. Ideally, however, all changes should be submitted as GitHub pull requests. No one should merge their own pull request, unless no other core members respond for at least a few days. If you'd like to create a new repository, it'd be nice if you created a GitHub issue and gathered some feedback first. - It'd be awesome if you could review, provide feedback on, and close issues or pull requests submitted to the project. Please provide kind, constructive feedback. Please don't be sarcastic or snarky. ### Creating a Release The process is relatively straight forward, but here's is a useful checklist for tagging: - Look at changes from the previously tagged release and write release notes: `git log v0.4.0...HEAD` - Run the release script: `./script/release A.B.C release-notes-file` - Go to [github releases](https://github.com/Quick/Nimble/releases) and mark the tagged commit as a release. - Use the same release notes you created for the tag, but tweak up formatting for github. - Attach the carthage release `Nimble.framework.zip` to the release. - Announce! ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/LICENSE.md ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2014 Quick Team Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Adapters/AdapterProtocols.swift ================================================ import Foundation /// Protocol for the assertion handler that Nimble uses for all expectations. public protocol AssertionHandler { func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) } /// Global backing interface for assertions that Nimble creates. /// Defaults to a private test handler that passes through to XCTest. /// /// If XCTest is not available, you must assign your own assertion handler /// before using any matchers, otherwise Nimble will abort the program. /// /// @see AssertionHandler public var NimbleAssertionHandler: AssertionHandler = { () -> AssertionHandler in return isXCTestAvailable() ? NimbleXCTestHandler() : NimbleXCTestUnavailableHandler() }() ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Adapters/AssertionDispatcher.swift ================================================ /// AssertionDispatcher allows multiple AssertionHandlers to receive /// assertion messages. /// /// @warning Does not fully dispatch if one of the handlers raises an exception. /// This is possible with XCTest-based assertion handlers. /// public class AssertionDispatcher: AssertionHandler { let handlers: [AssertionHandler] public init(handlers: [AssertionHandler]) { self.handlers = handlers } public func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { for handler in handlers { handler.assert(assertion, message: message, location: location) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Adapters/AssertionRecorder.swift ================================================ import Foundation /// A data structure that stores information about an assertion when /// AssertionRecorder is set as the Nimble assertion handler. /// /// @see AssertionRecorder /// @see AssertionHandler public struct AssertionRecord: CustomStringConvertible { /// Whether the assertion succeeded or failed public let success: Bool /// The failure message the assertion would display on failure. public let message: FailureMessage /// The source location the expectation occurred on. public let location: SourceLocation public var description: String { return "AssertionRecord { success=\(success), message='\(message.stringValue)', location=\(location) }" } } /// An AssertionHandler that silently records assertions that Nimble makes. /// This is useful for testing failure messages for matchers. /// /// @see AssertionHandler public class AssertionRecorder : AssertionHandler { /// All the assertions that were captured by this recorder public var assertions = [AssertionRecord]() public init() {} public func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { assertions.append( AssertionRecord( success: assertion, message: message, location: location)) } } /// Allows you to temporarily replace the current Nimble assertion handler with /// the one provided for the scope of the closure. /// /// Once the closure finishes, then the original Nimble assertion handler is restored. /// /// @see AssertionHandler public func withAssertionHandler(tempAssertionHandler: AssertionHandler, closure: () throws -> Void) { let environment = NimbleEnvironment.activeInstance let oldRecorder = environment.assertionHandler let capturer = NMBExceptionCapture(handler: nil, finally: ({ environment.assertionHandler = oldRecorder })) environment.assertionHandler = tempAssertionHandler capturer.tryBlock { try! closure() } } /// Captures expectations that occur in the given closure. Note that all /// expectations will still go through to the default Nimble handler. /// /// This can be useful if you want to gather information about expectations /// that occur within a closure. /// /// @param silently expectations are no longer send to the default Nimble /// assertion handler when this is true. Defaults to false. /// /// @see gatherFailingExpectations public func gatherExpectations(silently silently: Bool = false, closure: () -> Void) -> [AssertionRecord] { let previousRecorder = NimbleEnvironment.activeInstance.assertionHandler let recorder = AssertionRecorder() let handlers: [AssertionHandler] if silently { handlers = [recorder] } else { handlers = [recorder, previousRecorder] } let dispatcher = AssertionDispatcher(handlers: handlers) withAssertionHandler(dispatcher, closure: closure) return recorder.assertions } /// Captures failed expectations that occur in the given closure. Note that all /// expectations will still go through to the default Nimble handler. /// /// This can be useful if you want to gather information about failed /// expectations that occur within a closure. /// /// @param silently expectations are no longer send to the default Nimble /// assertion handler when this is true. Defaults to false. /// /// @see gatherExpectations /// @see raiseException source for an example use case. public func gatherFailingExpectations(silently silently: Bool = false, closure: () -> Void) -> [AssertionRecord] { let assertions = gatherExpectations(silently: silently, closure: closure) return assertions.filter { assertion in !assertion.success } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Adapters/NimbleEnvironment.swift ================================================ import Foundation /// "Global" state of Nimble is stored here. Only DSL functions should access / be aware of this /// class' existance internal class NimbleEnvironment { static var activeInstance: NimbleEnvironment { get { let env = NSThread.currentThread().threadDictionary["NimbleEnvironment"] if let env = env as? NimbleEnvironment { return env } else { let newEnv = NimbleEnvironment() self.activeInstance = newEnv return newEnv } } set { NSThread.currentThread().threadDictionary["NimbleEnvironment"] = newValue } } // TODO: eventually migrate the global to this environment value var assertionHandler: AssertionHandler { get { return NimbleAssertionHandler } set { NimbleAssertionHandler = newValue } } var awaiter: Awaiter init() { awaiter = Awaiter( waitLock: AssertionWaitLock(), asyncQueue: dispatch_get_main_queue(), timeoutQueue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Adapters/NimbleXCTestHandler.swift ================================================ import Foundation import XCTest /// Default handler for Nimble. This assertion handler passes failures along to /// XCTest. public class NimbleXCTestHandler : AssertionHandler { public func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { if !assertion { XCTFail("\(message.stringValue)\n", file: location.file, line: location.line) } } } /// Alternative handler for Nimble. This assertion handler passes failures along /// to XCTest by attempting to reduce the failure message size. public class NimbleShortXCTestHandler: AssertionHandler { public func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { if !assertion { let msg: String if let actual = message.actualValue { msg = "got: \(actual) \(message.postfixActual)" } else { msg = "expected \(message.to) \(message.postfixMessage)" } XCTFail("\(msg)\n", file: location.file, line: location.line) } } } /// Fallback handler in case XCTest is unavailable. This assertion handler will abort /// the program if it is invoked. class NimbleXCTestUnavailableHandler : AssertionHandler { func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { fatalError("XCTest is not available and no custom assertion handler was configured. Aborting.") } } func isXCTestAvailable() -> Bool { return NSClassFromString("XCTestCase") != nil } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/DSL+Wait.swift ================================================ import Foundation private enum ErrorResult { case Exception(NSException) case Error(ErrorType) case None } /// Only classes, protocols, methods, properties, and subscript declarations can be /// bridges to Objective-C via the @objc keyword. This class encapsulates callback-style /// asynchronous waiting logic so that it may be called from Objective-C and Swift. internal class NMBWait: NSObject { internal class func until( timeout timeout: NSTimeInterval, file: String = __FILE__, line: UInt = __LINE__, action: (() -> Void) -> Void) -> Void { return throwableUntil(timeout: timeout, file: file, line: line) { (done: () -> Void) throws -> Void in action() { done() } } } // Using a throwable closure makes this method not objc compatible. internal class func throwableUntil( timeout timeout: NSTimeInterval, file: String = __FILE__, line: UInt = __LINE__, action: (() -> Void) throws -> Void) -> Void { let awaiter = NimbleEnvironment.activeInstance.awaiter let leeway = timeout / 2.0 let result = awaiter.performBlock { (done: (ErrorResult) -> Void) throws -> Void in dispatch_async(dispatch_get_main_queue()) { let capture = NMBExceptionCapture( handler: ({ exception in done(.Exception(exception)) }), finally: ({ }) ) capture.tryBlock { do { try action() { done(.None) } } catch let e { done(.Error(e)) } } } }.timeout(timeout, forcefullyAbortTimeout: leeway).wait("waitUntil(...)", file: file, line: line) switch result { case .Incomplete: internalError("Reached .Incomplete state for waitUntil(...).") case .BlockedRunLoop: fail(blockedRunLoopErrorMessageFor("-waitUntil()", leeway: leeway), file: file, line: line) case .TimedOut: let pluralize = (timeout == 1 ? "" : "s") fail("Waited more than \(timeout) second\(pluralize)", file: file, line: line) case let .RaisedException(exception): fail("Unexpected exception raised: \(exception)") case let .ErrorThrown(error): fail("Unexpected error thrown: \(error)") case .Completed(.Exception(let exception)): fail("Unexpected exception raised: \(exception)") case .Completed(.Error(let error)): fail("Unexpected error thrown: \(error)") case .Completed(.None): // success break } } @objc(untilFile:line:action:) internal class func until(file: String = __FILE__, line: UInt = __LINE__, action: (() -> Void) -> Void) -> Void { until(timeout: 1, file: file, line: line, action: action) } } internal func blockedRunLoopErrorMessageFor(fnName: String, leeway: NSTimeInterval) -> String { return "\(fnName) timed out but was unable to run the timeout handler because the main thread is unresponsive (\(leeway) seconds is allow after the wait times out). Conditions that may cause this include processing blocking IO on the main thread, calls to sleep(), deadlocks, and synchronous IPC. Nimble forcefully stopped run loop which may cause future failures in test run." } /// Wait asynchronously until the done closure is called or the timeout has been reached. /// /// @discussion /// Call the done() closure to indicate the waiting has completed. /// /// This function manages the main run loop (`NSRunLoop.mainRunLoop()`) while this function /// is executing. Any attempts to touch the run loop may cause non-deterministic behavior. public func waitUntil(timeout timeout: NSTimeInterval = 1, file: String = __FILE__, line: UInt = __LINE__, action: (() -> Void) -> Void) -> Void { NMBWait.until(timeout: timeout, file: file, line: line, action: action) } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/DSL.swift ================================================ import Foundation /// Make an expectation on a given actual value. The value given is lazily evaluated. public func expect(@autoclosure(escaping) expression: () throws -> T?, file: String = __FILE__, line: UInt = __LINE__) -> Expectation { return Expectation( expression: Expression( expression: expression, location: SourceLocation(file: file, line: line), isClosure: true)) } /// Make an expectation on a given actual value. The closure is lazily invoked. public func expect(file: String = __FILE__, line: UInt = __LINE__, expression: () throws -> T?) -> Expectation { return Expectation( expression: Expression( expression: expression, location: SourceLocation(file: file, line: line), isClosure: true)) } /// Always fails the test with a message and a specified location. public func fail(message: String, location: SourceLocation) { let handler = NimbleEnvironment.activeInstance.assertionHandler handler.assert(false, message: FailureMessage(stringValue: message), location: location) } /// Always fails the test with a message. public func fail(message: String, file: String = __FILE__, line: UInt = __LINE__) { fail(message, location: SourceLocation(file: file, line: line)) } /// Always fails the test. public func fail(file: String = __FILE__, line: UInt = __LINE__) { fail("fail() always fails", file: file, line: line) } /// Like Swift's precondition(), but raises NSExceptions instead of sigaborts internal func nimblePrecondition( @autoclosure expr: () -> Bool, @autoclosure _ name: () -> String, @autoclosure _ message: () -> String) -> Bool { let result = expr() if !result { let e = NSException( name: name(), reason: message(), userInfo: nil) e.raise() } return result } @noreturn internal func internalError(msg: String, file: String = __FILE__, line: UInt = __LINE__) { fatalError( "Nimble Bug Found: \(msg) at \(file):\(line).\n" + "Please file a bug to Nimble: https://github.com/Quick/Nimble/issues with the " + "code snippet that caused this error." ) } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Expectation.swift ================================================ import Foundation internal func expressionMatches(expression: Expression, matcher: U, to: String, description: String?) -> (Bool, FailureMessage) { let msg = FailureMessage() msg.userDescription = description msg.to = to do { let pass = try matcher.matches(expression, failureMessage: msg) if msg.actualValue == "" { msg.actualValue = "<\(stringify(try expression.evaluate()))>" } return (pass, msg) } catch let error { msg.actualValue = "an unexpected error thrown: <\(error)>" return (false, msg) } } internal func expressionDoesNotMatch(expression: Expression, matcher: U, toNot: String, description: String?) -> (Bool, FailureMessage) { let msg = FailureMessage() msg.userDescription = description msg.to = toNot do { let pass = try matcher.doesNotMatch(expression, failureMessage: msg) if msg.actualValue == "" { msg.actualValue = "<\(stringify(try expression.evaluate()))>" } return (pass, msg) } catch let error { msg.actualValue = "an unexpected error thrown: <\(error)>" return (false, msg) } } public struct Expectation { let expression: Expression public func verify(pass: Bool, _ message: FailureMessage) { let handler = NimbleEnvironment.activeInstance.assertionHandler handler.assert(pass, message: message, location: expression.location) } /// Tests the actual value using a matcher to match. public func to(matcher: U, description: String? = nil) { let (pass, msg) = expressionMatches(expression, matcher: matcher, to: "to", description: description) verify(pass, msg) } /// Tests the actual value using a matcher to not match. public func toNot(matcher: U, description: String? = nil) { let (pass, msg) = expressionDoesNotMatch(expression, matcher: matcher, toNot: "to not", description: description) verify(pass, msg) } /// Tests the actual value using a matcher to not match. /// /// Alias to toNot(). public func notTo(matcher: U, description: String? = nil) { toNot(matcher, description: description) } // see: // - AsyncMatcherWrapper for extension // - NMBExpectation for Objective-C interface } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Expression.swift ================================================ import Foundation // Memoizes the given closure, only calling the passed // closure once; even if repeat calls to the returned closure internal func memoizedClosure(closure: () throws -> T) -> (Bool) throws -> T { var cache: T? return ({ withoutCaching in if (withoutCaching || cache == nil) { cache = try closure() } return cache! }) } /// Expression represents the closure of the value inside expect(...). /// Expressions are memoized by default. This makes them safe to call /// evaluate() multiple times without causing a re-evaluation of the underlying /// closure. /// /// @warning Since the closure can be any code, Objective-C code may choose /// to raise an exception. Currently, Expression does not memoize /// exception raising. /// /// This provides a common consumable API for matchers to utilize to allow /// Nimble to change internals to how the captured closure is managed. public struct Expression { internal let _expression: (Bool) throws -> T? internal let _withoutCaching: Bool public let location: SourceLocation public let isClosure: Bool /// Creates a new expression struct. Normally, expect(...) will manage this /// creation process. The expression is memoized. /// /// @param expression The closure that produces a given value. /// @param location The source location that this closure originates from. /// @param isClosure A bool indicating if the captured expression is a /// closure or internally produced closure. Some matchers /// may require closures. For example, toEventually() /// requires an explicit closure. This gives Nimble /// flexibility if @autoclosure behavior changes between /// Swift versions. Nimble internals always sets this true. public init(expression: () throws -> T?, location: SourceLocation, isClosure: Bool = true) { self._expression = memoizedClosure(expression) self.location = location self._withoutCaching = false self.isClosure = isClosure } /// Creates a new expression struct. Normally, expect(...) will manage this /// creation process. /// /// @param expression The closure that produces a given value. /// @param location The source location that this closure originates from. /// @param withoutCaching Indicates if the struct should memoize the given /// closure's result. Subsequent evaluate() calls will /// not call the given closure if this is true. /// @param isClosure A bool indicating if the captured expression is a /// closure or internally produced closure. Some matchers /// may require closures. For example, toEventually() /// requires an explicit closure. This gives Nimble /// flexibility if @autoclosure behavior changes between /// Swift versions. Nimble internals always sets this true. public init(memoizedExpression: (Bool) throws -> T?, location: SourceLocation, withoutCaching: Bool, isClosure: Bool = true) { self._expression = memoizedExpression self.location = location self._withoutCaching = withoutCaching self.isClosure = isClosure } /// Returns a new Expression from the given expression. Identical to a map() /// on this type. This should be used only to typecast the Expression's /// closure value. /// /// The returned expression will preserve location and isClosure. /// /// @param block The block that can cast the current Expression value to a /// new type. public func cast(block: (T?) throws -> U?) -> Expression { return Expression(expression: ({ try block(self.evaluate()) }), location: self.location, isClosure: self.isClosure) } public func evaluate() throws -> T? { return try self._expression(_withoutCaching) } public func withoutCaching() -> Expression { return Expression(memoizedExpression: self._expression, location: location, withoutCaching: true, isClosure: isClosure) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/FailureMessage.swift ================================================ import Foundation /// Encapsulates the failure message that matchers can report to the end user. /// /// This is shared state between Nimble and matchers that mutate this value. public class FailureMessage: NSObject { public var expected: String = "expected" public var actualValue: String? = "" // empty string -> use default; nil -> exclude public var to: String = "to" public var postfixMessage: String = "match" public var postfixActual: String = "" public var userDescription: String? = nil public var stringValue: String { get { if let value = _stringValueOverride { return value } else { return computeStringValue() } } set { _stringValueOverride = newValue } } internal var _stringValueOverride: String? public override init() { } public init(stringValue: String) { _stringValueOverride = stringValue } internal func stripNewlines(str: String) -> String { var lines: [String] = (str as NSString).componentsSeparatedByString("\n") as [String] let whitespace = NSCharacterSet.whitespaceAndNewlineCharacterSet() lines = lines.map { line in line.stringByTrimmingCharactersInSet(whitespace) } return lines.joinWithSeparator("") } internal func computeStringValue() -> String { var value = "\(expected) \(to) \(postfixMessage)" if let actualValue = actualValue { value = "\(expected) \(to) \(postfixMessage), got \(actualValue)\(postfixActual)" } value = stripNewlines(value) if let userDescription = userDescription { return "\(userDescription)\n\(value)" } return value } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSHumanReadableCopyright Copyright © 2014 Jeff Hui. All rights reserved. NSPrincipalClass ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/AllPass.swift ================================================ import Foundation public func allPass (passFunc: (T?) -> Bool) -> NonNilMatcherFunc { return allPass("pass a condition", passFunc) } public func allPass (passName: String, _ passFunc: (T?) -> Bool) -> NonNilMatcherFunc { return createAllPassMatcher() { expression, failureMessage in failureMessage.postfixMessage = passName return passFunc(try expression.evaluate()) } } public func allPass (matcher: V) -> NonNilMatcherFunc { return createAllPassMatcher() { try matcher.matches($0, failureMessage: $1) } } private func createAllPassMatcher (elementEvaluator:(Expression, FailureMessage) throws -> Bool) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.actualValue = nil if let actualValue = try actualExpression.evaluate() { for currentElement in actualValue { let exp = Expression( expression: {currentElement}, location: actualExpression.location) if try !elementEvaluator(exp, failureMessage) { failureMessage.postfixMessage = "all \(failureMessage.postfixMessage)," + " but failed first at element <\(stringify(currentElement))>" + " in <\(stringify(actualValue))>" return false } } failureMessage.postfixMessage = "all \(failureMessage.postfixMessage)" } else { failureMessage.postfixMessage = "all pass (use beNil() to match nils)" return false } return true } } extension NMBObjCMatcher { public class func allPassMatcher(matcher: NMBObjCMatcher) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let location = actualExpression.location let actualValue = try! actualExpression.evaluate() var nsObjects = [NSObject]() var collectionIsUsable = true if let value = actualValue as? NSFastEnumeration { let generator = NSFastGenerator(value) while let obj:AnyObject = generator.next() { if let nsObject = obj as? NSObject { nsObjects.append(nsObject) } else { collectionIsUsable = false break } } } else { collectionIsUsable = false } if !collectionIsUsable { failureMessage.postfixMessage = "allPass only works with NSFastEnumeration (NSArray, NSSet, ...) of NSObjects" failureMessage.expected = "" failureMessage.to = "" return false } let expr = Expression(expression: ({ nsObjects }), location: location) let elementEvaluator: (Expression, FailureMessage) -> Bool = { expression, failureMessage in return matcher.matches( {try! expression.evaluate()}, failureMessage: failureMessage, location: expr.location) } return try! createAllPassMatcher(elementEvaluator).matches( expr, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/BeAKindOf.swift ================================================ import Foundation // A Nimble matcher that catches attempts to use beAKindOf with non Objective-C types public func beAKindOf(expectedClass: Any) -> NonNilMatcherFunc { return NonNilMatcherFunc {actualExpression, failureMessage in failureMessage.stringValue = "beAKindOf only works on Objective-C types since" + " the Swift compiler will automatically type check Swift-only types." + " This expectation is redundant." return false } } /// A Nimble matcher that succeeds when the actual value is an instance of the given class. /// @see beAnInstanceOf if you want to match against the exact class public func beAKindOf(expectedClass: AnyClass) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in let instance = try actualExpression.evaluate() if let validInstance = instance { failureMessage.actualValue = "<\(NSStringFromClass(validInstance.dynamicType)) instance>" } else { failureMessage.actualValue = "" } failureMessage.postfixMessage = "be a kind of \(NSStringFromClass(expectedClass))" return instance != nil && instance!.isKindOfClass(expectedClass) } } extension NMBObjCMatcher { public class func beAKindOfMatcher(expected: AnyClass) -> NMBMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in return try! beAKindOf(expected).matches(actualExpression, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/BeAnInstanceOf.swift ================================================ import Foundation // A Nimble matcher that catches attempts to use beAnInstanceOf with non Objective-C types public func beAnInstanceOf(expectedClass: Any) -> NonNilMatcherFunc { return NonNilMatcherFunc {actualExpression, failureMessage in failureMessage.stringValue = "beAnInstanceOf only works on Objective-C types since" + " the Swift compiler will automatically type check Swift-only types." + " This expectation is redundant." return false } } /// A Nimble matcher that succeeds when the actual value is an instance of the given class. /// @see beAKindOf if you want to match against subclasses public func beAnInstanceOf(expectedClass: AnyClass) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in let instance = try actualExpression.evaluate() if let validInstance = instance { failureMessage.actualValue = "<\(NSStringFromClass(validInstance.dynamicType)) instance>" } else { failureMessage.actualValue = "" } failureMessage.postfixMessage = "be an instance of \(NSStringFromClass(expectedClass))" return instance != nil && instance!.isMemberOfClass(expectedClass) } } extension NMBObjCMatcher { public class func beAnInstanceOfMatcher(expected: AnyClass) -> NMBMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in return try! beAnInstanceOf(expected).matches(actualExpression, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/BeCloseTo.swift ================================================ import Foundation internal let DefaultDelta = 0.0001 internal func isCloseTo(actualValue: NMBDoubleConvertible?, expectedValue: NMBDoubleConvertible, delta: Double, failureMessage: FailureMessage) -> Bool { failureMessage.postfixMessage = "be close to <\(stringify(expectedValue))> (within \(stringify(delta)))" if actualValue != nil { failureMessage.actualValue = "<\(stringify(actualValue!))>" } else { failureMessage.actualValue = "" } return actualValue != nil && abs(actualValue!.doubleValue - expectedValue.doubleValue) < delta } /// A Nimble matcher that succeeds when a value is close to another. This is used for floating /// point values which can have imprecise results when doing arithmetic on them. /// /// @see equal public func beCloseTo(expectedValue: Double, within delta: Double = DefaultDelta) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in return isCloseTo(try actualExpression.evaluate(), expectedValue: expectedValue, delta: delta, failureMessage: failureMessage) } } /// A Nimble matcher that succeeds when a value is close to another. This is used for floating /// point values which can have imprecise results when doing arithmetic on them. /// /// @see equal public func beCloseTo(expectedValue: NMBDoubleConvertible, within delta: Double = DefaultDelta) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in return isCloseTo(try actualExpression.evaluate(), expectedValue: expectedValue, delta: delta, failureMessage: failureMessage) } } public class NMBObjCBeCloseToMatcher : NSObject, NMBMatcher { var _expected: NSNumber var _delta: CDouble init(expected: NSNumber, within: CDouble) { _expected = expected _delta = within } public func matches(actualExpression: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { let actualBlock: () -> NMBDoubleConvertible? = ({ return actualExpression() as? NMBDoubleConvertible }) let expr = Expression(expression: actualBlock, location: location) let matcher = beCloseTo(self._expected, within: self._delta) return try! matcher.matches(expr, failureMessage: failureMessage) } public func doesNotMatch(actualExpression: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { let actualBlock: () -> NMBDoubleConvertible? = ({ return actualExpression() as? NMBDoubleConvertible }) let expr = Expression(expression: actualBlock, location: location) let matcher = beCloseTo(self._expected, within: self._delta) return try! matcher.doesNotMatch(expr, failureMessage: failureMessage) } public var within: (CDouble) -> NMBObjCBeCloseToMatcher { return ({ delta in return NMBObjCBeCloseToMatcher(expected: self._expected, within: delta) }) } } extension NMBObjCMatcher { public class func beCloseToMatcher(expected: NSNumber, within: CDouble) -> NMBObjCBeCloseToMatcher { return NMBObjCBeCloseToMatcher(expected: expected, within: within) } } public func beCloseTo(expectedValues: [Double], within delta: Double = DefaultDelta) -> NonNilMatcherFunc <[Double]> { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be close to <\(stringify(expectedValues))> (each within \(stringify(delta)))" if let actual = try actualExpression.evaluate() { if actual.count != expectedValues.count { return false } else { for (index, actualItem) in actual.enumerate() { if fabs(actualItem - expectedValues[index]) > delta { return false } } return true } } return false } } // MARK: - Operators infix operator ≈ { associativity none precedence 130 } public func ≈(lhs: Expectation<[Double]>, rhs: [Double]) { lhs.to(beCloseTo(rhs)) } public func ≈(lhs: Expectation, rhs: Double) { lhs.to(beCloseTo(rhs)) } public func ≈(lhs: Expectation, rhs: (expected: Double, delta: Double)) { lhs.to(beCloseTo(rhs.expected, within: rhs.delta)) } public func ==(lhs: Expectation, rhs: (expected: Double, delta: Double)) { lhs.to(beCloseTo(rhs.expected, within: rhs.delta)) } // make this higher precedence than exponents so the Doubles either end aren't pulled in // unexpectantly infix operator ± { precedence 170 } public func ±(lhs: Double, rhs: Double) -> (expected: Double, delta: Double) { return (expected: lhs, delta: rhs) } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/BeEmpty.swift ================================================ import Foundation /// A Nimble matcher that succeeds when a value is "empty". For collections, this /// means the are no items in that collection. For strings, it is an empty string. public func beEmpty() -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be empty" let actualSeq = try actualExpression.evaluate() if actualSeq == nil { return true } var generator = actualSeq!.generate() return generator.next() == nil } } /// A Nimble matcher that succeeds when a value is "empty". For collections, this /// means the are no items in that collection. For strings, it is an empty string. public func beEmpty() -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be empty" let actualString = try actualExpression.evaluate() return actualString == nil || (actualString! as NSString).length == 0 } } /// A Nimble matcher that succeeds when a value is "empty". For collections, this /// means the are no items in that collection. For NSString instances, it is an empty string. public func beEmpty() -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be empty" let actualString = try actualExpression.evaluate() return actualString == nil || actualString!.length == 0 } } // Without specific overrides, beEmpty() is ambiguous for NSDictionary, NSArray, // etc, since they conform to SequenceType as well as NMBCollection. /// A Nimble matcher that succeeds when a value is "empty". For collections, this /// means the are no items in that collection. For strings, it is an empty string. public func beEmpty() -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be empty" let actualDictionary = try actualExpression.evaluate() return actualDictionary == nil || actualDictionary!.count == 0 } } /// A Nimble matcher that succeeds when a value is "empty". For collections, this /// means the are no items in that collection. For strings, it is an empty string. public func beEmpty() -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be empty" let actualArray = try actualExpression.evaluate() return actualArray == nil || actualArray!.count == 0 } } /// A Nimble matcher that succeeds when a value is "empty". For collections, this /// means the are no items in that collection. For strings, it is an empty string. public func beEmpty() -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be empty" let actual = try actualExpression.evaluate() return actual == nil || actual!.count == 0 } } extension NMBObjCMatcher { public class func beEmptyMatcher() -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let location = actualExpression.location let actualValue = try! actualExpression.evaluate() failureMessage.postfixMessage = "be empty" if let value = actualValue as? NMBCollection { let expr = Expression(expression: ({ value as NMBCollection }), location: location) return try! beEmpty().matches(expr, failureMessage: failureMessage) } else if let value = actualValue as? NSString { let expr = Expression(expression: ({ value as String }), location: location) return try! beEmpty().matches(expr, failureMessage: failureMessage) } else if let actualValue = actualValue { failureMessage.postfixMessage = "be empty (only works for NSArrays, NSSets, NSDictionaries, NSHashTables, and NSStrings)" failureMessage.actualValue = "\(NSStringFromClass(actualValue.dynamicType)) type" } return false } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/BeGreaterThan.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual value is greater than the expected value. public func beGreaterThan(expectedValue: T?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be greater than <\(stringify(expectedValue))>" return try actualExpression.evaluate() > expectedValue } } /// A Nimble matcher that succeeds when the actual value is greater than the expected value. public func beGreaterThan(expectedValue: NMBComparable?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be greater than <\(stringify(expectedValue))>" let actualValue = try actualExpression.evaluate() let matches = actualValue != nil && actualValue!.NMB_compare(expectedValue) == NSComparisonResult.OrderedDescending return matches } } public func >(lhs: Expectation, rhs: T) { lhs.to(beGreaterThan(rhs)) } public func >(lhs: Expectation, rhs: NMBComparable?) { lhs.to(beGreaterThan(rhs)) } extension NMBObjCMatcher { public class func beGreaterThanMatcher(expected: NMBComparable?) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let expr = actualExpression.cast { $0 as? NMBComparable } return try! beGreaterThan(expected).matches(expr, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/BeGreaterThanOrEqualTo.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual value is greater than /// or equal to the expected value. public func beGreaterThanOrEqualTo(expectedValue: T?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be greater than or equal to <\(stringify(expectedValue))>" let actualValue = try actualExpression.evaluate() return actualValue >= expectedValue } } /// A Nimble matcher that succeeds when the actual value is greater than /// or equal to the expected value. public func beGreaterThanOrEqualTo(expectedValue: T?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be greater than or equal to <\(stringify(expectedValue))>" let actualValue = try actualExpression.evaluate() let matches = actualValue != nil && actualValue!.NMB_compare(expectedValue) != NSComparisonResult.OrderedAscending return matches } } public func >=(lhs: Expectation, rhs: T) { lhs.to(beGreaterThanOrEqualTo(rhs)) } public func >=(lhs: Expectation, rhs: T) { lhs.to(beGreaterThanOrEqualTo(rhs)) } extension NMBObjCMatcher { public class func beGreaterThanOrEqualToMatcher(expected: NMBComparable?) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let expr = actualExpression.cast { $0 as? NMBComparable } return try! beGreaterThanOrEqualTo(expected).matches(expr, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/BeIdenticalTo.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual value is the same instance /// as the expected instance. public func beIdenticalTo(expected: T?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in let actual = try actualExpression.evaluate() failureMessage.actualValue = "\(identityAsString(actual))" failureMessage.postfixMessage = "be identical to \(identityAsString(expected))" return actual === expected && actual !== nil } } public func ===(lhs: Expectation, rhs: T?) { lhs.to(beIdenticalTo(rhs)) } public func !==(lhs: Expectation, rhs: T?) { lhs.toNot(beIdenticalTo(rhs)) } extension NMBObjCMatcher { public class func beIdenticalToMatcher(expected: NSObject?) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in return try! beIdenticalTo(expected).matches(actualExpression, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/BeLessThan.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual value is less than the expected value. public func beLessThan(expectedValue: T?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be less than <\(stringify(expectedValue))>" return try actualExpression.evaluate() < expectedValue } } /// A Nimble matcher that succeeds when the actual value is less than the expected value. public func beLessThan(expectedValue: NMBComparable?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be less than <\(stringify(expectedValue))>" let actualValue = try actualExpression.evaluate() let matches = actualValue != nil && actualValue!.NMB_compare(expectedValue) == NSComparisonResult.OrderedAscending return matches } } public func <(lhs: Expectation, rhs: T) { lhs.to(beLessThan(rhs)) } public func <(lhs: Expectation, rhs: NMBComparable?) { lhs.to(beLessThan(rhs)) } extension NMBObjCMatcher { public class func beLessThanMatcher(expected: NMBComparable?) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let expr = actualExpression.cast { $0 as! NMBComparable? } return try! beLessThan(expected).matches(expr, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/BeLessThanOrEqual.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual value is less than /// or equal to the expected value. public func beLessThanOrEqualTo(expectedValue: T?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be less than or equal to <\(stringify(expectedValue))>" return try actualExpression.evaluate() <= expectedValue } } /// A Nimble matcher that succeeds when the actual value is less than /// or equal to the expected value. public func beLessThanOrEqualTo(expectedValue: T?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be less than or equal to <\(stringify(expectedValue))>" let actualValue = try actualExpression.evaluate() return actualValue != nil && actualValue!.NMB_compare(expectedValue) != NSComparisonResult.OrderedDescending } } public func <=(lhs: Expectation, rhs: T) { lhs.to(beLessThanOrEqualTo(rhs)) } public func <=(lhs: Expectation, rhs: T) { lhs.to(beLessThanOrEqualTo(rhs)) } extension NMBObjCMatcher { public class func beLessThanOrEqualToMatcher(expected: NMBComparable?) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil:false) { actualExpression, failureMessage in let expr = actualExpression.cast { $0 as? NMBComparable } return try! beLessThanOrEqualTo(expected).matches(expr, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/BeLogical.swift ================================================ import Foundation internal func matcherWithFailureMessage(matcher: M, postprocessor: (FailureMessage) -> Void) -> FullMatcherFunc { return FullMatcherFunc { actualExpression, failureMessage, isNegation in let pass: Bool if isNegation { pass = try matcher.doesNotMatch(actualExpression, failureMessage: failureMessage) } else { pass = try matcher.matches(actualExpression, failureMessage: failureMessage) } postprocessor(failureMessage) return pass } } // MARK: beTrue() / beFalse() /// A Nimble matcher that succeeds when the actual value is exactly true. /// This matcher will not match against nils. public func beTrue() -> FullMatcherFunc { return matcherWithFailureMessage(equal(true)) { failureMessage in failureMessage.postfixMessage = "be true" } } /// A Nimble matcher that succeeds when the actual value is exactly false. /// This matcher will not match against nils. public func beFalse() -> FullMatcherFunc { return matcherWithFailureMessage(equal(false)) { failureMessage in failureMessage.postfixMessage = "be false" } } // MARK: beTruthy() / beFalsy() /// A Nimble matcher that succeeds when the actual value is not logically false. public func beTruthy() -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be truthy" let actualValue = try actualExpression.evaluate() if let actualValue = actualValue { if let actualValue = actualValue as? BooleanType { return actualValue.boolValue == true } } return actualValue != nil } } /// A Nimble matcher that succeeds when the actual value is logically false. /// This matcher will match against nils. public func beFalsy() -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be falsy" let actualValue = try actualExpression.evaluate() if let actualValue = actualValue { if let actualValue = actualValue as? BooleanType { return actualValue.boolValue != true } } return actualValue == nil } } extension NMBObjCMatcher { public class func beTruthyMatcher() -> NMBObjCMatcher { return NMBObjCMatcher { actualExpression, failureMessage in let expr = actualExpression.cast { ($0 as? NSNumber)?.boolValue ?? false as BooleanType? } return try! beTruthy().matches(expr, failureMessage: failureMessage) } } public class func beFalsyMatcher() -> NMBObjCMatcher { return NMBObjCMatcher { actualExpression, failureMessage in let expr = actualExpression.cast { ($0 as? NSNumber)?.boolValue ?? false as BooleanType? } return try! beFalsy().matches(expr, failureMessage: failureMessage) } } public class func beTrueMatcher() -> NMBObjCMatcher { return NMBObjCMatcher { actualExpression, failureMessage in let expr = actualExpression.cast { ($0 as? NSNumber)?.boolValue ?? false as Bool? } return try! beTrue().matches(expr, failureMessage: failureMessage) } } public class func beFalseMatcher() -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let expr = actualExpression.cast { ($0 as? NSNumber)?.boolValue ?? false as Bool? } return try! beFalse().matches(expr, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/BeNil.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual value is nil. public func beNil() -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be nil" let actualValue = try actualExpression.evaluate() return actualValue == nil } } extension NMBObjCMatcher { public class func beNilMatcher() -> NMBObjCMatcher { return NMBObjCMatcher { actualExpression, failureMessage in return try! beNil().matches(actualExpression, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/BeginWith.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual sequence's first element /// is equal to the expected value. public func beginWith(startingElement: T) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "begin with <\(startingElement)>" if let actualValue = try actualExpression.evaluate() { var actualGenerator = actualValue.generate() return actualGenerator.next() == startingElement } return false } } /// A Nimble matcher that succeeds when the actual collection's first element /// is equal to the expected object. public func beginWith(startingElement: AnyObject) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "begin with <\(startingElement)>" let collection = try actualExpression.evaluate() return collection != nil && collection!.indexOfObject(startingElement) == 0 } } /// A Nimble matcher that succeeds when the actual string contains expected substring /// where the expected substring's location is zero. public func beginWith(startingSubstring: String) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "begin with <\(startingSubstring)>" if let actual = try actualExpression.evaluate() { let range = actual.rangeOfString(startingSubstring) return range != nil && range!.startIndex == actual.startIndex } return false } } extension NMBObjCMatcher { public class func beginWithMatcher(expected: AnyObject) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let actual = try! actualExpression.evaluate() if let _ = actual as? String { let expr = actualExpression.cast { $0 as? String } return try! beginWith(expected as! String).matches(expr, failureMessage: failureMessage) } else { let expr = actualExpression.cast { $0 as? NMBOrderedCollection } return try! beginWith(expected).matches(expr, failureMessage: failureMessage) } } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/Contain.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual sequence contains the expected value. public func contain(items: T...) -> NonNilMatcherFunc { return contain(items) } private func contain(items: [T]) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "contain <\(arrayAsString(items))>" if let actual = try actualExpression.evaluate() { return all(items) { return actual.contains($0) } } return false } } /// A Nimble matcher that succeeds when the actual string contains the expected substring. public func contain(substrings: String...) -> NonNilMatcherFunc { return contain(substrings) } private func contain(substrings: [String]) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "contain <\(arrayAsString(substrings))>" if let actual = try actualExpression.evaluate() { return all(substrings) { let scanRange = Range(start: actual.startIndex, end: actual.endIndex) let range = actual.rangeOfString($0, options: [], range: scanRange, locale: nil) return range != nil && !range!.isEmpty } } return false } } /// A Nimble matcher that succeeds when the actual string contains the expected substring. public func contain(substrings: NSString...) -> NonNilMatcherFunc { return contain(substrings) } private func contain(substrings: [NSString]) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "contain <\(arrayAsString(substrings))>" if let actual = try actualExpression.evaluate() { return all(substrings) { actual.rangeOfString($0.description).length != 0 } } return false } } /// A Nimble matcher that succeeds when the actual collection contains the expected object. public func contain(items: AnyObject?...) -> NonNilMatcherFunc { return contain(items) } private func contain(items: [AnyObject?]) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "contain <\(arrayAsString(items))>" let actual = try actualExpression.evaluate() return all(items) { item in return actual != nil && actual!.containsObject(item) } } } extension NMBObjCMatcher { public class func containMatcher(expected: [NSObject]) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let location = actualExpression.location let actualValue = try! actualExpression.evaluate() if let value = actualValue as? NMBContainer { let expr = Expression(expression: ({ value as NMBContainer }), location: location) // A straightforward cast on the array causes this to crash, so we have to cast the individual items let expectedOptionals: [AnyObject?] = expected.map({ $0 as AnyObject? }) return try! contain(expectedOptionals).matches(expr, failureMessage: failureMessage) } else if let value = actualValue as? NSString { let expr = Expression(expression: ({ value as String }), location: location) return try! contain(expected as! [String]).matches(expr, failureMessage: failureMessage) } else if actualValue != nil { failureMessage.postfixMessage = "contain <\(arrayAsString(expected))> (only works for NSArrays, NSSets, NSHashTables, and NSStrings)" } else { failureMessage.postfixMessage = "contain <\(arrayAsString(expected))>" } return false } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/EndWith.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual sequence's last element /// is equal to the expected value. public func endWith(endingElement: T) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "end with <\(endingElement)>" if let actualValue = try actualExpression.evaluate() { var actualGenerator = actualValue.generate() var lastItem: T? var item: T? repeat { lastItem = item item = actualGenerator.next() } while(item != nil) return lastItem == endingElement } return false } } /// A Nimble matcher that succeeds when the actual collection's last element /// is equal to the expected object. public func endWith(endingElement: AnyObject) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "end with <\(endingElement)>" let collection = try actualExpression.evaluate() return collection != nil && collection!.indexOfObject(endingElement) == collection!.count - 1 } } /// A Nimble matcher that succeeds when the actual string contains the expected substring /// where the expected substring's location is the actual string's length minus the /// expected substring's length. public func endWith(endingSubstring: String) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "end with <\(endingSubstring)>" if let collection = try actualExpression.evaluate() { let range = collection.rangeOfString(endingSubstring) return range != nil && range!.endIndex == collection.endIndex } return false } } extension NMBObjCMatcher { public class func endWithMatcher(expected: AnyObject) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let actual = try! actualExpression.evaluate() if let _ = actual as? String { let expr = actualExpression.cast { $0 as? String } return try! endWith(expected as! String).matches(expr, failureMessage: failureMessage) } else { let expr = actualExpression.cast { $0 as? NMBOrderedCollection } return try! endWith(expected).matches(expr, failureMessage: failureMessage) } } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/Equal.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual value is equal to the expected value. /// Values can support equal by supporting the Equatable protocol. /// /// @see beCloseTo if you want to match imprecise types (eg - floats, doubles). public func equal(expectedValue: T?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "equal <\(stringify(expectedValue))>" let actualValue = try actualExpression.evaluate() let matches = actualValue == expectedValue && expectedValue != nil if expectedValue == nil || actualValue == nil { if expectedValue == nil { failureMessage.postfixActual = " (use beNil() to match nils)" } return false } return matches } } /// A Nimble matcher that succeeds when the actual value is equal to the expected value. /// Values can support equal by supporting the Equatable protocol. /// /// @see beCloseTo if you want to match imprecise types (eg - floats, doubles). public func equal(expectedValue: [T: C]?) -> NonNilMatcherFunc<[T: C]> { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "equal <\(stringify(expectedValue))>" let actualValue = try actualExpression.evaluate() if expectedValue == nil || actualValue == nil { if expectedValue == nil { failureMessage.postfixActual = " (use beNil() to match nils)" } return false } return expectedValue! == actualValue! } } /// A Nimble matcher that succeeds when the actual collection is equal to the expected collection. /// Items must implement the Equatable protocol. public func equal(expectedValue: [T]?) -> NonNilMatcherFunc<[T]> { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "equal <\(stringify(expectedValue))>" let actualValue = try actualExpression.evaluate() if expectedValue == nil || actualValue == nil { if expectedValue == nil { failureMessage.postfixActual = " (use beNil() to match nils)" } return false } return expectedValue! == actualValue! } } /// A Nimble matcher allowing comparison of collection with optional type public func equal(expectedValue: [T?]) -> NonNilMatcherFunc<[T?]> { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "equal <\(stringify(expectedValue))>" if let actualValue = try actualExpression.evaluate() { if expectedValue.count != actualValue.count { return false } for (index, item) in actualValue.enumerate() { let otherItem = expectedValue[index] if item == nil && otherItem == nil { continue } else if item == nil && otherItem != nil { return false } else if item != nil && otherItem == nil { return false } else if item! != otherItem! { return false } } return true } else { failureMessage.postfixActual = " (use beNil() to match nils)" } return false } } /// A Nimble matcher that succeeds when the actual set is equal to the expected set. public func equal(expectedValue: Set?) -> NonNilMatcherFunc> { return equal(expectedValue, stringify: stringify) } /// A Nimble matcher that succeeds when the actual set is equal to the expected set. public func equal(expectedValue: Set?) -> NonNilMatcherFunc> { return equal(expectedValue, stringify: { if let set = $0 { return stringify(Array(set).sort { $0 < $1 }) } else { return "nil" } }) } private func equal(expectedValue: Set?, stringify: Set? -> String) -> NonNilMatcherFunc> { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "equal <\(stringify(expectedValue))>" if let expectedValue = expectedValue { if let actualValue = try actualExpression.evaluate() { failureMessage.actualValue = "<\(stringify(actualValue))>" if expectedValue == actualValue { return true } let missing = expectedValue.subtract(actualValue) if missing.count > 0 { failureMessage.postfixActual += ", missing <\(stringify(missing))>" } let extra = actualValue.subtract(expectedValue) if extra.count > 0 { failureMessage.postfixActual += ", extra <\(stringify(extra))>" } } } else { failureMessage.postfixActual = " (use beNil() to match nils)" } return false } } public func ==(lhs: Expectation, rhs: T?) { lhs.to(equal(rhs)) } public func !=(lhs: Expectation, rhs: T?) { lhs.toNot(equal(rhs)) } public func ==(lhs: Expectation<[T]>, rhs: [T]?) { lhs.to(equal(rhs)) } public func !=(lhs: Expectation<[T]>, rhs: [T]?) { lhs.toNot(equal(rhs)) } public func ==(lhs: Expectation>, rhs: Set?) { lhs.to(equal(rhs)) } public func !=(lhs: Expectation>, rhs: Set?) { lhs.toNot(equal(rhs)) } public func ==(lhs: Expectation>, rhs: Set?) { lhs.to(equal(rhs)) } public func !=(lhs: Expectation>, rhs: Set?) { lhs.toNot(equal(rhs)) } public func ==(lhs: Expectation<[T: C]>, rhs: [T: C]?) { lhs.to(equal(rhs)) } public func !=(lhs: Expectation<[T: C]>, rhs: [T: C]?) { lhs.toNot(equal(rhs)) } extension NMBObjCMatcher { public class func equalMatcher(expected: NSObject) -> NMBMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in return try! equal(expected).matches(actualExpression, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/HaveCount.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual CollectionType's count equals /// the expected value public func haveCount(expectedValue: T.Index.Distance) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in if let actualValue = try actualExpression.evaluate() { failureMessage.postfixMessage = "have \(actualValue) with count \(expectedValue)" let result = expectedValue == actualValue.count failureMessage.actualValue = "\(actualValue.count)" return result } else { return false } } } /// A Nimble matcher that succeeds when the actual collection's count equals /// the expected value public func haveCount(expectedValue: Int) -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in if let actualValue = try actualExpression.evaluate() { failureMessage.postfixMessage = "have \(actualValue) with count \(expectedValue)" let result = expectedValue == actualValue.count failureMessage.actualValue = "\(actualValue.count)" return result } else { return false } } } extension NMBObjCMatcher { public class func haveCountMatcher(expected: NSNumber) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let location = actualExpression.location let actualValue = try! actualExpression.evaluate() if let value = actualValue as? NMBCollection { let expr = Expression(expression: ({ value as NMBCollection}), location: location) return try! haveCount(expected.integerValue).matches(expr, failureMessage: failureMessage) } else if let actualValue = actualValue { failureMessage.postfixMessage = "get type of NSArray, NSSet, NSDictionary, or NSHashTable" failureMessage.actualValue = "\(NSStringFromClass(actualValue.dynamicType))" } return false } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/Match.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual string satisfies the regular expression /// described by the expected string. public func match(expectedValue: String?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "match <\(stringify(expectedValue))>" if let actual = try actualExpression.evaluate() { if let regexp = expectedValue { return actual.rangeOfString(regexp, options: .RegularExpressionSearch) != nil } } return false } } extension NMBObjCMatcher { public class func matchMatcher(expected: NSString) -> NMBMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let actual = actualExpression.cast { $0 as? String } return try! match(expected.description).matches(actual, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/MatcherProtocols.swift ================================================ import Foundation /// Implement this protocol to implement a custom matcher for Swift public protocol Matcher { typealias ValueType func matches(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool } /// Objective-C interface to the Swift variant of Matcher. @objc public protocol NMBMatcher { func matches(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool func doesNotMatch(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool } /// Protocol for types that support contain() matcher. @objc public protocol NMBContainer { func containsObject(object: AnyObject!) -> Bool } extension NSArray : NMBContainer {} extension NSSet : NMBContainer {} extension NSHashTable : NMBContainer {} /// Protocol for types that support only beEmpty(), haveCount() matchers @objc public protocol NMBCollection { var count: Int { get } } extension NSSet : NMBCollection {} extension NSDictionary : NMBCollection {} extension NSHashTable : NMBCollection {} extension NSMapTable : NMBCollection {} /// Protocol for types that support beginWith(), endWith(), beEmpty() matchers @objc public protocol NMBOrderedCollection : NMBCollection { func indexOfObject(object: AnyObject!) -> Int } extension NSArray : NMBOrderedCollection {} /// Protocol for types to support beCloseTo() matcher @objc public protocol NMBDoubleConvertible { var doubleValue: CDouble { get } } extension NSNumber : NMBDoubleConvertible { } private let dateFormatter: NSDateFormatter = { let formatter = NSDateFormatter() formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSSS" formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") return formatter }() extension NSDate: NMBDoubleConvertible { public var doubleValue: CDouble { get { return self.timeIntervalSinceReferenceDate } } } extension NMBDoubleConvertible { public var stringRepresentation: String { get { if let date = self as? NSDate { return dateFormatter.stringFromDate(date) } if let debugStringConvertible = self as? CustomDebugStringConvertible { return debugStringConvertible.debugDescription } if let stringConvertible = self as? CustomStringConvertible { return stringConvertible.description } return "" } } } /// Protocol for types to support beLessThan(), beLessThanOrEqualTo(), /// beGreaterThan(), beGreaterThanOrEqualTo(), and equal() matchers. /// /// Types that conform to Swift's Comparable protocol will work implicitly too @objc public protocol NMBComparable { func NMB_compare(otherObject: NMBComparable!) -> NSComparisonResult } extension NSNumber : NMBComparable { public func NMB_compare(otherObject: NMBComparable!) -> NSComparisonResult { return compare(otherObject as! NSNumber) } } extension NSString : NMBComparable { public func NMB_compare(otherObject: NMBComparable!) -> NSComparisonResult { return compare(otherObject as! String) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/RaisesException.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual expression raises an /// exception with the specified name, reason, and/or userInfo. /// /// Alternatively, you can pass a closure to do any arbitrary custom matching /// to the raised exception. The closure only gets called when an exception /// is raised. /// /// nil arguments indicates that the matcher should not attempt to match against /// that parameter. public func raiseException( named named: String? = nil, reason: String? = nil, userInfo: NSDictionary? = nil, closure: ((NSException) -> Void)? = nil) -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in var exception: NSException? let capture = NMBExceptionCapture(handler: ({ e in exception = e }), finally: nil) capture.tryBlock { try! actualExpression.evaluate() return } setFailureMessageForException(failureMessage, exception: exception, named: named, reason: reason, userInfo: userInfo, closure: closure) return exceptionMatchesNonNilFieldsOrClosure(exception, named: named, reason: reason, userInfo: userInfo, closure: closure) } } internal func setFailureMessageForException( failureMessage: FailureMessage, exception: NSException?, named: String?, reason: String?, userInfo: NSDictionary?, closure: ((NSException) -> Void)?) { failureMessage.postfixMessage = "raise exception" if let named = named { failureMessage.postfixMessage += " with name <\(named)>" } if let reason = reason { failureMessage.postfixMessage += " with reason <\(reason)>" } if let userInfo = userInfo { failureMessage.postfixMessage += " with userInfo <\(userInfo)>" } if let _ = closure { failureMessage.postfixMessage += " that satisfies block" } if named == nil && reason == nil && userInfo == nil && closure == nil { failureMessage.postfixMessage = "raise any exception" } if let exception = exception { failureMessage.actualValue = "\(NSStringFromClass(exception.dynamicType)) { name=\(exception.name), reason='\(stringify(exception.reason))', userInfo=\(stringify(exception.userInfo)) }" } else { failureMessage.actualValue = "no exception" } } internal func exceptionMatchesNonNilFieldsOrClosure( exception: NSException?, named: String?, reason: String?, userInfo: NSDictionary?, closure: ((NSException) -> Void)?) -> Bool { var matches = false if let exception = exception { matches = true if named != nil && exception.name != named { matches = false } if reason != nil && exception.reason != reason { matches = false } if userInfo != nil && exception.userInfo != userInfo { matches = false } if let closure = closure { let assertions = gatherFailingExpectations { closure(exception) } let messages = assertions.map { $0.message } if messages.count > 0 { matches = false } } } return matches } public class NMBObjCRaiseExceptionMatcher : NSObject, NMBMatcher { internal var _name: String? internal var _reason: String? internal var _userInfo: NSDictionary? internal var _block: ((NSException) -> Void)? internal init(name: String?, reason: String?, userInfo: NSDictionary?, block: ((NSException) -> Void)?) { _name = name _reason = reason _userInfo = userInfo _block = block } public func matches(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { let block: () -> Any? = ({ actualBlock(); return nil }) let expr = Expression(expression: block, location: location) return try! raiseException( named: _name, reason: _reason, userInfo: _userInfo, closure: _block ).matches(expr, failureMessage: failureMessage) } public func doesNotMatch(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { return !matches(actualBlock, failureMessage: failureMessage, location: location) } public var named: (name: String) -> NMBObjCRaiseExceptionMatcher { return ({ name in return NMBObjCRaiseExceptionMatcher( name: name, reason: self._reason, userInfo: self._userInfo, block: self._block ) }) } public var reason: (reason: String?) -> NMBObjCRaiseExceptionMatcher { return ({ reason in return NMBObjCRaiseExceptionMatcher( name: self._name, reason: reason, userInfo: self._userInfo, block: self._block ) }) } public var userInfo: (userInfo: NSDictionary?) -> NMBObjCRaiseExceptionMatcher { return ({ userInfo in return NMBObjCRaiseExceptionMatcher( name: self._name, reason: self._reason, userInfo: userInfo, block: self._block ) }) } public var satisfyingBlock: (block: ((NSException) -> Void)?) -> NMBObjCRaiseExceptionMatcher { return ({ block in return NMBObjCRaiseExceptionMatcher( name: self._name, reason: self._reason, userInfo: self._userInfo, block: block ) }) } } extension NMBObjCMatcher { public class func raiseExceptionMatcher() -> NMBObjCRaiseExceptionMatcher { return NMBObjCRaiseExceptionMatcher(name: nil, reason: nil, userInfo: nil, block: nil) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/SatisfyAnyOf.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual value matches with any of the matchers /// provided in the variable list of matchers. public func satisfyAnyOf(matchers: U...) -> NonNilMatcherFunc { return satisfyAnyOf(matchers) } internal func satisfyAnyOf(matchers: [U]) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in var fullPostfixMessage = "match one of: " var matches = false for var i = 0; i < matchers.count && !matches; ++i { fullPostfixMessage += "{" let matcher = matchers[i] matches = try matcher.matches(actualExpression, failureMessage: failureMessage) fullPostfixMessage += "\(failureMessage.postfixMessage)}" if i < (matchers.count - 1) { fullPostfixMessage += ", or " } } failureMessage.postfixMessage = fullPostfixMessage if let actualValue = try actualExpression.evaluate() { failureMessage.actualValue = "\(actualValue)" } return matches } } public func ||(left: NonNilMatcherFunc, right: NonNilMatcherFunc) -> NonNilMatcherFunc { return satisfyAnyOf(left, right) } public func ||(left: FullMatcherFunc, right: FullMatcherFunc) -> NonNilMatcherFunc { return satisfyAnyOf(left, right) } public func ||(left: MatcherFunc, right: MatcherFunc) -> NonNilMatcherFunc { return satisfyAnyOf(left, right) } extension NMBObjCMatcher { public class func satisfyAnyOfMatcher(matchers: [NMBObjCMatcher]) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in if matchers.isEmpty { failureMessage.stringValue = "satisfyAnyOf must be called with at least one matcher" return false } var elementEvaluators = [NonNilMatcherFunc]() for matcher in matchers { let elementEvaluator: (Expression, FailureMessage) -> Bool = { expression, failureMessage in return matcher.matches( {try! expression.evaluate()}, failureMessage: failureMessage, location: actualExpression.location) } elementEvaluators.append(NonNilMatcherFunc(elementEvaluator)) } return try! satisfyAnyOf(elementEvaluators).matches(actualExpression, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Matchers/ThrowError.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual expression throws an /// error of the specified type or from the specified case. /// /// Errors are tried to be compared by their implementation of Equatable, /// otherwise they fallback to comparision by _domain and _code. /// /// Alternatively, you can pass a closure to do any arbitrary custom matching /// to the thrown error. The closure only gets called when an error was thrown. /// /// nil arguments indicates that the matcher should not attempt to match against /// that parameter. public func throwError( error: T? = nil, errorType: T.Type? = nil, closure: ((T) -> Void)? = nil) -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in var actualError: ErrorType? do { try actualExpression.evaluate() } catch let catchedError { actualError = catchedError } setFailureMessageForError(failureMessage, actualError: actualError, error: error, errorType: errorType, closure: closure) return errorMatchesNonNilFieldsOrClosure(actualError, error: error, errorType: errorType, closure: closure) } } internal func setFailureMessageForError( failureMessage: FailureMessage, actualError: ErrorType?, error: T?, errorType: T.Type? = nil, closure: ((T) -> Void)?) { failureMessage.postfixMessage = "throw error" if let error = error { if let error = error as? CustomDebugStringConvertible { failureMessage.postfixMessage += " <\(error.debugDescription)>" } else { failureMessage.postfixMessage += " <\(error)>" } } else if errorType != nil || closure != nil { failureMessage.postfixMessage += " from type <\(T.self)>" } if let _ = closure { failureMessage.postfixMessage += " that satisfies block" } if error == nil && errorType == nil && closure == nil { failureMessage.postfixMessage = "throw any error" } if let actualError = actualError { failureMessage.actualValue = "<\(actualError)>" } else { failureMessage.actualValue = "no error" } } internal func errorMatchesExpectedError( actualError: ErrorType, expectedError: T) -> Bool { return actualError._domain == expectedError._domain && actualError._code == expectedError._code } internal func errorMatchesExpectedError( actualError: ErrorType, expectedError: T) -> Bool { if let actualError = actualError as? T { return actualError == expectedError } return false } internal func errorMatchesNonNilFieldsOrClosure( actualError: ErrorType?, error: T?, errorType: T.Type?, closure: ((T) -> Void)?) -> Bool { var matches = false if let actualError = actualError { matches = true if let error = error { if !errorMatchesExpectedError(actualError, expectedError: error) { matches = false } } if let actualError = actualError as? T { if let closure = closure { let assertions = gatherFailingExpectations { closure(actualError as T) } let messages = assertions.map { $0.message } if messages.count > 0 { matches = false } } } else if errorType != nil && closure != nil { // The closure expects another ErrorType as argument, so this // is _supposed_ to fail, so that it becomes more obvious. let assertions = gatherExpectations { expect(actualError is T).to(equal(true)) } precondition(assertions.map { $0.message }.count > 0) matches = false } } return matches } /// A Nimble matcher that succeeds when the actual expression throws any /// error or when the passed closures' arbitrary custom matching succeeds. /// /// This duplication to it's generic adequate is required to allow to receive /// values of the existential type ErrorType in the closure. /// /// The closure only gets called when an error was thrown. public func throwError( closure closure: ((ErrorType) -> Void)? = nil) -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in var actualError: ErrorType? do { try actualExpression.evaluate() } catch let catchedError { actualError = catchedError } setFailureMessageForError(failureMessage, actualError: actualError, closure: closure) return errorMatchesNonNilFieldsOrClosure(actualError, closure: closure) } } internal func setFailureMessageForError( failureMessage: FailureMessage, actualError: ErrorType?, closure: ((ErrorType) -> Void)?) { failureMessage.postfixMessage = "throw error" if let _ = closure { failureMessage.postfixMessage += " that satisfies block" } else { failureMessage.postfixMessage = "throw any error" } if let actualError = actualError { failureMessage.actualValue = "<\(actualError)>" } else { failureMessage.actualValue = "no error" } } internal func errorMatchesNonNilFieldsOrClosure( actualError: ErrorType?, closure: ((ErrorType) -> Void)?) -> Bool { var matches = false if let actualError = actualError { matches = true if let closure = closure { let assertions = gatherFailingExpectations { closure(actualError) } let messages = assertions.map { $0.message } if messages.count > 0 { matches = false } } } return matches } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Nimble.h ================================================ #import #import "NMBExceptionCapture.h" #import "DSL.h" FOUNDATION_EXPORT double NimbleVersionNumber; FOUNDATION_EXPORT const unsigned char NimbleVersionString[]; ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/ObjCExpectation.swift ================================================ internal struct ObjCMatcherWrapper : Matcher { let matcher: NMBMatcher func matches(actualExpression: Expression, failureMessage: FailureMessage) -> Bool { return matcher.matches( ({ try! actualExpression.evaluate() }), failureMessage: failureMessage, location: actualExpression.location) } func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) -> Bool { return matcher.doesNotMatch( ({ try! actualExpression.evaluate() }), failureMessage: failureMessage, location: actualExpression.location) } } // Equivalent to Expectation, but for Nimble's Objective-C interface public class NMBExpectation : NSObject { internal let _actualBlock: () -> NSObject! internal var _negative: Bool internal let _file: String internal let _line: UInt internal var _timeout: NSTimeInterval = 1.0 public init(actualBlock: () -> NSObject!, negative: Bool, file: String, line: UInt) { self._actualBlock = actualBlock self._negative = negative self._file = file self._line = line } private var expectValue: Expectation { return expect(_file, line: _line){ self._actualBlock() as NSObject? } } public var withTimeout: (NSTimeInterval) -> NMBExpectation { return ({ timeout in self._timeout = timeout return self }) } public var to: (NMBMatcher) -> Void { return ({ matcher in self.expectValue.to(ObjCMatcherWrapper(matcher: matcher)) }) } public var toWithDescription: (NMBMatcher, String) -> Void { return ({ matcher, description in self.expectValue.to(ObjCMatcherWrapper(matcher: matcher), description: description) }) } public var toNot: (NMBMatcher) -> Void { return ({ matcher in self.expectValue.toNot( ObjCMatcherWrapper(matcher: matcher) ) }) } public var toNotWithDescription: (NMBMatcher, String) -> Void { return ({ matcher, description in self.expectValue.toNot( ObjCMatcherWrapper(matcher: matcher), description: description ) }) } public var notTo: (NMBMatcher) -> Void { return toNot } public var notToWithDescription: (NMBMatcher, String) -> Void { return toNotWithDescription } public var toEventually: (NMBMatcher) -> Void { return ({ matcher in self.expectValue.toEventually( ObjCMatcherWrapper(matcher: matcher), timeout: self._timeout, description: nil ) }) } public var toEventuallyWithDescription: (NMBMatcher, String) -> Void { return ({ matcher, description in self.expectValue.toEventually( ObjCMatcherWrapper(matcher: matcher), timeout: self._timeout, description: description ) }) } public var toEventuallyNot: (NMBMatcher) -> Void { return ({ matcher in self.expectValue.toEventuallyNot( ObjCMatcherWrapper(matcher: matcher), timeout: self._timeout, description: nil ) }) } public var toEventuallyNotWithDescription: (NMBMatcher, String) -> Void { return ({ matcher, description in self.expectValue.toEventuallyNot( ObjCMatcherWrapper(matcher: matcher), timeout: self._timeout, description: description ) }) } public var toNotEventually: (NMBMatcher) -> Void { return toEventuallyNot } public var toNotEventuallyWithDescription: (NMBMatcher, String) -> Void { return toEventuallyNotWithDescription } public class func failWithMessage(message: String, file: String, line: UInt) { fail(message, location: SourceLocation(file: file, line: line)) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Utils/Async.swift ================================================ import Foundation import Dispatch private let timeoutLeeway: UInt64 = NSEC_PER_MSEC private let pollLeeway: UInt64 = NSEC_PER_MSEC /// Stores debugging information about callers internal struct WaitingInfo: CustomStringConvertible { let name: String let file: String let lineNumber: UInt var description: String { return "\(name) at \(file):\(lineNumber)" } } internal protocol WaitLock { func acquireWaitingLock(fnName: String, file: String, line: UInt) func releaseWaitingLock() func isWaitingLocked() -> Bool } internal class AssertionWaitLock: WaitLock { private var currentWaiter: WaitingInfo? = nil init() { } func acquireWaitingLock(fnName: String, file: String, line: UInt) { let info = WaitingInfo(name: fnName, file: file, lineNumber: line) nimblePrecondition( NSThread.isMainThread(), "InvalidNimbleAPIUsage", "\(fnName) can only run on the main thread." ) nimblePrecondition( currentWaiter == nil, "InvalidNimbleAPIUsage", "Nested async expectations are not allowed to avoid creating flaky tests.\n\n" + "The call to\n\t\(info)\n" + "triggered this exception because\n\t\(currentWaiter!)\n" + "is currently managing the main run loop." ) currentWaiter = info } func isWaitingLocked() -> Bool { return currentWaiter != nil } func releaseWaitingLock() { currentWaiter = nil } } internal enum AwaitResult { /// Incomplete indicates None (aka - this value hasn't been fulfilled yet) case Incomplete /// TimedOut indicates the result reached its defined timeout limit before returning case TimedOut /// BlockedRunLoop indicates the main runloop is too busy processing other blocks to trigger /// the timeout code. /// /// This may also mean the async code waiting upon may have never actually ran within the /// required time because other timers & sources are running on the main run loop. case BlockedRunLoop /// The async block successfully executed and returned a given result case Completed(T) /// When a Swift Error is thrown case ErrorThrown(ErrorType) /// When an Objective-C Exception is raised case RaisedException(NSException) func isIncomplete() -> Bool { switch self { case .Incomplete: return true default: return false } } func isCompleted() -> Bool { switch self { case .Completed(_): return true default: return false } } } /// Holds the resulting value from an asynchronous expectation. /// This class is thread-safe at receiving an "response" to this promise. internal class AwaitPromise { private(set) internal var asyncResult: AwaitResult = .Incomplete private var signal: dispatch_semaphore_t init() { signal = dispatch_semaphore_create(1) } /// Resolves the promise with the given result if it has not been resolved. Repeated calls to /// this method will resolve in a no-op. /// /// @returns a Bool that indicates if the async result was accepted or rejected because another /// value was recieved first. func resolveResult(result: AwaitResult) -> Bool { if dispatch_semaphore_wait(signal, DISPATCH_TIME_NOW) == 0 { self.asyncResult = result return true } else { return false } } } internal struct AwaitTrigger { let timeoutSource: dispatch_source_t let actionSource: dispatch_source_t? let start: () throws -> Void } /// Factory for building fully configured AwaitPromises and waiting for their results. /// /// This factory stores all the state for an async expectation so that Await doesn't /// doesn't have to manage it. internal class AwaitPromiseBuilder { let awaiter: Awaiter let waitLock: WaitLock let trigger: AwaitTrigger let promise: AwaitPromise internal init( awaiter: Awaiter, waitLock: WaitLock, promise: AwaitPromise, trigger: AwaitTrigger) { self.awaiter = awaiter self.waitLock = waitLock self.promise = promise self.trigger = trigger } func timeout(timeoutInterval: NSTimeInterval, forcefullyAbortTimeout: NSTimeInterval) -> Self { // = Discussion = // // There's a lot of technical decisions here that is useful to elaborate on. This is // definitely more lower-level than the previous NSRunLoop based implementation. // // // Why Dispatch Source? // // // We're using a dispatch source to have better control of the run loop behavior. // A timer source gives us deferred-timing control without having to rely as much on // a run loop's traditional dispatching machinery (eg - NSTimers, DefaultRunLoopMode, etc.) // which is ripe for getting corrupted by application code. // // And unlike dispatch_async(), we can control how likely our code gets prioritized to // executed (see leeway parameter) + DISPATCH_TIMER_STRICT. // // This timer is assumed to run on the HIGH priority queue to ensure it maintains the // highest priority over normal application / test code when possible. // // // Run Loop Management // // In order to properly interrupt the waiting behavior performed by this factory class, // this timer stops the main run loop to tell the waiter code that the result should be // checked. // // In addition, stopping the run loop is used to halt code executed on the main run loop. dispatch_source_set_timer( trigger.timeoutSource, dispatch_time(DISPATCH_TIME_NOW, Int64(timeoutInterval * Double(NSEC_PER_SEC))), DISPATCH_TIME_FOREVER, timeoutLeeway ) dispatch_source_set_event_handler(trigger.timeoutSource) { guard self.promise.asyncResult.isIncomplete() else { return } let timedOutSem = dispatch_semaphore_create(0) let semTimedOutOrBlocked = dispatch_semaphore_create(0) dispatch_semaphore_signal(semTimedOutOrBlocked) let runLoop = CFRunLoopGetMain() CFRunLoopPerformBlock(runLoop, kCFRunLoopDefaultMode) { if dispatch_semaphore_wait(semTimedOutOrBlocked, DISPATCH_TIME_NOW) == 0 { dispatch_semaphore_signal(timedOutSem) dispatch_semaphore_signal(semTimedOutOrBlocked) if self.promise.resolveResult(.TimedOut) { CFRunLoopStop(CFRunLoopGetMain()) } } } // potentially interrupt blocking code on run loop to let timeout code run CFRunLoopStop(runLoop) let now = dispatch_time(DISPATCH_TIME_NOW, Int64(forcefullyAbortTimeout * Double(NSEC_PER_SEC))) let didNotTimeOut = dispatch_semaphore_wait(timedOutSem, now) != 0 let timeoutWasNotTriggered = dispatch_semaphore_wait(semTimedOutOrBlocked, 0) == 0 if didNotTimeOut && timeoutWasNotTriggered { if self.promise.resolveResult(.BlockedRunLoop) { CFRunLoopStop(CFRunLoopGetMain()) } } } return self } /// Blocks for an asynchronous result. /// /// @discussion /// This function must be executed on the main thread and cannot be nested. This is because /// this function (and it's related methods) coordinate through the main run loop. Tampering /// with the run loop can cause undesireable behavior. /// /// This method will return an AwaitResult in the following cases: /// /// - The main run loop is blocked by other operations and the async expectation cannot be /// be stopped. /// - The async expectation timed out /// - The async expectation succeeded /// - The async expectation raised an unexpected exception (objc) /// - The async expectation raised an unexpected error (swift) /// /// The returned AwaitResult will NEVER be .Incomplete. func wait(fnName: String = __FUNCTION__, file: String = __FILE__, line: UInt = __LINE__) -> AwaitResult { waitLock.acquireWaitingLock( fnName, file: file, line: line) let capture = NMBExceptionCapture(handler: ({ exception in self.promise.resolveResult(.RaisedException(exception)) }), finally: ({ self.waitLock.releaseWaitingLock() })) capture.tryBlock { do { try self.trigger.start() } catch let error { self.promise.resolveResult(.ErrorThrown(error)) } dispatch_resume(self.trigger.timeoutSource) while self.promise.asyncResult.isIncomplete() { // Stopping the run loop does not work unless we run only 1 mode NSRunLoop.currentRunLoop().runMode(NSDefaultRunLoopMode, beforeDate: NSDate.distantFuture()) } dispatch_suspend(self.trigger.timeoutSource) dispatch_source_cancel(self.trigger.timeoutSource) if let asyncSource = self.trigger.actionSource { dispatch_source_cancel(asyncSource) } } return promise.asyncResult } } internal class Awaiter { let waitLock: WaitLock let timeoutQueue: dispatch_queue_t let asyncQueue: dispatch_queue_t internal init( waitLock: WaitLock, asyncQueue: dispatch_queue_t, timeoutQueue: dispatch_queue_t) { self.waitLock = waitLock self.asyncQueue = asyncQueue self.timeoutQueue = timeoutQueue } private func createTimerSource(queue: dispatch_queue_t) -> dispatch_source_t { return dispatch_source_create( DISPATCH_SOURCE_TYPE_TIMER, 0, DISPATCH_TIMER_STRICT, queue ) } func performBlock( closure: ((T) -> Void) throws -> Void) -> AwaitPromiseBuilder { let promise = AwaitPromise() let timeoutSource = createTimerSource(timeoutQueue) var completionCount = 0 let trigger = AwaitTrigger(timeoutSource: timeoutSource, actionSource: nil) { try closure() { completionCount += 1 nimblePrecondition( completionCount < 2, "InvalidNimbleAPIUsage", "Done closure's was called multiple times. waitUntil(..) expects its " + "completion closure to only be called once.") if promise.resolveResult(.Completed($0)) { CFRunLoopStop(CFRunLoopGetMain()) } } } return AwaitPromiseBuilder( awaiter: self, waitLock: waitLock, promise: promise, trigger: trigger) } func poll(pollInterval: NSTimeInterval, closure: () throws -> T?) -> AwaitPromiseBuilder { let promise = AwaitPromise() let timeoutSource = createTimerSource(timeoutQueue) let asyncSource = createTimerSource(asyncQueue) let trigger = AwaitTrigger(timeoutSource: timeoutSource, actionSource: asyncSource) { let interval = UInt64(pollInterval * Double(NSEC_PER_SEC)) dispatch_source_set_timer(asyncSource, DISPATCH_TIME_NOW, interval, pollLeeway) dispatch_source_set_event_handler(asyncSource) { do { if let result = try closure() { if promise.resolveResult(.Completed(result)) { CFRunLoopStop(CFRunLoopGetCurrent()) } } } catch let error { if promise.resolveResult(.ErrorThrown(error)) { CFRunLoopStop(CFRunLoopGetCurrent()) } } } dispatch_resume(asyncSource) } return AwaitPromiseBuilder( awaiter: self, waitLock: waitLock, promise: promise, trigger: trigger) } } internal func pollBlock( pollInterval pollInterval: NSTimeInterval, timeoutInterval: NSTimeInterval, file: String, line: UInt, fnName: String = __FUNCTION__, expression: () throws -> Bool) -> AwaitResult { let awaiter = NimbleEnvironment.activeInstance.awaiter let result = awaiter.poll(pollInterval) { () throws -> Bool? in do { if try expression() { return true } return nil } catch let error { throw error } }.timeout(timeoutInterval, forcefullyAbortTimeout: timeoutInterval / 2.0).wait(fnName, file: file, line: line) return result } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Utils/Functional.swift ================================================ import Foundation internal func all(array: [T], fn: (T) -> Bool) -> Bool { for item in array { if !fn(item) { return false } } return true } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Utils/SourceLocation.swift ================================================ import Foundation public class SourceLocation : NSObject { public let file: String public let line: UInt override init() { file = "Unknown File" line = 0 } init(file: String, line: UInt) { self.file = file self.line = line } override public var description: String { return "\(file):\(line)" } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Utils/Stringers.swift ================================================ import Foundation internal func identityAsString(value: AnyObject?) -> String { if value == nil { return "nil" } return NSString(format: "<%p>", unsafeBitCast(value!, Int.self)).description } internal func arrayAsString(items: [T], joiner: String = ", ") -> String { return items.reduce("") { accum, item in let prefix = (accum.isEmpty ? "" : joiner) return accum + prefix + "\(stringify(item))" } } @objc internal protocol NMBStringer { func NMB_stringify() -> String } internal func stringify(value: S) -> String { var generator = value.generate() var strings = [String]() var value: S.Generator.Element? repeat { value = generator.next() if value != nil { strings.append(stringify(value)) } } while value != nil let str = strings.joinWithSeparator(", ") return "[\(str)]" } extension NSArray : NMBStringer { func NMB_stringify() -> String { let str = self.componentsJoinedByString(", ") return "[\(str)]" } } internal func stringify(value: T) -> String { if let value = value as? Double { return NSString(format: "%.4f", (value)).description } return String(value) } internal func stringify(value: NMBDoubleConvertible) -> String { if let value = value as? Double { return NSString(format: "%.4f", (value)).description } return value.stringRepresentation } internal func stringify(value: T?) -> String { if let unboxed = value { return stringify(unboxed) } return "nil" } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Wrappers/AsyncMatcherWrapper.swift ================================================ import Foundation internal struct AsyncMatcherWrapper: Matcher { let fullMatcher: U let timeoutInterval: NSTimeInterval let pollInterval: NSTimeInterval init(fullMatcher: U, timeoutInterval: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01) { self.fullMatcher = fullMatcher self.timeoutInterval = timeoutInterval self.pollInterval = pollInterval } func matches(actualExpression: Expression, failureMessage: FailureMessage) -> Bool { let uncachedExpression = actualExpression.withoutCaching() let fnName = "expect(...).toEventually(...)" let result = pollBlock( pollInterval: pollInterval, timeoutInterval: timeoutInterval, file: actualExpression.location.file, line: actualExpression.location.line, fnName: fnName) { try self.fullMatcher.matches(uncachedExpression, failureMessage: failureMessage) } switch (result) { case let .Completed(isSuccessful): return isSuccessful case .TimedOut: return false case let .ErrorThrown(error): failureMessage.actualValue = "an unexpected error thrown: <\(error)>" return false case let .RaisedException(exception): failureMessage.actualValue = "an unexpected exception thrown: <\(exception)>" return false case .BlockedRunLoop: failureMessage.postfixMessage += " (timed out, but main thread was unresponsive)." return false case .Incomplete: internalError("Reached .Incomplete state for toEventually(...).") } } func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) -> Bool { let uncachedExpression = actualExpression.withoutCaching() let result = pollBlock( pollInterval: pollInterval, timeoutInterval: timeoutInterval, file: actualExpression.location.file, line: actualExpression.location.line, fnName: "expect(...).toEventuallyNot(...)") { try self.fullMatcher.doesNotMatch(uncachedExpression, failureMessage: failureMessage) } switch (result) { case let .Completed(isSuccessful): return isSuccessful case .TimedOut: return false case let .ErrorThrown(error): failureMessage.actualValue = "an unexpected error thrown: <\(error)>" return false case let .RaisedException(exception): failureMessage.actualValue = "an unexpected exception thrown: <\(exception)>" return false case .BlockedRunLoop: failureMessage.postfixMessage += " (timed out, but main thread was unresponsive)." return false case .Incomplete: internalError("Reached .Incomplete state for toEventuallyNot(...).") } } } private let toEventuallyRequiresClosureError = FailureMessage(stringValue: "expect(...).toEventually(...) requires an explicit closure (eg - expect { ... }.toEventually(...) )\nSwift 1.2 @autoclosure behavior has changed in an incompatible way for Nimble to function") extension Expectation { /// Tests the actual value using a matcher to match by checking continuously /// at each pollInterval until the timeout is reached. /// /// @discussion /// This function manages the main run loop (`NSRunLoop.mainRunLoop()`) while this function /// is executing. Any attempts to touch the run loop may cause non-deterministic behavior. public func toEventually(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01, description: String? = nil) { if expression.isClosure { let (pass, msg) = expressionMatches( expression, matcher: AsyncMatcherWrapper( fullMatcher: matcher, timeoutInterval: timeout, pollInterval: pollInterval), to: "to eventually", description: description ) verify(pass, msg) } else { verify(false, toEventuallyRequiresClosureError) } } /// Tests the actual value using a matcher to not match by checking /// continuously at each pollInterval until the timeout is reached. /// /// @discussion /// This function manages the main run loop (`NSRunLoop.mainRunLoop()`) while this function /// is executing. Any attempts to touch the run loop may cause non-deterministic behavior. public func toEventuallyNot(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01, description: String? = nil) { if expression.isClosure { let (pass, msg) = expressionDoesNotMatch( expression, matcher: AsyncMatcherWrapper( fullMatcher: matcher, timeoutInterval: timeout, pollInterval: pollInterval), toNot: "to eventually not", description: description ) verify(pass, msg) } else { verify(false, toEventuallyRequiresClosureError) } } /// Tests the actual value using a matcher to not match by checking /// continuously at each pollInterval until the timeout is reached. /// /// Alias of toEventuallyNot() /// /// @discussion /// This function manages the main run loop (`NSRunLoop.mainRunLoop()`) while this function /// is executing. Any attempts to touch the run loop may cause non-deterministic behavior. public func toNotEventually(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01, description: String? = nil) { return toEventuallyNot(matcher, timeout: timeout, pollInterval: pollInterval, description: description) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Wrappers/MatcherFunc.swift ================================================ /// A convenience API to build matchers that allow full control over /// to() and toNot() match cases. /// /// The final bool argument in the closure is if the match is for negation. /// /// You may use this when implementing your own custom matchers. /// /// Use the Matcher protocol instead of this type to accept custom matchers as /// input parameters. /// @see allPass for an example that uses accepts other matchers as input. public struct FullMatcherFunc: Matcher { public let matcher: (Expression, FailureMessage, Bool) throws -> Bool public init(_ matcher: (Expression, FailureMessage, Bool) throws -> Bool) { self.matcher = matcher } public func matches(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { return try matcher(actualExpression, failureMessage, false) } public func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { return try matcher(actualExpression, failureMessage, true) } } /// A convenience API to build matchers that don't need special negation /// behavior. The toNot() behavior is the negation of to(). /// /// @see NonNilMatcherFunc if you prefer to have this matcher fail when nil /// values are recieved in an expectation. /// /// You may use this when implementing your own custom matchers. /// /// Use the Matcher protocol instead of this type to accept custom matchers as /// input parameters. /// @see allPass for an example that uses accepts other matchers as input. public struct MatcherFunc: Matcher { public let matcher: (Expression, FailureMessage) throws -> Bool public init(_ matcher: (Expression, FailureMessage) throws -> Bool) { self.matcher = matcher } public func matches(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { return try matcher(actualExpression, failureMessage) } public func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { return try !matcher(actualExpression, failureMessage) } } /// A convenience API to build matchers that don't need special negation /// behavior. The toNot() behavior is the negation of to(). /// /// Unlike MatcherFunc, this will always fail if an expectation contains nil. /// This applies regardless of using to() or toNot(). /// /// You may use this when implementing your own custom matchers. /// /// Use the Matcher protocol instead of this type to accept custom matchers as /// input parameters. /// @see allPass for an example that uses accepts other matchers as input. public struct NonNilMatcherFunc: Matcher { public let matcher: (Expression, FailureMessage) throws -> Bool public init(_ matcher: (Expression, FailureMessage) throws -> Bool) { self.matcher = matcher } public func matches(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { let pass = try matcher(actualExpression, failureMessage) if try attachNilErrorIfNeeded(actualExpression, failureMessage: failureMessage) { return false } return pass } public func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { let pass = try !matcher(actualExpression, failureMessage) if try attachNilErrorIfNeeded(actualExpression, failureMessage: failureMessage) { return false } return pass } internal func attachNilErrorIfNeeded(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { if try actualExpression.evaluate() == nil { failureMessage.postfixActual = " (use beNil() to match nils)" return true } return false } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/Wrappers/ObjCMatcher.swift ================================================ import Foundation public typealias MatcherBlock = (actualExpression: Expression, failureMessage: FailureMessage) -> Bool public typealias FullMatcherBlock = (actualExpression: Expression, failureMessage: FailureMessage, shouldNotMatch: Bool) -> Bool public class NMBObjCMatcher : NSObject, NMBMatcher { let _match: MatcherBlock let _doesNotMatch: MatcherBlock let canMatchNil: Bool public init(canMatchNil: Bool, matcher: MatcherBlock, notMatcher: MatcherBlock) { self.canMatchNil = canMatchNil self._match = matcher self._doesNotMatch = notMatcher } public convenience init(matcher: MatcherBlock) { self.init(canMatchNil: true, matcher: matcher) } public convenience init(canMatchNil: Bool, matcher: MatcherBlock) { self.init(canMatchNil: canMatchNil, matcher: matcher, notMatcher: ({ actualExpression, failureMessage in return !matcher(actualExpression: actualExpression, failureMessage: failureMessage) })) } public convenience init(matcher: FullMatcherBlock) { self.init(canMatchNil: true, matcher: matcher) } public convenience init(canMatchNil: Bool, matcher: FullMatcherBlock) { self.init(canMatchNil: canMatchNil, matcher: ({ actualExpression, failureMessage in return matcher(actualExpression: actualExpression, failureMessage: failureMessage, shouldNotMatch: false) }), notMatcher: ({ actualExpression, failureMessage in return matcher(actualExpression: actualExpression, failureMessage: failureMessage, shouldNotMatch: true) })) } private func canMatch(actualExpression: Expression, failureMessage: FailureMessage) -> Bool { do { if !canMatchNil { if try actualExpression.evaluate() == nil { failureMessage.postfixActual = " (use beNil() to match nils)" return false } } } catch let error { failureMessage.actualValue = "an unexpected error thrown: \(error)" return false } return true } public func matches(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { let expr = Expression(expression: actualBlock, location: location) let result = _match( actualExpression: expr, failureMessage: failureMessage) if self.canMatch(Expression(expression: actualBlock, location: location), failureMessage: failureMessage) { return result } else { return false } } public func doesNotMatch(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { let expr = Expression(expression: actualBlock, location: location) let result = _doesNotMatch( actualExpression: expr, failureMessage: failureMessage) if self.canMatch(Expression(expression: actualBlock, location: location), failureMessage: failureMessage) { return result } else { return false } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/objc/DSL.h ================================================ #import @class NMBExpectation; @class NMBObjCBeCloseToMatcher; @class NMBObjCRaiseExceptionMatcher; @protocol NMBMatcher; #define NIMBLE_EXPORT FOUNDATION_EXPORT #ifdef NIMBLE_DISABLE_SHORT_SYNTAX #define NIMBLE_SHORT(PROTO, ORIGINAL) #else #define NIMBLE_SHORT(PROTO, ORIGINAL) FOUNDATION_STATIC_INLINE PROTO { return (ORIGINAL); } #endif NIMBLE_EXPORT NMBExpectation *NMB_expect(id(^actualBlock)(), NSString *file, NSUInteger line); NIMBLE_EXPORT NMBExpectation *NMB_expectAction(void(^actualBlock)(), NSString *file, NSUInteger line); NIMBLE_EXPORT id NMB_equal(id expectedValue); NIMBLE_SHORT(id equal(id expectedValue), NMB_equal(expectedValue)); NIMBLE_EXPORT id NMB_haveCount(id expectedValue); NIMBLE_SHORT(id haveCount(id expectedValue), NMB_haveCount(expectedValue)); NIMBLE_EXPORT NMBObjCBeCloseToMatcher *NMB_beCloseTo(NSNumber *expectedValue); NIMBLE_SHORT(NMBObjCBeCloseToMatcher *beCloseTo(id expectedValue), NMB_beCloseTo(expectedValue)); NIMBLE_EXPORT id NMB_beAnInstanceOf(Class expectedClass); NIMBLE_SHORT(id beAnInstanceOf(Class expectedClass), NMB_beAnInstanceOf(expectedClass)); NIMBLE_EXPORT id NMB_beAKindOf(Class expectedClass); NIMBLE_SHORT(id beAKindOf(Class expectedClass), NMB_beAKindOf(expectedClass)); NIMBLE_EXPORT id NMB_beginWith(id itemElementOrSubstring); NIMBLE_SHORT(id beginWith(id itemElementOrSubstring), NMB_beginWith(itemElementOrSubstring)); NIMBLE_EXPORT id NMB_beGreaterThan(NSNumber *expectedValue); NIMBLE_SHORT(id beGreaterThan(NSNumber *expectedValue), NMB_beGreaterThan(expectedValue)); NIMBLE_EXPORT id NMB_beGreaterThanOrEqualTo(NSNumber *expectedValue); NIMBLE_SHORT(id beGreaterThanOrEqualTo(NSNumber *expectedValue), NMB_beGreaterThanOrEqualTo(expectedValue)); NIMBLE_EXPORT id NMB_beIdenticalTo(id expectedInstance); NIMBLE_SHORT(id beIdenticalTo(id expectedInstance), NMB_beIdenticalTo(expectedInstance)); NIMBLE_EXPORT id NMB_beLessThan(NSNumber *expectedValue); NIMBLE_SHORT(id beLessThan(NSNumber *expectedValue), NMB_beLessThan(expectedValue)); NIMBLE_EXPORT id NMB_beLessThanOrEqualTo(NSNumber *expectedValue); NIMBLE_SHORT(id beLessThanOrEqualTo(NSNumber *expectedValue), NMB_beLessThanOrEqualTo(expectedValue)); NIMBLE_EXPORT id NMB_beTruthy(void); NIMBLE_SHORT(id beTruthy(void), NMB_beTruthy()); NIMBLE_EXPORT id NMB_beFalsy(void); NIMBLE_SHORT(id beFalsy(void), NMB_beFalsy()); NIMBLE_EXPORT id NMB_beTrue(void); NIMBLE_SHORT(id beTrue(void), NMB_beTrue()); NIMBLE_EXPORT id NMB_beFalse(void); NIMBLE_SHORT(id beFalse(void), NMB_beFalse()); NIMBLE_EXPORT id NMB_beNil(void); NIMBLE_SHORT(id beNil(void), NMB_beNil()); NIMBLE_EXPORT id NMB_beEmpty(void); NIMBLE_SHORT(id beEmpty(void), NMB_beEmpty()); NIMBLE_EXPORT id NMB_containWithNilTermination(id itemOrSubstring, ...) NS_REQUIRES_NIL_TERMINATION; #define NMB_contain(...) NMB_containWithNilTermination(__VA_ARGS__, nil) #ifndef NIMBLE_DISABLE_SHORT_SYNTAX #define contain(...) NMB_contain(__VA_ARGS__) #endif NIMBLE_EXPORT id NMB_endWith(id itemElementOrSubstring); NIMBLE_SHORT(id endWith(id itemElementOrSubstring), NMB_endWith(itemElementOrSubstring)); NIMBLE_EXPORT NMBObjCRaiseExceptionMatcher *NMB_raiseException(void); NIMBLE_SHORT(NMBObjCRaiseExceptionMatcher *raiseException(void), NMB_raiseException()); NIMBLE_EXPORT id NMB_match(id expectedValue); NIMBLE_SHORT(id match(id expectedValue), NMB_match(expectedValue)); NIMBLE_EXPORT id NMB_allPass(id matcher); NIMBLE_SHORT(id allPass(id matcher), NMB_allPass(matcher)); NIMBLE_EXPORT id NMB_satisfyAnyOfWithMatchers(id matchers); #define NMB_satisfyAnyOf(...) NMB_satisfyAnyOfWithMatchers(@[__VA_ARGS__]) #ifndef NIMBLE_DISABLE_SHORT_SYNTAX #define satisfyAnyOf(...) NMB_satisfyAnyOf(__VA_ARGS__) #endif // In order to preserve breakpoint behavior despite using macros to fill in __FILE__ and __LINE__, // define a builder that populates __FILE__ and __LINE__, and returns a block that takes timeout // and action arguments. See https://github.com/Quick/Quick/pull/185 for details. typedef void (^NMBWaitUntilTimeoutBlock)(NSTimeInterval timeout, void (^action)(void (^)(void))); typedef void (^NMBWaitUntilBlock)(void (^action)(void (^)(void))); NIMBLE_EXPORT void NMB_failWithMessage(NSString *msg, NSString *file, NSUInteger line); NIMBLE_EXPORT NMBWaitUntilTimeoutBlock NMB_waitUntilTimeoutBuilder(NSString *file, NSUInteger line); NIMBLE_EXPORT NMBWaitUntilBlock NMB_waitUntilBuilder(NSString *file, NSUInteger line); NIMBLE_EXPORT void NMB_failWithMessage(NSString *msg, NSString *file, NSUInteger line); #define NMB_waitUntilTimeout NMB_waitUntilTimeoutBuilder(@(__FILE__), __LINE__) #define NMB_waitUntil NMB_waitUntilBuilder(@(__FILE__), __LINE__) #ifndef NIMBLE_DISABLE_SHORT_SYNTAX #define expect(...) NMB_expect(^id{ return (__VA_ARGS__); }, @(__FILE__), __LINE__) #define expectAction(BLOCK) NMB_expectAction((BLOCK), @(__FILE__), __LINE__) #define failWithMessage(msg) NMB_failWithMessage(msg, @(__FILE__), __LINE__) #define fail() failWithMessage(@"fail() always fails") #define waitUntilTimeout NMB_waitUntilTimeout #define waitUntil NMB_waitUntil #endif ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/objc/DSL.m ================================================ #import #import SWIFT_CLASS("_TtC6Nimble7NMBWait") @interface NMBWait : NSObject + (void)untilTimeout:(NSTimeInterval)timeout file:(NSString *)file line:(NSUInteger)line action:(void(^)())action; + (void)untilFile:(NSString *)file line:(NSUInteger)line action:(void(^)())action; @end NIMBLE_EXPORT NMBExpectation *NMB_expect(id(^actualBlock)(), NSString *file, NSUInteger line) { return [[NMBExpectation alloc] initWithActualBlock:actualBlock negative:NO file:file line:line]; } NIMBLE_EXPORT NMBExpectation *NMB_expectAction(void(^actualBlock)(), NSString *file, NSUInteger line) { return NMB_expect(^id{ actualBlock(); return nil; }, file, line); } NIMBLE_EXPORT void NMB_failWithMessage(NSString *msg, NSString *file, NSUInteger line) { return [NMBExpectation failWithMessage:msg file:file line:line]; } NIMBLE_EXPORT id NMB_beAnInstanceOf(Class expectedClass) { return [NMBObjCMatcher beAnInstanceOfMatcher:expectedClass]; } NIMBLE_EXPORT id NMB_beAKindOf(Class expectedClass) { return [NMBObjCMatcher beAKindOfMatcher:expectedClass]; } NIMBLE_EXPORT NMBObjCBeCloseToMatcher *NMB_beCloseTo(NSNumber *expectedValue) { return [NMBObjCMatcher beCloseToMatcher:expectedValue within:0.001]; } NIMBLE_EXPORT id NMB_beginWith(id itemElementOrSubstring) { return [NMBObjCMatcher beginWithMatcher:itemElementOrSubstring]; } NIMBLE_EXPORT id NMB_beGreaterThan(NSNumber *expectedValue) { return [NMBObjCMatcher beGreaterThanMatcher:expectedValue]; } NIMBLE_EXPORT id NMB_beGreaterThanOrEqualTo(NSNumber *expectedValue) { return [NMBObjCMatcher beGreaterThanOrEqualToMatcher:expectedValue]; } NIMBLE_EXPORT id NMB_beIdenticalTo(id expectedInstance) { return [NMBObjCMatcher beIdenticalToMatcher:expectedInstance]; } NIMBLE_EXPORT id NMB_beLessThan(NSNumber *expectedValue) { return [NMBObjCMatcher beLessThanMatcher:expectedValue]; } NIMBLE_EXPORT id NMB_beLessThanOrEqualTo(NSNumber *expectedValue) { return [NMBObjCMatcher beLessThanOrEqualToMatcher:expectedValue]; } NIMBLE_EXPORT id NMB_beTruthy() { return [NMBObjCMatcher beTruthyMatcher]; } NIMBLE_EXPORT id NMB_beFalsy() { return [NMBObjCMatcher beFalsyMatcher]; } NIMBLE_EXPORT id NMB_beTrue() { return [NMBObjCMatcher beTrueMatcher]; } NIMBLE_EXPORT id NMB_beFalse() { return [NMBObjCMatcher beFalseMatcher]; } NIMBLE_EXPORT id NMB_beNil() { return [NMBObjCMatcher beNilMatcher]; } NIMBLE_EXPORT id NMB_beEmpty() { return [NMBObjCMatcher beEmptyMatcher]; } NIMBLE_EXPORT id NMB_containWithNilTermination(id itemOrSubstring, ...) { NSMutableArray *itemOrSubstringArray = [NSMutableArray array]; if (itemOrSubstring) { [itemOrSubstringArray addObject:itemOrSubstring]; va_list args; va_start(args, itemOrSubstring); id next; while ((next = va_arg(args, id))) { [itemOrSubstringArray addObject:next]; } va_end(args); } return [NMBObjCMatcher containMatcher:itemOrSubstringArray]; } NIMBLE_EXPORT id NMB_endWith(id itemElementOrSubstring) { return [NMBObjCMatcher endWithMatcher:itemElementOrSubstring]; } NIMBLE_EXPORT id NMB_equal(id expectedValue) { return [NMBObjCMatcher equalMatcher:expectedValue]; } NIMBLE_EXPORT id NMB_haveCount(id expectedValue) { return [NMBObjCMatcher haveCountMatcher:expectedValue]; } NIMBLE_EXPORT id NMB_match(id expectedValue) { return [NMBObjCMatcher matchMatcher:expectedValue]; } NIMBLE_EXPORT id NMB_allPass(id expectedValue) { return [NMBObjCMatcher allPassMatcher:expectedValue]; } NIMBLE_EXPORT id NMB_satisfyAnyOfWithMatchers(id matchers) { return [NMBObjCMatcher satisfyAnyOfMatcher:matchers]; } NIMBLE_EXPORT NMBObjCRaiseExceptionMatcher *NMB_raiseException() { return [NMBObjCMatcher raiseExceptionMatcher]; } NIMBLE_EXPORT NMBWaitUntilTimeoutBlock NMB_waitUntilTimeoutBuilder(NSString *file, NSUInteger line) { return ^(NSTimeInterval timeout, void (^action)(void (^)(void))) { [NMBWait untilTimeout:timeout file:file line:line action:action]; }; } NIMBLE_EXPORT NMBWaitUntilBlock NMB_waitUntilBuilder(NSString *file, NSUInteger line) { return ^(void (^action)(void (^)(void))) { [NMBWait untilFile:file line:line action:action]; }; } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/objc/NMBExceptionCapture.h ================================================ #import #import @interface NMBExceptionCapture : NSObject - (id)initWithHandler:(void(^)(NSException *))handler finally:(void(^)())finally; - (void)tryBlock:(void(^)())unsafeBlock; @end typedef void(^NMBSourceCallbackBlock)(BOOL successful); ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble/objc/NMBExceptionCapture.m ================================================ #import "NMBExceptionCapture.h" @interface NMBExceptionCapture () @property (nonatomic, copy) void(^handler)(NSException *exception); @property (nonatomic, copy) void(^finally)(); @end @implementation NMBExceptionCapture - (id)initWithHandler:(void(^)(NSException *))handler finally:(void(^)())finally { self = [super init]; if (self) { self.handler = handler; self.finally = finally; } return self; } - (void)tryBlock:(void(^)())unsafeBlock { @try { unsafeBlock(); } @catch (NSException *exception) { if (self.handler) { self.handler(exception); } } @finally { if (self.finally) { self.finally(); } } } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble.podspec ================================================ Pod::Spec.new do |s| s.name = "Nimble" s.version = "3.1.0" s.summary = "A Matcher Framework for Swift and Objective-C" s.description = <<-DESC Use Nimble to express the expected outcomes of Swift or Objective-C expressions. Inspired by Cedar. DESC s.homepage = "https://github.com/Quick/Nimble" s.license = { :type => "Apache 2.0", :file => "LICENSE.md" } s.author = "Quick Contributors" s.ios.deployment_target = "7.0" s.osx.deployment_target = "10.9" s.tvos.deployment_target = "9.0" s.source = { :git => "https://github.com/Quick/Nimble.git", :tag => "v#{s.version}" } s.source_files = "Nimble", "Nimble/**/*.{swift,h,m}" s.weak_framework = "XCTest" s.requires_arc = true s.pod_target_xcconfig = { 'ENABLE_BITCODE' => 'NO', 'OTHER_LDFLAGS' => '-weak-lswiftXCTest', 'FRAMEWORK_SEARCH_PATHS' => '$(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks"' } end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 1F0648CC19639F5A001F9C46 /* ObjectWithLazyProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0648CB19639F5A001F9C46 /* ObjectWithLazyProperty.swift */; }; 1F0648CD19639F5A001F9C46 /* ObjectWithLazyProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0648CB19639F5A001F9C46 /* ObjectWithLazyProperty.swift */; }; 1F0648D41963AAB2001F9C46 /* SynchronousTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0648D31963AAB2001F9C46 /* SynchronousTests.swift */; }; 1F0648D51963AAB2001F9C46 /* SynchronousTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0648D31963AAB2001F9C46 /* SynchronousTests.swift */; }; 1F0FEA9A1AF32DA4001E554E /* ObjCExpectation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0FEA991AF32DA4001E554E /* ObjCExpectation.swift */; }; 1F0FEA9B1AF32DA4001E554E /* ObjCExpectation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0FEA991AF32DA4001E554E /* ObjCExpectation.swift */; }; 1F14FB64194180C5009F2A08 /* utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F14FB63194180C5009F2A08 /* utils.swift */; }; 1F1A742F1940169200FFFC47 /* Nimble.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F1A742E1940169200FFFC47 /* Nimble.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F1A74351940169200FFFC47 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F1A74291940169200FFFC47 /* Nimble.framework */; }; 1F1B5AD41963E13900CA8BF9 /* BeAKindOfTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F1B5AD31963E13900CA8BF9 /* BeAKindOfTest.swift */; }; 1F1B5AD51963E13900CA8BF9 /* BeAKindOfTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F1B5AD31963E13900CA8BF9 /* BeAKindOfTest.swift */; }; 1F299EAB19627B2D002641AF /* BeEmptyTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F299EAA19627B2D002641AF /* BeEmptyTest.swift */; }; 1F299EAC19627B2D002641AF /* BeEmptyTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F299EAA19627B2D002641AF /* BeEmptyTest.swift */; }; 1F43728A1A1B343800EB80F8 /* Functional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD251968AB07008ED995 /* Functional.swift */; }; 1F43728B1A1B343900EB80F8 /* Functional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD251968AB07008ED995 /* Functional.swift */; }; 1F43728C1A1B343C00EB80F8 /* SourceLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD271968AB07008ED995 /* SourceLocation.swift */; }; 1F43728D1A1B343D00EB80F8 /* SourceLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD271968AB07008ED995 /* SourceLocation.swift */; }; 1F43728E1A1B343F00EB80F8 /* Stringers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD281968AB07008ED995 /* Stringers.swift */; }; 1F43728F1A1B344000EB80F8 /* Stringers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD281968AB07008ED995 /* Stringers.swift */; }; 1F4A56661A3B305F009E1637 /* ObjCAsyncTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56651A3B305F009E1637 /* ObjCAsyncTest.m */; }; 1F4A56671A3B305F009E1637 /* ObjCAsyncTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56651A3B305F009E1637 /* ObjCAsyncTest.m */; }; 1F4A566A1A3B3108009E1637 /* ObjCBeAnInstanceOfTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56691A3B3108009E1637 /* ObjCBeAnInstanceOfTest.m */; }; 1F4A566B1A3B3108009E1637 /* ObjCBeAnInstanceOfTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56691A3B3108009E1637 /* ObjCBeAnInstanceOfTest.m */; }; 1F4A566D1A3B3159009E1637 /* ObjCBeKindOfTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A566C1A3B3159009E1637 /* ObjCBeKindOfTest.m */; }; 1F4A566E1A3B3159009E1637 /* ObjCBeKindOfTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A566C1A3B3159009E1637 /* ObjCBeKindOfTest.m */; }; 1F4A56701A3B319F009E1637 /* ObjCBeCloseToTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A566F1A3B319F009E1637 /* ObjCBeCloseToTest.m */; }; 1F4A56711A3B319F009E1637 /* ObjCBeCloseToTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A566F1A3B319F009E1637 /* ObjCBeCloseToTest.m */; }; 1F4A56731A3B3210009E1637 /* ObjCBeginWithTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56721A3B3210009E1637 /* ObjCBeginWithTest.m */; }; 1F4A56741A3B3210009E1637 /* ObjCBeginWithTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56721A3B3210009E1637 /* ObjCBeginWithTest.m */; }; 1F4A56761A3B3253009E1637 /* ObjCBeGreaterThanTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56751A3B3253009E1637 /* ObjCBeGreaterThanTest.m */; }; 1F4A56771A3B3253009E1637 /* ObjCBeGreaterThanTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56751A3B3253009E1637 /* ObjCBeGreaterThanTest.m */; }; 1F4A56791A3B32E3009E1637 /* ObjCBeGreaterThanOrEqualToTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56781A3B32E3009E1637 /* ObjCBeGreaterThanOrEqualToTest.m */; }; 1F4A567A1A3B32E3009E1637 /* ObjCBeGreaterThanOrEqualToTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56781A3B32E3009E1637 /* ObjCBeGreaterThanOrEqualToTest.m */; }; 1F4A567C1A3B3311009E1637 /* ObjCBeIdenticalToTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A567B1A3B3311009E1637 /* ObjCBeIdenticalToTest.m */; }; 1F4A567D1A3B3311009E1637 /* ObjCBeIdenticalToTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A567B1A3B3311009E1637 /* ObjCBeIdenticalToTest.m */; }; 1F4A567F1A3B333F009E1637 /* ObjCBeLessThanTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A567E1A3B333F009E1637 /* ObjCBeLessThanTest.m */; }; 1F4A56801A3B333F009E1637 /* ObjCBeLessThanTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A567E1A3B333F009E1637 /* ObjCBeLessThanTest.m */; }; 1F4A56821A3B336F009E1637 /* ObjCBeLessThanOrEqualToTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56811A3B336F009E1637 /* ObjCBeLessThanOrEqualToTest.m */; }; 1F4A56831A3B336F009E1637 /* ObjCBeLessThanOrEqualToTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56811A3B336F009E1637 /* ObjCBeLessThanOrEqualToTest.m */; }; 1F4A56851A3B33A0009E1637 /* ObjCBeTruthyTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56841A3B33A0009E1637 /* ObjCBeTruthyTest.m */; }; 1F4A56861A3B33A0009E1637 /* ObjCBeTruthyTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56841A3B33A0009E1637 /* ObjCBeTruthyTest.m */; }; 1F4A56881A3B33CB009E1637 /* ObjCBeFalsyTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56871A3B33CB009E1637 /* ObjCBeFalsyTest.m */; }; 1F4A56891A3B33CB009E1637 /* ObjCBeFalsyTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56871A3B33CB009E1637 /* ObjCBeFalsyTest.m */; }; 1F4A568B1A3B3407009E1637 /* ObjCBeTrueTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A568A1A3B3407009E1637 /* ObjCBeTrueTest.m */; }; 1F4A568C1A3B3407009E1637 /* ObjCBeTrueTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A568A1A3B3407009E1637 /* ObjCBeTrueTest.m */; }; 1F4A568E1A3B342B009E1637 /* ObjCBeFalseTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A568D1A3B342B009E1637 /* ObjCBeFalseTest.m */; }; 1F4A568F1A3B342B009E1637 /* ObjCBeFalseTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A568D1A3B342B009E1637 /* ObjCBeFalseTest.m */; }; 1F4A56911A3B344A009E1637 /* ObjCBeNilTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56901A3B344A009E1637 /* ObjCBeNilTest.m */; }; 1F4A56921A3B344A009E1637 /* ObjCBeNilTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56901A3B344A009E1637 /* ObjCBeNilTest.m */; }; 1F4A56941A3B346F009E1637 /* ObjCContainTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56931A3B346F009E1637 /* ObjCContainTest.m */; }; 1F4A56951A3B346F009E1637 /* ObjCContainTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56931A3B346F009E1637 /* ObjCContainTest.m */; }; 1F4A56971A3B34AA009E1637 /* ObjCEndWithTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56961A3B34AA009E1637 /* ObjCEndWithTest.m */; }; 1F4A56981A3B34AA009E1637 /* ObjCEndWithTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56961A3B34AA009E1637 /* ObjCEndWithTest.m */; }; 1F4A569A1A3B3539009E1637 /* ObjCEqualTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56991A3B3539009E1637 /* ObjCEqualTest.m */; }; 1F4A569B1A3B3539009E1637 /* ObjCEqualTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56991A3B3539009E1637 /* ObjCEqualTest.m */; }; 1F4A569D1A3B3565009E1637 /* ObjCMatchTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A569C1A3B3565009E1637 /* ObjCMatchTest.m */; }; 1F4A569E1A3B3565009E1637 /* ObjCMatchTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A569C1A3B3565009E1637 /* ObjCMatchTest.m */; }; 1F4A56A01A3B359E009E1637 /* ObjCRaiseExceptionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A569F1A3B359E009E1637 /* ObjCRaiseExceptionTest.m */; }; 1F4A56A11A3B359E009E1637 /* ObjCRaiseExceptionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A569F1A3B359E009E1637 /* ObjCRaiseExceptionTest.m */; }; 1F5DF15F1BDCA0CE00C3A531 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F5DF1551BDCA0CE00C3A531 /* Nimble.framework */; }; 1F5DF16C1BDCA0F500C3A531 /* AssertionRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD051968AB07008ED995 /* AssertionRecorder.swift */; }; 1F5DF16D1BDCA0F500C3A531 /* AdapterProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD061968AB07008ED995 /* AdapterProtocols.swift */; }; 1F5DF16E1BDCA0F500C3A531 /* NimbleXCTestHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD071968AB07008ED995 /* NimbleXCTestHandler.swift */; }; 1F5DF16F1BDCA0F500C3A531 /* AssertionDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FDBD8661AF8A4FF0089F27B /* AssertionDispatcher.swift */; }; 1F5DF1701BDCA0F500C3A531 /* DSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD081968AB07008ED995 /* DSL.swift */; }; 1F5DF1711BDCA0F500C3A531 /* DSL+Wait.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9E8C811A414BB9002633C2 /* DSL+Wait.swift */; }; 1F5DF1721BDCA0F500C3A531 /* Expectation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD091968AB07008ED995 /* Expectation.swift */; }; 1F5DF1731BDCA0F500C3A531 /* ObjCExpectation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0FEA991AF32DA4001E554E /* ObjCExpectation.swift */; }; 1F5DF1741BDCA0F500C3A531 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0A1968AB07008ED995 /* Expression.swift */; }; 1F5DF1751BDCA0F500C3A531 /* FailureMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0B1968AB07008ED995 /* FailureMessage.swift */; }; 1F5DF1761BDCA0F500C3A531 /* AllPass.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB1BC781A92235600F743C3 /* AllPass.swift */; }; 1F5DF1771BDCA0F500C3A531 /* BeAKindOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0E1968AB07008ED995 /* BeAKindOf.swift */; }; 1F5DF1781BDCA0F500C3A531 /* BeAnInstanceOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0D1968AB07008ED995 /* BeAnInstanceOf.swift */; }; 1F5DF1791BDCA0F500C3A531 /* BeCloseTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0F1968AB07008ED995 /* BeCloseTo.swift */; }; 1F5DF17A1BDCA0F500C3A531 /* BeEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD101968AB07008ED995 /* BeEmpty.swift */; }; 1F5DF17B1BDCA0F500C3A531 /* BeginWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD111968AB07008ED995 /* BeginWith.swift */; }; 1F5DF17C1BDCA0F500C3A531 /* BeGreaterThan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD121968AB07008ED995 /* BeGreaterThan.swift */; }; 1F5DF17D1BDCA0F500C3A531 /* BeGreaterThanOrEqualTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD131968AB07008ED995 /* BeGreaterThanOrEqualTo.swift */; }; 1F5DF17E1BDCA0F500C3A531 /* BeIdenticalTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD141968AB07008ED995 /* BeIdenticalTo.swift */; }; 1F5DF17F1BDCA0F500C3A531 /* BeLessThan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD151968AB07008ED995 /* BeLessThan.swift */; }; 1F5DF1801BDCA0F500C3A531 /* BeLessThanOrEqual.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD161968AB07008ED995 /* BeLessThanOrEqual.swift */; }; 1F5DF1811BDCA0F500C3A531 /* BeLogical.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD171968AB07008ED995 /* BeLogical.swift */; }; 1F5DF1821BDCA0F500C3A531 /* BeNil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD181968AB07008ED995 /* BeNil.swift */; }; 1F5DF1831BDCA0F500C3A531 /* Contain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1A1968AB07008ED995 /* Contain.swift */; }; 1F5DF1841BDCA0F500C3A531 /* EndWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1B1968AB07008ED995 /* EndWith.swift */; }; 1F5DF1851BDCA0F500C3A531 /* Equal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1C1968AB07008ED995 /* Equal.swift */; }; 1F5DF1861BDCA0F500C3A531 /* HaveCount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472FD1341B9E085700C7B8DA /* HaveCount.swift */; }; 1F5DF1871BDCA0F500C3A531 /* Match.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB4D5EC19FE43C200E9D9FE /* Match.swift */; }; 1F5DF1881BDCA0F500C3A531 /* MatcherProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1D1968AB07008ED995 /* MatcherProtocols.swift */; }; 1F5DF1891BDCA0F500C3A531 /* RaisesException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1E1968AB07008ED995 /* RaisesException.swift */; }; 1F5DF18A1BDCA0F500C3A531 /* ThrowError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29EA59651B551EE6002D767E /* ThrowError.swift */; }; 1F5DF18B1BDCA0F500C3A531 /* Functional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD251968AB07008ED995 /* Functional.swift */; }; 1F5DF18C1BDCA0F500C3A531 /* Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD261968AB07008ED995 /* Async.swift */; }; 1F5DF18D1BDCA0F500C3A531 /* SourceLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD271968AB07008ED995 /* SourceLocation.swift */; }; 1F5DF18E1BDCA0F500C3A531 /* Stringers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD281968AB07008ED995 /* Stringers.swift */; }; 1F5DF18F1BDCA0F500C3A531 /* AsyncMatcherWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2A1968AB07008ED995 /* AsyncMatcherWrapper.swift */; }; 1F5DF1901BDCA0F500C3A531 /* MatcherFunc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2C1968AB07008ED995 /* MatcherFunc.swift */; }; 1F5DF1911BDCA0F500C3A531 /* ObjCMatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2D1968AB07008ED995 /* ObjCMatcher.swift */; }; 1F5DF1921BDCA10200C3A531 /* AsynchronousTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EE5195C121200ED456B /* AsynchronousTest.swift */; }; 1F5DF1931BDCA10200C3A531 /* SynchronousTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0648D31963AAB2001F9C46 /* SynchronousTests.swift */; }; 1F5DF1941BDCA10200C3A531 /* UserDescriptionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 965B0D0B1B62C06D0005AE66 /* UserDescriptionTest.swift */; }; 1F5DF1951BDCA10200C3A531 /* utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F14FB63194180C5009F2A08 /* utils.swift */; }; 1F5DF1961BDCA10200C3A531 /* ObjectWithLazyProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0648CB19639F5A001F9C46 /* ObjectWithLazyProperty.swift */; }; 1F5DF1971BDCA10200C3A531 /* AllPassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD72EC631A93874A002F7651 /* AllPassTest.swift */; }; 1F5DF1981BDCA10200C3A531 /* BeAKindOfTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F1B5AD31963E13900CA8BF9 /* BeAKindOfTest.swift */; }; 1F5DF1991BDCA10200C3A531 /* BeAnInstanceOfTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EE8195C124400ED456B /* BeAnInstanceOfTest.swift */; }; 1F5DF19A1BDCA10200C3A531 /* BeCloseToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EF5195C147800ED456B /* BeCloseToTest.swift */; }; 1F5DF19B1BDCA10200C3A531 /* BeEmptyTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F299EAA19627B2D002641AF /* BeEmptyTest.swift */; }; 1F5DF19C1BDCA10200C3A531 /* BeginWithTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EFB195C186800ED456B /* BeginWithTest.swift */; }; 1F5DF19D1BDCA10200C3A531 /* BeGreaterThanOrEqualToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F10195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift */; }; 1F5DF19E1BDCA10200C3A531 /* BeGreaterThanTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F07195C18CF00ED456B /* BeGreaterThanTest.swift */; }; 1F5DF19F1BDCA10200C3A531 /* BeIdenticalToObjectTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD9A9A8D19CF413800706F49 /* BeIdenticalToObjectTest.swift */; }; 1F5DF1A01BDCA10200C3A531 /* BeIdenticalToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FB90097195EC4B8001D7FAE /* BeIdenticalToTest.swift */; }; 1F5DF1A11BDCA10200C3A531 /* BeLessThanOrEqualToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F0D195C18F500ED456B /* BeLessThanOrEqualToTest.swift */; }; 1F5DF1A21BDCA10200C3A531 /* BeLessThanTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F0A195C18E100ED456B /* BeLessThanTest.swift */; }; 1F5DF1A31BDCA10200C3A531 /* BeLogicalTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EEE195C136500ED456B /* BeLogicalTest.swift */; }; 1F5DF1A41BDCA10200C3A531 /* BeNilTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EF8195C175000ED456B /* BeNilTest.swift */; }; 1F5DF1A51BDCA10200C3A531 /* ContainTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F01195C189500ED456B /* ContainTest.swift */; }; 1F5DF1A61BDCA10200C3A531 /* EndWithTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EFE195C187600ED456B /* EndWithTest.swift */; }; 1F5DF1A71BDCA10200C3A531 /* EqualTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F04195C18B700ED456B /* EqualTest.swift */; }; 1F5DF1A81BDCA10200C3A531 /* HaveCountTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472FD1361B9E094B00C7B8DA /* HaveCountTest.swift */; }; 1F5DF1A91BDCA10200C3A531 /* MatchTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB4D5EF19FE442800E9D9FE /* MatchTest.swift */; }; 1F5DF1AA1BDCA10200C3A531 /* RaisesExceptionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EEB195C12C800ED456B /* RaisesExceptionTest.swift */; }; 1F5DF1AB1BDCA10200C3A531 /* ThrowErrorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29EA59621B551ED2002D767E /* ThrowErrorTest.swift */; }; 1F5DF1AC1BDCA16E00C3A531 /* DSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD211968AB07008ED995 /* DSL.m */; }; 1F5DF1AD1BDCA16E00C3A531 /* NMBExceptionCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD231968AB07008ED995 /* NMBExceptionCapture.m */; }; 1F5DF1AE1BDCA17600C3A531 /* Nimble.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F1A742E1940169200FFFC47 /* Nimble.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F5DF1AF1BDCA17600C3A531 /* DSL.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FD8CD201968AB07008ED995 /* DSL.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F5DF1B01BDCA17600C3A531 /* NMBExceptionCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FD8CD221968AB07008ED995 /* NMBExceptionCapture.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F8A37B01B7C5042001C8357 /* ObjCSyncTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F8A37AF1B7C5042001C8357 /* ObjCSyncTest.m */; }; 1F8A37B11B7C5042001C8357 /* ObjCSyncTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F8A37AF1B7C5042001C8357 /* ObjCSyncTest.m */; }; 1F925EB8195C0D6300ED456B /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F925EAD195C0D6300ED456B /* Nimble.framework */; }; 1F925EC7195C0DD100ED456B /* Nimble.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F1A742E1940169200FFFC47 /* Nimble.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F925EE2195C0DFD00ED456B /* utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F14FB63194180C5009F2A08 /* utils.swift */; }; 1F925EE6195C121200ED456B /* AsynchronousTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EE5195C121200ED456B /* AsynchronousTest.swift */; }; 1F925EE7195C121200ED456B /* AsynchronousTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EE5195C121200ED456B /* AsynchronousTest.swift */; }; 1F925EE9195C124400ED456B /* BeAnInstanceOfTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EE8195C124400ED456B /* BeAnInstanceOfTest.swift */; }; 1F925EEA195C124400ED456B /* BeAnInstanceOfTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EE8195C124400ED456B /* BeAnInstanceOfTest.swift */; }; 1F925EEC195C12C800ED456B /* RaisesExceptionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EEB195C12C800ED456B /* RaisesExceptionTest.swift */; }; 1F925EED195C12C800ED456B /* RaisesExceptionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EEB195C12C800ED456B /* RaisesExceptionTest.swift */; }; 1F925EEF195C136500ED456B /* BeLogicalTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EEE195C136500ED456B /* BeLogicalTest.swift */; }; 1F925EF0195C136500ED456B /* BeLogicalTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EEE195C136500ED456B /* BeLogicalTest.swift */; }; 1F925EF6195C147800ED456B /* BeCloseToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EF5195C147800ED456B /* BeCloseToTest.swift */; }; 1F925EF7195C147800ED456B /* BeCloseToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EF5195C147800ED456B /* BeCloseToTest.swift */; }; 1F925EF9195C175000ED456B /* BeNilTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EF8195C175000ED456B /* BeNilTest.swift */; }; 1F925EFA195C175000ED456B /* BeNilTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EF8195C175000ED456B /* BeNilTest.swift */; }; 1F925EFC195C186800ED456B /* BeginWithTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EFB195C186800ED456B /* BeginWithTest.swift */; }; 1F925EFD195C186800ED456B /* BeginWithTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EFB195C186800ED456B /* BeginWithTest.swift */; }; 1F925EFF195C187600ED456B /* EndWithTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EFE195C187600ED456B /* EndWithTest.swift */; }; 1F925F00195C187600ED456B /* EndWithTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EFE195C187600ED456B /* EndWithTest.swift */; }; 1F925F02195C189500ED456B /* ContainTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F01195C189500ED456B /* ContainTest.swift */; }; 1F925F03195C189500ED456B /* ContainTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F01195C189500ED456B /* ContainTest.swift */; }; 1F925F05195C18B700ED456B /* EqualTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F04195C18B700ED456B /* EqualTest.swift */; }; 1F925F06195C18B700ED456B /* EqualTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F04195C18B700ED456B /* EqualTest.swift */; }; 1F925F08195C18CF00ED456B /* BeGreaterThanTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F07195C18CF00ED456B /* BeGreaterThanTest.swift */; }; 1F925F09195C18CF00ED456B /* BeGreaterThanTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F07195C18CF00ED456B /* BeGreaterThanTest.swift */; }; 1F925F0B195C18E100ED456B /* BeLessThanTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F0A195C18E100ED456B /* BeLessThanTest.swift */; }; 1F925F0C195C18E100ED456B /* BeLessThanTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F0A195C18E100ED456B /* BeLessThanTest.swift */; }; 1F925F0E195C18F500ED456B /* BeLessThanOrEqualToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F0D195C18F500ED456B /* BeLessThanOrEqualToTest.swift */; }; 1F925F0F195C18F500ED456B /* BeLessThanOrEqualToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F0D195C18F500ED456B /* BeLessThanOrEqualToTest.swift */; }; 1F925F11195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F10195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift */; }; 1F925F12195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F10195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift */; }; 1F9DB8FB1A74E793002E96AD /* ObjCBeEmptyTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F9DB8FA1A74E793002E96AD /* ObjCBeEmptyTest.m */; }; 1F9DB8FC1A74E793002E96AD /* ObjCBeEmptyTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F9DB8FA1A74E793002E96AD /* ObjCBeEmptyTest.m */; }; 1FB90098195EC4B8001D7FAE /* BeIdenticalToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FB90097195EC4B8001D7FAE /* BeIdenticalToTest.swift */; }; 1FB90099195EC4B8001D7FAE /* BeIdenticalToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FB90097195EC4B8001D7FAE /* BeIdenticalToTest.swift */; }; 1FC494AA1C29CBA40010975C /* NimbleEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FC494A91C29CBA40010975C /* NimbleEnvironment.swift */; }; 1FC494AB1C29CBA40010975C /* NimbleEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FC494A91C29CBA40010975C /* NimbleEnvironment.swift */; }; 1FC494AC1C29CBA40010975C /* NimbleEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FC494A91C29CBA40010975C /* NimbleEnvironment.swift */; }; 1FD8CD2E1968AB07008ED995 /* AssertionRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD051968AB07008ED995 /* AssertionRecorder.swift */; }; 1FD8CD2F1968AB07008ED995 /* AssertionRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD051968AB07008ED995 /* AssertionRecorder.swift */; }; 1FD8CD301968AB07008ED995 /* AdapterProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD061968AB07008ED995 /* AdapterProtocols.swift */; }; 1FD8CD311968AB07008ED995 /* AdapterProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD061968AB07008ED995 /* AdapterProtocols.swift */; }; 1FD8CD321968AB07008ED995 /* NimbleXCTestHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD071968AB07008ED995 /* NimbleXCTestHandler.swift */; }; 1FD8CD331968AB07008ED995 /* NimbleXCTestHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD071968AB07008ED995 /* NimbleXCTestHandler.swift */; }; 1FD8CD341968AB07008ED995 /* DSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD081968AB07008ED995 /* DSL.swift */; }; 1FD8CD351968AB07008ED995 /* DSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD081968AB07008ED995 /* DSL.swift */; }; 1FD8CD361968AB07008ED995 /* Expectation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD091968AB07008ED995 /* Expectation.swift */; }; 1FD8CD371968AB07008ED995 /* Expectation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD091968AB07008ED995 /* Expectation.swift */; }; 1FD8CD381968AB07008ED995 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0A1968AB07008ED995 /* Expression.swift */; }; 1FD8CD391968AB07008ED995 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0A1968AB07008ED995 /* Expression.swift */; }; 1FD8CD3A1968AB07008ED995 /* FailureMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0B1968AB07008ED995 /* FailureMessage.swift */; }; 1FD8CD3B1968AB07008ED995 /* FailureMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0B1968AB07008ED995 /* FailureMessage.swift */; }; 1FD8CD3C1968AB07008ED995 /* BeAnInstanceOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0D1968AB07008ED995 /* BeAnInstanceOf.swift */; }; 1FD8CD3D1968AB07008ED995 /* BeAnInstanceOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0D1968AB07008ED995 /* BeAnInstanceOf.swift */; }; 1FD8CD3E1968AB07008ED995 /* BeAKindOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0E1968AB07008ED995 /* BeAKindOf.swift */; }; 1FD8CD3F1968AB07008ED995 /* BeAKindOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0E1968AB07008ED995 /* BeAKindOf.swift */; }; 1FD8CD401968AB07008ED995 /* BeCloseTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0F1968AB07008ED995 /* BeCloseTo.swift */; }; 1FD8CD411968AB07008ED995 /* BeCloseTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0F1968AB07008ED995 /* BeCloseTo.swift */; }; 1FD8CD421968AB07008ED995 /* BeEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD101968AB07008ED995 /* BeEmpty.swift */; }; 1FD8CD431968AB07008ED995 /* BeEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD101968AB07008ED995 /* BeEmpty.swift */; }; 1FD8CD441968AB07008ED995 /* BeginWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD111968AB07008ED995 /* BeginWith.swift */; }; 1FD8CD451968AB07008ED995 /* BeginWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD111968AB07008ED995 /* BeginWith.swift */; }; 1FD8CD461968AB07008ED995 /* BeGreaterThan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD121968AB07008ED995 /* BeGreaterThan.swift */; }; 1FD8CD471968AB07008ED995 /* BeGreaterThan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD121968AB07008ED995 /* BeGreaterThan.swift */; }; 1FD8CD481968AB07008ED995 /* BeGreaterThanOrEqualTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD131968AB07008ED995 /* BeGreaterThanOrEqualTo.swift */; }; 1FD8CD491968AB07008ED995 /* BeGreaterThanOrEqualTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD131968AB07008ED995 /* BeGreaterThanOrEqualTo.swift */; }; 1FD8CD4A1968AB07008ED995 /* BeIdenticalTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD141968AB07008ED995 /* BeIdenticalTo.swift */; }; 1FD8CD4B1968AB07008ED995 /* BeIdenticalTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD141968AB07008ED995 /* BeIdenticalTo.swift */; }; 1FD8CD4C1968AB07008ED995 /* BeLessThan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD151968AB07008ED995 /* BeLessThan.swift */; }; 1FD8CD4D1968AB07008ED995 /* BeLessThan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD151968AB07008ED995 /* BeLessThan.swift */; }; 1FD8CD4E1968AB07008ED995 /* BeLessThanOrEqual.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD161968AB07008ED995 /* BeLessThanOrEqual.swift */; }; 1FD8CD4F1968AB07008ED995 /* BeLessThanOrEqual.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD161968AB07008ED995 /* BeLessThanOrEqual.swift */; }; 1FD8CD501968AB07008ED995 /* BeLogical.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD171968AB07008ED995 /* BeLogical.swift */; }; 1FD8CD511968AB07008ED995 /* BeLogical.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD171968AB07008ED995 /* BeLogical.swift */; }; 1FD8CD521968AB07008ED995 /* BeNil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD181968AB07008ED995 /* BeNil.swift */; }; 1FD8CD531968AB07008ED995 /* BeNil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD181968AB07008ED995 /* BeNil.swift */; }; 1FD8CD561968AB07008ED995 /* Contain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1A1968AB07008ED995 /* Contain.swift */; }; 1FD8CD571968AB07008ED995 /* Contain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1A1968AB07008ED995 /* Contain.swift */; }; 1FD8CD581968AB07008ED995 /* EndWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1B1968AB07008ED995 /* EndWith.swift */; }; 1FD8CD591968AB07008ED995 /* EndWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1B1968AB07008ED995 /* EndWith.swift */; }; 1FD8CD5A1968AB07008ED995 /* Equal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1C1968AB07008ED995 /* Equal.swift */; }; 1FD8CD5B1968AB07008ED995 /* Equal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1C1968AB07008ED995 /* Equal.swift */; }; 1FD8CD5C1968AB07008ED995 /* MatcherProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1D1968AB07008ED995 /* MatcherProtocols.swift */; }; 1FD8CD5D1968AB07008ED995 /* MatcherProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1D1968AB07008ED995 /* MatcherProtocols.swift */; }; 1FD8CD5E1968AB07008ED995 /* RaisesException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1E1968AB07008ED995 /* RaisesException.swift */; }; 1FD8CD5F1968AB07008ED995 /* RaisesException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1E1968AB07008ED995 /* RaisesException.swift */; }; 1FD8CD601968AB07008ED995 /* DSL.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FD8CD201968AB07008ED995 /* DSL.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1FD8CD611968AB07008ED995 /* DSL.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FD8CD201968AB07008ED995 /* DSL.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1FD8CD621968AB07008ED995 /* DSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD211968AB07008ED995 /* DSL.m */; }; 1FD8CD631968AB07008ED995 /* DSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD211968AB07008ED995 /* DSL.m */; }; 1FD8CD641968AB07008ED995 /* NMBExceptionCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FD8CD221968AB07008ED995 /* NMBExceptionCapture.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1FD8CD651968AB07008ED995 /* NMBExceptionCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FD8CD221968AB07008ED995 /* NMBExceptionCapture.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1FD8CD661968AB07008ED995 /* NMBExceptionCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD231968AB07008ED995 /* NMBExceptionCapture.m */; }; 1FD8CD671968AB07008ED995 /* NMBExceptionCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD231968AB07008ED995 /* NMBExceptionCapture.m */; }; 1FD8CD6A1968AB07008ED995 /* Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD261968AB07008ED995 /* Async.swift */; }; 1FD8CD6B1968AB07008ED995 /* Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD261968AB07008ED995 /* Async.swift */; }; 1FD8CD701968AB07008ED995 /* AsyncMatcherWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2A1968AB07008ED995 /* AsyncMatcherWrapper.swift */; }; 1FD8CD711968AB07008ED995 /* AsyncMatcherWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2A1968AB07008ED995 /* AsyncMatcherWrapper.swift */; }; 1FD8CD741968AB07008ED995 /* MatcherFunc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2C1968AB07008ED995 /* MatcherFunc.swift */; }; 1FD8CD751968AB07008ED995 /* MatcherFunc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2C1968AB07008ED995 /* MatcherFunc.swift */; }; 1FD8CD761968AB07008ED995 /* ObjCMatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2D1968AB07008ED995 /* ObjCMatcher.swift */; }; 1FD8CD771968AB07008ED995 /* ObjCMatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2D1968AB07008ED995 /* ObjCMatcher.swift */; }; 1FDBD8671AF8A4FF0089F27B /* AssertionDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FDBD8661AF8A4FF0089F27B /* AssertionDispatcher.swift */; }; 1FDBD8681AF8A4FF0089F27B /* AssertionDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FDBD8661AF8A4FF0089F27B /* AssertionDispatcher.swift */; }; 29EA59631B551ED2002D767E /* ThrowErrorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29EA59621B551ED2002D767E /* ThrowErrorTest.swift */; }; 29EA59641B551ED2002D767E /* ThrowErrorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29EA59621B551ED2002D767E /* ThrowErrorTest.swift */; }; 29EA59661B551EE6002D767E /* ThrowError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29EA59651B551EE6002D767E /* ThrowError.swift */; }; 29EA59671B551EE6002D767E /* ThrowError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29EA59651B551EE6002D767E /* ThrowError.swift */; }; 472FD1351B9E085700C7B8DA /* HaveCount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472FD1341B9E085700C7B8DA /* HaveCount.swift */; }; 472FD1391B9E0A9700C7B8DA /* HaveCount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472FD1341B9E085700C7B8DA /* HaveCount.swift */; }; 472FD13A1B9E0A9F00C7B8DA /* HaveCountTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472FD1361B9E094B00C7B8DA /* HaveCountTest.swift */; }; 472FD13B1B9E0CFE00C7B8DA /* HaveCountTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472FD1361B9E094B00C7B8DA /* HaveCountTest.swift */; }; 4793854D1BA0BB2500296F85 /* ObjCHaveCount.m in Sources */ = {isa = PBXBuildFile; fileRef = 4793854C1BA0BB2500296F85 /* ObjCHaveCount.m */; }; 4793854E1BA0BB2500296F85 /* ObjCHaveCount.m in Sources */ = {isa = PBXBuildFile; fileRef = 4793854C1BA0BB2500296F85 /* ObjCHaveCount.m */; }; 7B5358BA1C3846C900A23FAA /* SatisfyAnyOfTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B5358B91C3846C900A23FAA /* SatisfyAnyOfTest.swift */; }; 7B5358BB1C3846C900A23FAA /* SatisfyAnyOfTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B5358B91C3846C900A23FAA /* SatisfyAnyOfTest.swift */; }; 7B5358BC1C3846C900A23FAA /* SatisfyAnyOfTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B5358B91C3846C900A23FAA /* SatisfyAnyOfTest.swift */; }; 7B5358BE1C38479700A23FAA /* SatisfyAnyOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B5358BD1C38479700A23FAA /* SatisfyAnyOf.swift */; }; 7B5358BF1C38479700A23FAA /* SatisfyAnyOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B5358BD1C38479700A23FAA /* SatisfyAnyOf.swift */; }; 7B5358C01C38479700A23FAA /* SatisfyAnyOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B5358BD1C38479700A23FAA /* SatisfyAnyOf.swift */; }; 7B5358C51C39184200A23FAA /* ObjCSatisfyAnyOfTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B5358C11C39155600A23FAA /* ObjCSatisfyAnyOfTest.m */; }; 7B5358C61C39184200A23FAA /* ObjCSatisfyAnyOfTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7B5358C11C39155600A23FAA /* ObjCSatisfyAnyOfTest.m */; }; 965B0D091B62B8ED0005AE66 /* ObjCUserDescriptionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 965B0D081B62B8ED0005AE66 /* ObjCUserDescriptionTest.m */; }; 965B0D0A1B62B8ED0005AE66 /* ObjCUserDescriptionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 965B0D081B62B8ED0005AE66 /* ObjCUserDescriptionTest.m */; }; 965B0D0C1B62C06D0005AE66 /* UserDescriptionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 965B0D0B1B62C06D0005AE66 /* UserDescriptionTest.swift */; }; 965B0D0D1B62C06D0005AE66 /* UserDescriptionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 965B0D0B1B62C06D0005AE66 /* UserDescriptionTest.swift */; }; DA9E8C821A414BB9002633C2 /* DSL+Wait.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9E8C811A414BB9002633C2 /* DSL+Wait.swift */; }; DA9E8C831A414BB9002633C2 /* DSL+Wait.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9E8C811A414BB9002633C2 /* DSL+Wait.swift */; }; DD72EC641A93874A002F7651 /* AllPassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD72EC631A93874A002F7651 /* AllPassTest.swift */; }; DD72EC651A93874A002F7651 /* AllPassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD72EC631A93874A002F7651 /* AllPassTest.swift */; }; DD9A9A8F19CF439B00706F49 /* BeIdenticalToObjectTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD9A9A8D19CF413800706F49 /* BeIdenticalToObjectTest.swift */; }; DD9A9A9019CF43AD00706F49 /* BeIdenticalToObjectTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD9A9A8D19CF413800706F49 /* BeIdenticalToObjectTest.swift */; }; DDB1BC791A92235600F743C3 /* AllPass.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB1BC781A92235600F743C3 /* AllPass.swift */; }; DDB1BC7A1A92235600F743C3 /* AllPass.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB1BC781A92235600F743C3 /* AllPass.swift */; }; DDB4D5ED19FE43C200E9D9FE /* Match.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB4D5EC19FE43C200E9D9FE /* Match.swift */; }; DDB4D5EE19FE43C200E9D9FE /* Match.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB4D5EC19FE43C200E9D9FE /* Match.swift */; }; DDB4D5F019FE442800E9D9FE /* MatchTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB4D5EF19FE442800E9D9FE /* MatchTest.swift */; }; DDB4D5F119FE442800E9D9FE /* MatchTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB4D5EF19FE442800E9D9FE /* MatchTest.swift */; }; DDEFAEB41A93CBE6005CA37A /* ObjCAllPassTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DDEFAEB31A93CBE6005CA37A /* ObjCAllPassTest.m */; }; DDEFAEB51A93CBE6005CA37A /* ObjCAllPassTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DDEFAEB31A93CBE6005CA37A /* ObjCAllPassTest.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 1F1A74361940169200FFFC47 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F1A74281940169200FFFC47; remoteInfo = "Nimble-iOS"; }; 1F5DF1601BDCA0CE00C3A531 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F5DF1541BDCA0CE00C3A531; remoteInfo = "Nimble-tvOS"; }; 1F6BB82A1968BFF9009F1DBB /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F1A74281940169200FFFC47; remoteInfo = "Nimble-iOS"; }; 1F925EA4195C0C8500ED456B /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F1A74281940169200FFFC47; remoteInfo = Nimble; }; 1F925EA6195C0C8500ED456B /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F1A74281940169200FFFC47; remoteInfo = Nimble; }; 1F925EB9195C0D6300ED456B /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F925EAC195C0D6300ED456B; remoteInfo = "Nimble-OSX"; }; 1F9B7BFD1968AD760094EB8F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F925EAC195C0D6300ED456B; remoteInfo = "Nimble-OSX"; }; 1F9B7BFF1968AD760094EB8F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F925EAC195C0D6300ED456B; remoteInfo = "Nimble-OSX"; }; 1F9B7C011968AD820094EB8F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F925EAC195C0D6300ED456B; remoteInfo = "Nimble-OSX"; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 1F0648CB19639F5A001F9C46 /* ObjectWithLazyProperty.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectWithLazyProperty.swift; sourceTree = ""; }; 1F0648D31963AAB2001F9C46 /* SynchronousTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronousTests.swift; sourceTree = ""; }; 1F0FEA991AF32DA4001E554E /* ObjCExpectation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjCExpectation.swift; sourceTree = ""; }; 1F14FB63194180C5009F2A08 /* utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = utils.swift; sourceTree = ""; }; 1F1A74291940169200FFFC47 /* Nimble.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Nimble.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1F1A742D1940169200FFFC47 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 1F1A742E1940169200FFFC47 /* Nimble.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Nimble.h; sourceTree = ""; }; 1F1A74341940169200FFFC47 /* NimbleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NimbleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 1F1A743A1940169200FFFC47 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 1F1B5AD31963E13900CA8BF9 /* BeAKindOfTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeAKindOfTest.swift; sourceTree = ""; }; 1F2752D119445B8400052A26 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; lineEnding = 0; path = README.md; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.markdown; }; 1F299EAA19627B2D002641AF /* BeEmptyTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeEmptyTest.swift; sourceTree = ""; }; 1F4A56651A3B305F009E1637 /* ObjCAsyncTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCAsyncTest.m; sourceTree = ""; }; 1F4A56681A3B3074009E1637 /* NimbleSpecHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NimbleSpecHelper.h; sourceTree = ""; }; 1F4A56691A3B3108009E1637 /* ObjCBeAnInstanceOfTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeAnInstanceOfTest.m; sourceTree = ""; }; 1F4A566C1A3B3159009E1637 /* ObjCBeKindOfTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeKindOfTest.m; sourceTree = ""; }; 1F4A566F1A3B319F009E1637 /* ObjCBeCloseToTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeCloseToTest.m; sourceTree = ""; }; 1F4A56721A3B3210009E1637 /* ObjCBeginWithTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeginWithTest.m; sourceTree = ""; }; 1F4A56751A3B3253009E1637 /* ObjCBeGreaterThanTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeGreaterThanTest.m; sourceTree = ""; }; 1F4A56781A3B32E3009E1637 /* ObjCBeGreaterThanOrEqualToTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeGreaterThanOrEqualToTest.m; sourceTree = ""; }; 1F4A567B1A3B3311009E1637 /* ObjCBeIdenticalToTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeIdenticalToTest.m; sourceTree = ""; }; 1F4A567E1A3B333F009E1637 /* ObjCBeLessThanTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeLessThanTest.m; sourceTree = ""; }; 1F4A56811A3B336F009E1637 /* ObjCBeLessThanOrEqualToTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeLessThanOrEqualToTest.m; sourceTree = ""; }; 1F4A56841A3B33A0009E1637 /* ObjCBeTruthyTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeTruthyTest.m; sourceTree = ""; }; 1F4A56871A3B33CB009E1637 /* ObjCBeFalsyTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeFalsyTest.m; sourceTree = ""; }; 1F4A568A1A3B3407009E1637 /* ObjCBeTrueTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeTrueTest.m; sourceTree = ""; }; 1F4A568D1A3B342B009E1637 /* ObjCBeFalseTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeFalseTest.m; sourceTree = ""; }; 1F4A56901A3B344A009E1637 /* ObjCBeNilTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeNilTest.m; sourceTree = ""; }; 1F4A56931A3B346F009E1637 /* ObjCContainTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCContainTest.m; sourceTree = ""; }; 1F4A56961A3B34AA009E1637 /* ObjCEndWithTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCEndWithTest.m; sourceTree = ""; }; 1F4A56991A3B3539009E1637 /* ObjCEqualTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCEqualTest.m; sourceTree = ""; }; 1F4A569C1A3B3565009E1637 /* ObjCMatchTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCMatchTest.m; sourceTree = ""; }; 1F4A569F1A3B359E009E1637 /* ObjCRaiseExceptionTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCRaiseExceptionTest.m; sourceTree = ""; }; 1F5DF1551BDCA0CE00C3A531 /* Nimble.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Nimble.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1F5DF15E1BDCA0CE00C3A531 /* NimbleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NimbleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 1F8A37AF1B7C5042001C8357 /* ObjCSyncTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCSyncTest.m; sourceTree = ""; }; 1F925EAD195C0D6300ED456B /* Nimble.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Nimble.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1F925EB7195C0D6300ED456B /* NimbleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NimbleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 1F925EE5195C121200ED456B /* AsynchronousTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsynchronousTest.swift; sourceTree = ""; }; 1F925EE8195C124400ED456B /* BeAnInstanceOfTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeAnInstanceOfTest.swift; sourceTree = ""; }; 1F925EEB195C12C800ED456B /* RaisesExceptionTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RaisesExceptionTest.swift; sourceTree = ""; }; 1F925EEE195C136500ED456B /* BeLogicalTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeLogicalTest.swift; sourceTree = ""; }; 1F925EF5195C147800ED456B /* BeCloseToTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeCloseToTest.swift; sourceTree = ""; }; 1F925EF8195C175000ED456B /* BeNilTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeNilTest.swift; sourceTree = ""; }; 1F925EFB195C186800ED456B /* BeginWithTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeginWithTest.swift; sourceTree = ""; }; 1F925EFE195C187600ED456B /* EndWithTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EndWithTest.swift; sourceTree = ""; }; 1F925F01195C189500ED456B /* ContainTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContainTest.swift; sourceTree = ""; }; 1F925F04195C18B700ED456B /* EqualTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EqualTest.swift; sourceTree = ""; }; 1F925F07195C18CF00ED456B /* BeGreaterThanTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeGreaterThanTest.swift; sourceTree = ""; }; 1F925F0A195C18E100ED456B /* BeLessThanTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeLessThanTest.swift; sourceTree = ""; }; 1F925F0D195C18F500ED456B /* BeLessThanOrEqualToTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeLessThanOrEqualToTest.swift; sourceTree = ""; }; 1F925F10195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeGreaterThanOrEqualToTest.swift; sourceTree = ""; }; 1F9DB8FA1A74E793002E96AD /* ObjCBeEmptyTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeEmptyTest.m; sourceTree = ""; }; 1FB90097195EC4B8001D7FAE /* BeIdenticalToTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeIdenticalToTest.swift; sourceTree = ""; }; 1FC494A91C29CBA40010975C /* NimbleEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NimbleEnvironment.swift; sourceTree = ""; }; 1FD8CD051968AB07008ED995 /* AssertionRecorder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssertionRecorder.swift; sourceTree = ""; }; 1FD8CD061968AB07008ED995 /* AdapterProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdapterProtocols.swift; sourceTree = ""; }; 1FD8CD071968AB07008ED995 /* NimbleXCTestHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NimbleXCTestHandler.swift; sourceTree = ""; }; 1FD8CD081968AB07008ED995 /* DSL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DSL.swift; sourceTree = ""; }; 1FD8CD091968AB07008ED995 /* Expectation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Expectation.swift; sourceTree = ""; }; 1FD8CD0A1968AB07008ED995 /* Expression.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Expression.swift; sourceTree = ""; }; 1FD8CD0B1968AB07008ED995 /* FailureMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FailureMessage.swift; sourceTree = ""; }; 1FD8CD0D1968AB07008ED995 /* BeAnInstanceOf.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeAnInstanceOf.swift; sourceTree = ""; }; 1FD8CD0E1968AB07008ED995 /* BeAKindOf.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeAKindOf.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD0F1968AB07008ED995 /* BeCloseTo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeCloseTo.swift; sourceTree = ""; }; 1FD8CD101968AB07008ED995 /* BeEmpty.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeEmpty.swift; sourceTree = ""; }; 1FD8CD111968AB07008ED995 /* BeginWith.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeginWith.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD121968AB07008ED995 /* BeGreaterThan.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeGreaterThan.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD131968AB07008ED995 /* BeGreaterThanOrEqualTo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeGreaterThanOrEqualTo.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD141968AB07008ED995 /* BeIdenticalTo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeIdenticalTo.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD151968AB07008ED995 /* BeLessThan.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeLessThan.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD161968AB07008ED995 /* BeLessThanOrEqual.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeLessThanOrEqual.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD171968AB07008ED995 /* BeLogical.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeLogical.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD181968AB07008ED995 /* BeNil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeNil.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD1A1968AB07008ED995 /* Contain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Contain.swift; sourceTree = ""; }; 1FD8CD1B1968AB07008ED995 /* EndWith.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EndWith.swift; sourceTree = ""; }; 1FD8CD1C1968AB07008ED995 /* Equal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Equal.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD1D1968AB07008ED995 /* MatcherProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MatcherProtocols.swift; sourceTree = ""; }; 1FD8CD1E1968AB07008ED995 /* RaisesException.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = RaisesException.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD201968AB07008ED995 /* DSL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DSL.h; sourceTree = ""; }; 1FD8CD211968AB07008ED995 /* DSL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DSL.m; sourceTree = ""; }; 1FD8CD221968AB07008ED995 /* NMBExceptionCapture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NMBExceptionCapture.h; sourceTree = ""; }; 1FD8CD231968AB07008ED995 /* NMBExceptionCapture.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NMBExceptionCapture.m; sourceTree = ""; }; 1FD8CD251968AB07008ED995 /* Functional.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Functional.swift; sourceTree = ""; }; 1FD8CD261968AB07008ED995 /* Async.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Async.swift; sourceTree = ""; }; 1FD8CD271968AB07008ED995 /* SourceLocation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SourceLocation.swift; sourceTree = ""; }; 1FD8CD281968AB07008ED995 /* Stringers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Stringers.swift; sourceTree = ""; }; 1FD8CD2A1968AB07008ED995 /* AsyncMatcherWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsyncMatcherWrapper.swift; sourceTree = ""; }; 1FD8CD2C1968AB07008ED995 /* MatcherFunc.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MatcherFunc.swift; sourceTree = ""; }; 1FD8CD2D1968AB07008ED995 /* ObjCMatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjCMatcher.swift; sourceTree = ""; }; 1FDBD8661AF8A4FF0089F27B /* AssertionDispatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssertionDispatcher.swift; sourceTree = ""; }; 1FFD729B1963FCAB00CD29A2 /* NimbleTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NimbleTests-Bridging-Header.h"; sourceTree = ""; }; 1FFD729C1963FCAB00CD29A2 /* Nimble-OSXTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Nimble-OSXTests-Bridging-Header.h"; sourceTree = ""; }; 29EA59621B551ED2002D767E /* ThrowErrorTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThrowErrorTest.swift; sourceTree = ""; }; 29EA59651B551EE6002D767E /* ThrowError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThrowError.swift; sourceTree = ""; }; 472FD1341B9E085700C7B8DA /* HaveCount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HaveCount.swift; sourceTree = ""; }; 472FD1361B9E094B00C7B8DA /* HaveCountTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HaveCountTest.swift; sourceTree = ""; }; 4793854C1BA0BB2500296F85 /* ObjCHaveCount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCHaveCount.m; sourceTree = ""; }; 7B5358B91C3846C900A23FAA /* SatisfyAnyOfTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SatisfyAnyOfTest.swift; sourceTree = ""; }; 7B5358BD1C38479700A23FAA /* SatisfyAnyOf.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SatisfyAnyOf.swift; sourceTree = ""; }; 7B5358C11C39155600A23FAA /* ObjCSatisfyAnyOfTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCSatisfyAnyOfTest.m; sourceTree = ""; }; 965B0D081B62B8ED0005AE66 /* ObjCUserDescriptionTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCUserDescriptionTest.m; sourceTree = ""; }; 965B0D0B1B62C06D0005AE66 /* UserDescriptionTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDescriptionTest.swift; sourceTree = ""; }; DA9E8C811A414BB9002633C2 /* DSL+Wait.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DSL+Wait.swift"; sourceTree = ""; }; DD72EC631A93874A002F7651 /* AllPassTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AllPassTest.swift; sourceTree = ""; }; DD9A9A8D19CF413800706F49 /* BeIdenticalToObjectTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeIdenticalToObjectTest.swift; sourceTree = ""; }; DDB1BC781A92235600F743C3 /* AllPass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AllPass.swift; sourceTree = ""; }; DDB4D5EC19FE43C200E9D9FE /* Match.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Match.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; DDB4D5EF19FE442800E9D9FE /* MatchTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MatchTest.swift; sourceTree = ""; }; DDEFAEB31A93CBE6005CA37A /* ObjCAllPassTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCAllPassTest.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 1F1A74251940169200FFFC47 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F1A74311940169200FFFC47 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 1F1A74351940169200FFFC47 /* Nimble.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F5DF1511BDCA0CE00C3A531 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F5DF15B1BDCA0CE00C3A531 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 1F5DF15F1BDCA0CE00C3A531 /* Nimble.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F925EA9195C0D6300ED456B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F925EB4195C0D6300ED456B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 1F925EB8195C0D6300ED456B /* Nimble.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 1F14FB61194180A7009F2A08 /* Helpers */ = { isa = PBXGroup; children = ( 1F14FB63194180C5009F2A08 /* utils.swift */, 1F0648CB19639F5A001F9C46 /* ObjectWithLazyProperty.swift */, ); path = Helpers; sourceTree = ""; }; 1F1A741F1940169200FFFC47 = { isa = PBXGroup; children = ( 1F2752D119445B8400052A26 /* README.md */, 1F1A742B1940169200FFFC47 /* Nimble */, 1F1A74381940169200FFFC47 /* NimbleTests */, 1F1A742A1940169200FFFC47 /* Products */, ); sourceTree = ""; }; 1F1A742A1940169200FFFC47 /* Products */ = { isa = PBXGroup; children = ( 1F1A74291940169200FFFC47 /* Nimble.framework */, 1F1A74341940169200FFFC47 /* NimbleTests.xctest */, 1F925EAD195C0D6300ED456B /* Nimble.framework */, 1F925EB7195C0D6300ED456B /* NimbleTests.xctest */, 1F5DF1551BDCA0CE00C3A531 /* Nimble.framework */, 1F5DF15E1BDCA0CE00C3A531 /* NimbleTests.xctest */, ); name = Products; sourceTree = ""; }; 1F1A742B1940169200FFFC47 /* Nimble */ = { isa = PBXGroup; children = ( 1FD8CD041968AB07008ED995 /* Adapters */, 1FD8CD081968AB07008ED995 /* DSL.swift */, DA9E8C811A414BB9002633C2 /* DSL+Wait.swift */, 1FD8CD091968AB07008ED995 /* Expectation.swift */, 1F0FEA991AF32DA4001E554E /* ObjCExpectation.swift */, 1FD8CD0A1968AB07008ED995 /* Expression.swift */, 1FD8CD0B1968AB07008ED995 /* FailureMessage.swift */, 1FD8CD0C1968AB07008ED995 /* Matchers */, 1F1A742E1940169200FFFC47 /* Nimble.h */, 1FD8CD1F1968AB07008ED995 /* objc */, 1F1A742C1940169200FFFC47 /* Supporting Files */, 1FD8CD241968AB07008ED995 /* Utils */, 1FD8CD291968AB07008ED995 /* Wrappers */, ); path = Nimble; sourceTree = ""; }; 1F1A742C1940169200FFFC47 /* Supporting Files */ = { isa = PBXGroup; children = ( 1F1A742D1940169200FFFC47 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; 1F1A74381940169200FFFC47 /* NimbleTests */ = { isa = PBXGroup; children = ( 1F925EE5195C121200ED456B /* AsynchronousTest.swift */, 1F0648D31963AAB2001F9C46 /* SynchronousTests.swift */, 965B0D0B1B62C06D0005AE66 /* UserDescriptionTest.swift */, 1FFD729A1963FC8200CD29A2 /* objc */, 1F14FB61194180A7009F2A08 /* Helpers */, 1F925EE3195C11B000ED456B /* Matchers */, 1F1A74391940169200FFFC47 /* Supporting Files */, ); path = NimbleTests; sourceTree = ""; }; 1F1A74391940169200FFFC47 /* Supporting Files */ = { isa = PBXGroup; children = ( 1F1A743A1940169200FFFC47 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; 1F925EE3195C11B000ED456B /* Matchers */ = { isa = PBXGroup; children = ( DD72EC631A93874A002F7651 /* AllPassTest.swift */, 1F1B5AD31963E13900CA8BF9 /* BeAKindOfTest.swift */, 1F925EE8195C124400ED456B /* BeAnInstanceOfTest.swift */, 1F925EF5195C147800ED456B /* BeCloseToTest.swift */, 1F299EAA19627B2D002641AF /* BeEmptyTest.swift */, 1F925EFB195C186800ED456B /* BeginWithTest.swift */, 1F925F10195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift */, 1F925F07195C18CF00ED456B /* BeGreaterThanTest.swift */, DD9A9A8D19CF413800706F49 /* BeIdenticalToObjectTest.swift */, 1FB90097195EC4B8001D7FAE /* BeIdenticalToTest.swift */, 1F925F0D195C18F500ED456B /* BeLessThanOrEqualToTest.swift */, 1F925F0A195C18E100ED456B /* BeLessThanTest.swift */, 1F925EEE195C136500ED456B /* BeLogicalTest.swift */, 1F925EF8195C175000ED456B /* BeNilTest.swift */, 1F925F01195C189500ED456B /* ContainTest.swift */, 1F925EFE195C187600ED456B /* EndWithTest.swift */, 1F925F04195C18B700ED456B /* EqualTest.swift */, 472FD1361B9E094B00C7B8DA /* HaveCountTest.swift */, DDB4D5EF19FE442800E9D9FE /* MatchTest.swift */, 1F925EEB195C12C800ED456B /* RaisesExceptionTest.swift */, 29EA59621B551ED2002D767E /* ThrowErrorTest.swift */, 7B5358B91C3846C900A23FAA /* SatisfyAnyOfTest.swift */, ); path = Matchers; sourceTree = ""; }; 1FD8CD041968AB07008ED995 /* Adapters */ = { isa = PBXGroup; children = ( 1FD8CD051968AB07008ED995 /* AssertionRecorder.swift */, 1FD8CD061968AB07008ED995 /* AdapterProtocols.swift */, 1FD8CD071968AB07008ED995 /* NimbleXCTestHandler.swift */, 1FDBD8661AF8A4FF0089F27B /* AssertionDispatcher.swift */, 1FC494A91C29CBA40010975C /* NimbleEnvironment.swift */, ); path = Adapters; sourceTree = ""; }; 1FD8CD0C1968AB07008ED995 /* Matchers */ = { isa = PBXGroup; children = ( DDB1BC781A92235600F743C3 /* AllPass.swift */, 1FD8CD0E1968AB07008ED995 /* BeAKindOf.swift */, 1FD8CD0D1968AB07008ED995 /* BeAnInstanceOf.swift */, 1FD8CD0F1968AB07008ED995 /* BeCloseTo.swift */, 1FD8CD101968AB07008ED995 /* BeEmpty.swift */, 1FD8CD111968AB07008ED995 /* BeginWith.swift */, 1FD8CD121968AB07008ED995 /* BeGreaterThan.swift */, 1FD8CD131968AB07008ED995 /* BeGreaterThanOrEqualTo.swift */, 1FD8CD141968AB07008ED995 /* BeIdenticalTo.swift */, 1FD8CD151968AB07008ED995 /* BeLessThan.swift */, 1FD8CD161968AB07008ED995 /* BeLessThanOrEqual.swift */, 1FD8CD171968AB07008ED995 /* BeLogical.swift */, 1FD8CD181968AB07008ED995 /* BeNil.swift */, 1FD8CD1A1968AB07008ED995 /* Contain.swift */, 1FD8CD1B1968AB07008ED995 /* EndWith.swift */, 1FD8CD1C1968AB07008ED995 /* Equal.swift */, 472FD1341B9E085700C7B8DA /* HaveCount.swift */, DDB4D5EC19FE43C200E9D9FE /* Match.swift */, 1FD8CD1D1968AB07008ED995 /* MatcherProtocols.swift */, 1FD8CD1E1968AB07008ED995 /* RaisesException.swift */, 29EA59651B551EE6002D767E /* ThrowError.swift */, 7B5358BD1C38479700A23FAA /* SatisfyAnyOf.swift */, ); path = Matchers; sourceTree = ""; }; 1FD8CD1F1968AB07008ED995 /* objc */ = { isa = PBXGroup; children = ( 1FD8CD201968AB07008ED995 /* DSL.h */, 1FD8CD211968AB07008ED995 /* DSL.m */, 1FD8CD221968AB07008ED995 /* NMBExceptionCapture.h */, 1FD8CD231968AB07008ED995 /* NMBExceptionCapture.m */, ); path = objc; sourceTree = ""; }; 1FD8CD241968AB07008ED995 /* Utils */ = { isa = PBXGroup; children = ( 1FD8CD251968AB07008ED995 /* Functional.swift */, 1FD8CD261968AB07008ED995 /* Async.swift */, 1FD8CD271968AB07008ED995 /* SourceLocation.swift */, 1FD8CD281968AB07008ED995 /* Stringers.swift */, ); path = Utils; sourceTree = ""; }; 1FD8CD291968AB07008ED995 /* Wrappers */ = { isa = PBXGroup; children = ( 1FD8CD2A1968AB07008ED995 /* AsyncMatcherWrapper.swift */, 1FD8CD2C1968AB07008ED995 /* MatcherFunc.swift */, 1FD8CD2D1968AB07008ED995 /* ObjCMatcher.swift */, ); path = Wrappers; sourceTree = ""; }; 1FFD729A1963FC8200CD29A2 /* objc */ = { isa = PBXGroup; children = ( 1FFD729C1963FCAB00CD29A2 /* Nimble-OSXTests-Bridging-Header.h */, 1F4A56681A3B3074009E1637 /* NimbleSpecHelper.h */, 1FFD729B1963FCAB00CD29A2 /* NimbleTests-Bridging-Header.h */, 1F4A56651A3B305F009E1637 /* ObjCAsyncTest.m */, 1F8A37AF1B7C5042001C8357 /* ObjCSyncTest.m */, 1F4A56691A3B3108009E1637 /* ObjCBeAnInstanceOfTest.m */, 1F4A566F1A3B319F009E1637 /* ObjCBeCloseToTest.m */, 1F9DB8FA1A74E793002E96AD /* ObjCBeEmptyTest.m */, 1F4A568D1A3B342B009E1637 /* ObjCBeFalseTest.m */, 1F4A56871A3B33CB009E1637 /* ObjCBeFalsyTest.m */, 1F4A56721A3B3210009E1637 /* ObjCBeginWithTest.m */, 1F4A56781A3B32E3009E1637 /* ObjCBeGreaterThanOrEqualToTest.m */, 1F4A56751A3B3253009E1637 /* ObjCBeGreaterThanTest.m */, 1F4A567B1A3B3311009E1637 /* ObjCBeIdenticalToTest.m */, 1F4A566C1A3B3159009E1637 /* ObjCBeKindOfTest.m */, 1F4A56811A3B336F009E1637 /* ObjCBeLessThanOrEqualToTest.m */, 1F4A567E1A3B333F009E1637 /* ObjCBeLessThanTest.m */, 1F4A56901A3B344A009E1637 /* ObjCBeNilTest.m */, 1F4A568A1A3B3407009E1637 /* ObjCBeTrueTest.m */, 1F4A56841A3B33A0009E1637 /* ObjCBeTruthyTest.m */, 1F4A56931A3B346F009E1637 /* ObjCContainTest.m */, 1F4A56961A3B34AA009E1637 /* ObjCEndWithTest.m */, 1F4A56991A3B3539009E1637 /* ObjCEqualTest.m */, 4793854C1BA0BB2500296F85 /* ObjCHaveCount.m */, 1F4A569C1A3B3565009E1637 /* ObjCMatchTest.m */, 1F4A569F1A3B359E009E1637 /* ObjCRaiseExceptionTest.m */, 965B0D081B62B8ED0005AE66 /* ObjCUserDescriptionTest.m */, DDEFAEB31A93CBE6005CA37A /* ObjCAllPassTest.m */, 7B5358C11C39155600A23FAA /* ObjCSatisfyAnyOfTest.m */, ); path = objc; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 1F1A74261940169200FFFC47 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 1FD8CD601968AB07008ED995 /* DSL.h in Headers */, 1FD8CD641968AB07008ED995 /* NMBExceptionCapture.h in Headers */, 1F1A742F1940169200FFFC47 /* Nimble.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F5DF1521BDCA0CE00C3A531 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 1F5DF1AF1BDCA17600C3A531 /* DSL.h in Headers */, 1F5DF1B01BDCA17600C3A531 /* NMBExceptionCapture.h in Headers */, 1F5DF1AE1BDCA17600C3A531 /* Nimble.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F925EAA195C0D6300ED456B /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 1FD8CD611968AB07008ED995 /* DSL.h in Headers */, 1FD8CD651968AB07008ED995 /* NMBExceptionCapture.h in Headers */, 1F925EC7195C0DD100ED456B /* Nimble.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 1F1A74281940169200FFFC47 /* Nimble-iOS */ = { isa = PBXNativeTarget; buildConfigurationList = 1F1A743F1940169200FFFC47 /* Build configuration list for PBXNativeTarget "Nimble-iOS" */; buildPhases = ( 1F1A74241940169200FFFC47 /* Sources */, 1F1A74251940169200FFFC47 /* Frameworks */, 1F1A74261940169200FFFC47 /* Headers */, 1F1A74271940169200FFFC47 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Nimble-iOS"; productName = "Nimble-iOS"; productReference = 1F1A74291940169200FFFC47 /* Nimble.framework */; productType = "com.apple.product-type.framework"; }; 1F1A74331940169200FFFC47 /* Nimble-iOSTests */ = { isa = PBXNativeTarget; buildConfigurationList = 1F1A74421940169200FFFC47 /* Build configuration list for PBXNativeTarget "Nimble-iOSTests" */; buildPhases = ( 1F1A74301940169200FFFC47 /* Sources */, 1F1A74311940169200FFFC47 /* Frameworks */, 1F1A74321940169200FFFC47 /* Resources */, ); buildRules = ( ); dependencies = ( 1F1A74371940169200FFFC47 /* PBXTargetDependency */, 1F925EA5195C0C8500ED456B /* PBXTargetDependency */, 1F925EA7195C0C8500ED456B /* PBXTargetDependency */, 1F6BB82B1968BFF9009F1DBB /* PBXTargetDependency */, ); name = "Nimble-iOSTests"; productName = "Nimble-iOSTests"; productReference = 1F1A74341940169200FFFC47 /* NimbleTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 1F5DF1541BDCA0CE00C3A531 /* Nimble-tvOS */ = { isa = PBXNativeTarget; buildConfigurationList = 1F5DF16A1BDCA0CE00C3A531 /* Build configuration list for PBXNativeTarget "Nimble-tvOS" */; buildPhases = ( 1F5DF1501BDCA0CE00C3A531 /* Sources */, 1F5DF1511BDCA0CE00C3A531 /* Frameworks */, 1F5DF1521BDCA0CE00C3A531 /* Headers */, 1F5DF1531BDCA0CE00C3A531 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Nimble-tvOS"; productName = "Nimble-tvOS"; productReference = 1F5DF1551BDCA0CE00C3A531 /* Nimble.framework */; productType = "com.apple.product-type.framework"; }; 1F5DF15D1BDCA0CE00C3A531 /* Nimble-tvOSTests */ = { isa = PBXNativeTarget; buildConfigurationList = 1F5DF16B1BDCA0CE00C3A531 /* Build configuration list for PBXNativeTarget "Nimble-tvOSTests" */; buildPhases = ( 1F5DF15A1BDCA0CE00C3A531 /* Sources */, 1F5DF15B1BDCA0CE00C3A531 /* Frameworks */, 1F5DF15C1BDCA0CE00C3A531 /* Resources */, ); buildRules = ( ); dependencies = ( 1F5DF1611BDCA0CE00C3A531 /* PBXTargetDependency */, ); name = "Nimble-tvOSTests"; productName = "Nimble-tvOSTests"; productReference = 1F5DF15E1BDCA0CE00C3A531 /* NimbleTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 1F925EAC195C0D6300ED456B /* Nimble-OSX */ = { isa = PBXNativeTarget; buildConfigurationList = 1F925EC0195C0D6300ED456B /* Build configuration list for PBXNativeTarget "Nimble-OSX" */; buildPhases = ( 1F925EA8195C0D6300ED456B /* Sources */, 1F925EA9195C0D6300ED456B /* Frameworks */, 1F925EAA195C0D6300ED456B /* Headers */, 1F925EAB195C0D6300ED456B /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Nimble-OSX"; productName = "Nimble-OSX"; productReference = 1F925EAD195C0D6300ED456B /* Nimble.framework */; productType = "com.apple.product-type.framework"; }; 1F925EB6195C0D6300ED456B /* Nimble-OSXTests */ = { isa = PBXNativeTarget; buildConfigurationList = 1F925EC3195C0D6300ED456B /* Build configuration list for PBXNativeTarget "Nimble-OSXTests" */; buildPhases = ( 1F925EB3195C0D6300ED456B /* Sources */, 1F925EB4195C0D6300ED456B /* Frameworks */, 1F925EB5195C0D6300ED456B /* Resources */, ); buildRules = ( ); dependencies = ( 1F925EBA195C0D6300ED456B /* PBXTargetDependency */, 1F9B7BFE1968AD760094EB8F /* PBXTargetDependency */, 1F9B7C001968AD760094EB8F /* PBXTargetDependency */, 1F9B7C021968AD820094EB8F /* PBXTargetDependency */, ); name = "Nimble-OSXTests"; productName = "Nimble-OSXTests"; productReference = 1F925EB7195C0D6300ED456B /* NimbleTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 1F1A74201940169200FFFC47 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0710; LastUpgradeCheck = 0710; ORGANIZATIONNAME = "Jeff Hui"; TargetAttributes = { 1F1A74281940169200FFFC47 = { CreatedOnToolsVersion = 6.0; }; 1F1A74331940169200FFFC47 = { CreatedOnToolsVersion = 6.0; TestTargetID = 1F1A74281940169200FFFC47; }; 1F5DF1541BDCA0CE00C3A531 = { CreatedOnToolsVersion = 7.1; }; 1F5DF15D1BDCA0CE00C3A531 = { CreatedOnToolsVersion = 7.1; }; 1F925EAC195C0D6300ED456B = { CreatedOnToolsVersion = 6.0; }; 1F925EB6195C0D6300ED456B = { CreatedOnToolsVersion = 6.0; TestTargetID = 1F925EAC195C0D6300ED456B; }; }; }; buildConfigurationList = 1F1A74231940169200FFFC47 /* Build configuration list for PBXProject "Nimble" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = 1F1A741F1940169200FFFC47; productRefGroup = 1F1A742A1940169200FFFC47 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 1F1A74281940169200FFFC47 /* Nimble-iOS */, 1F1A74331940169200FFFC47 /* Nimble-iOSTests */, 1F925EAC195C0D6300ED456B /* Nimble-OSX */, 1F925EB6195C0D6300ED456B /* Nimble-OSXTests */, 1F5DF1541BDCA0CE00C3A531 /* Nimble-tvOS */, 1F5DF15D1BDCA0CE00C3A531 /* Nimble-tvOSTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 1F1A74271940169200FFFC47 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F1A74321940169200FFFC47 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F5DF1531BDCA0CE00C3A531 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F5DF15C1BDCA0CE00C3A531 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F925EAB195C0D6300ED456B /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F925EB5195C0D6300ED456B /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 1F1A74241940169200FFFC47 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 1FD8CD401968AB07008ED995 /* BeCloseTo.swift in Sources */, 1FD8CD741968AB07008ED995 /* MatcherFunc.swift in Sources */, 1FD8CD361968AB07008ED995 /* Expectation.swift in Sources */, 1FD8CD321968AB07008ED995 /* NimbleXCTestHandler.swift in Sources */, 1F43728F1A1B344000EB80F8 /* Stringers.swift in Sources */, 1F43728D1A1B343D00EB80F8 /* SourceLocation.swift in Sources */, 1FD8CD4E1968AB07008ED995 /* BeLessThanOrEqual.swift in Sources */, 1FDBD8671AF8A4FF0089F27B /* AssertionDispatcher.swift in Sources */, 1F43728A1A1B343800EB80F8 /* Functional.swift in Sources */, 1FD8CD3C1968AB07008ED995 /* BeAnInstanceOf.swift in Sources */, 1FD8CD501968AB07008ED995 /* BeLogical.swift in Sources */, 1F0FEA9A1AF32DA4001E554E /* ObjCExpectation.swift in Sources */, 1FD8CD661968AB07008ED995 /* NMBExceptionCapture.m in Sources */, DA9E8C821A414BB9002633C2 /* DSL+Wait.swift in Sources */, DDB1BC791A92235600F743C3 /* AllPass.swift in Sources */, 1FD8CD3E1968AB07008ED995 /* BeAKindOf.swift in Sources */, DDB4D5ED19FE43C200E9D9FE /* Match.swift in Sources */, 1FD8CD2E1968AB07008ED995 /* AssertionRecorder.swift in Sources */, 29EA59661B551EE6002D767E /* ThrowError.swift in Sources */, 1FD8CD5A1968AB07008ED995 /* Equal.swift in Sources */, 1FD8CD4C1968AB07008ED995 /* BeLessThan.swift in Sources */, 1FD8CD461968AB07008ED995 /* BeGreaterThan.swift in Sources */, 1FD8CD301968AB07008ED995 /* AdapterProtocols.swift in Sources */, 1FC494AA1C29CBA40010975C /* NimbleEnvironment.swift in Sources */, 1FD8CD5E1968AB07008ED995 /* RaisesException.swift in Sources */, 1FD8CD561968AB07008ED995 /* Contain.swift in Sources */, 1FD8CD481968AB07008ED995 /* BeGreaterThanOrEqualTo.swift in Sources */, 1FD8CD701968AB07008ED995 /* AsyncMatcherWrapper.swift in Sources */, 1FD8CD441968AB07008ED995 /* BeginWith.swift in Sources */, 1FD8CD4A1968AB07008ED995 /* BeIdenticalTo.swift in Sources */, 1FD8CD621968AB07008ED995 /* DSL.m in Sources */, 1FD8CD421968AB07008ED995 /* BeEmpty.swift in Sources */, 1FD8CD521968AB07008ED995 /* BeNil.swift in Sources */, 1FD8CD6A1968AB07008ED995 /* Async.swift in Sources */, 1FD8CD581968AB07008ED995 /* EndWith.swift in Sources */, 1FD8CD5C1968AB07008ED995 /* MatcherProtocols.swift in Sources */, 1FD8CD761968AB07008ED995 /* ObjCMatcher.swift in Sources */, 1FD8CD341968AB07008ED995 /* DSL.swift in Sources */, 7B5358BE1C38479700A23FAA /* SatisfyAnyOf.swift in Sources */, 1FD8CD381968AB07008ED995 /* Expression.swift in Sources */, 1FD8CD3A1968AB07008ED995 /* FailureMessage.swift in Sources */, 472FD1351B9E085700C7B8DA /* HaveCount.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F1A74301940169200FFFC47 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 1F4A569A1A3B3539009E1637 /* ObjCEqualTest.m in Sources */, 1F925EEC195C12C800ED456B /* RaisesExceptionTest.swift in Sources */, 1F925EFF195C187600ED456B /* EndWithTest.swift in Sources */, 1F1B5AD41963E13900CA8BF9 /* BeAKindOfTest.swift in Sources */, 1F925F0E195C18F500ED456B /* BeLessThanOrEqualToTest.swift in Sources */, 1F4A56661A3B305F009E1637 /* ObjCAsyncTest.m in Sources */, 1F925EFC195C186800ED456B /* BeginWithTest.swift in Sources */, 1F14FB64194180C5009F2A08 /* utils.swift in Sources */, DDB4D5F019FE442800E9D9FE /* MatchTest.swift in Sources */, 1F4A56731A3B3210009E1637 /* ObjCBeginWithTest.m in Sources */, 1F4A56821A3B336F009E1637 /* ObjCBeLessThanOrEqualToTest.m in Sources */, 1F925F02195C189500ED456B /* ContainTest.swift in Sources */, 1F4A56881A3B33CB009E1637 /* ObjCBeFalsyTest.m in Sources */, 1F4A568E1A3B342B009E1637 /* ObjCBeFalseTest.m in Sources */, 1F925F11195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift in Sources */, 1F925EEF195C136500ED456B /* BeLogicalTest.swift in Sources */, 1F4A56A01A3B359E009E1637 /* ObjCRaiseExceptionTest.m in Sources */, 1F925F0B195C18E100ED456B /* BeLessThanTest.swift in Sources */, 1F9DB8FB1A74E793002E96AD /* ObjCBeEmptyTest.m in Sources */, 1FB90098195EC4B8001D7FAE /* BeIdenticalToTest.swift in Sources */, 1F4A56761A3B3253009E1637 /* ObjCBeGreaterThanTest.m in Sources */, 1F925EF9195C175000ED456B /* BeNilTest.swift in Sources */, 1F4A56701A3B319F009E1637 /* ObjCBeCloseToTest.m in Sources */, 1F4A56971A3B34AA009E1637 /* ObjCEndWithTest.m in Sources */, 1F4A567C1A3B3311009E1637 /* ObjCBeIdenticalToTest.m in Sources */, 965B0D0C1B62C06D0005AE66 /* UserDescriptionTest.swift in Sources */, 965B0D091B62B8ED0005AE66 /* ObjCUserDescriptionTest.m in Sources */, 1F4A56911A3B344A009E1637 /* ObjCBeNilTest.m in Sources */, 1F8A37B01B7C5042001C8357 /* ObjCSyncTest.m in Sources */, 1F4A56941A3B346F009E1637 /* ObjCContainTest.m in Sources */, 1F299EAB19627B2D002641AF /* BeEmptyTest.swift in Sources */, 1F925EF6195C147800ED456B /* BeCloseToTest.swift in Sources */, 1F4A56791A3B32E3009E1637 /* ObjCBeGreaterThanOrEqualToTest.m in Sources */, 1F4A568B1A3B3407009E1637 /* ObjCBeTrueTest.m in Sources */, DDEFAEB41A93CBE6005CA37A /* ObjCAllPassTest.m in Sources */, 1F4A567F1A3B333F009E1637 /* ObjCBeLessThanTest.m in Sources */, 1F925EE6195C121200ED456B /* AsynchronousTest.swift in Sources */, 1F0648CC19639F5A001F9C46 /* ObjectWithLazyProperty.swift in Sources */, 1F4A56851A3B33A0009E1637 /* ObjCBeTruthyTest.m in Sources */, DD9A9A8F19CF439B00706F49 /* BeIdenticalToObjectTest.swift in Sources */, 1F0648D41963AAB2001F9C46 /* SynchronousTests.swift in Sources */, 4793854D1BA0BB2500296F85 /* ObjCHaveCount.m in Sources */, 1F925F08195C18CF00ED456B /* BeGreaterThanTest.swift in Sources */, 7B5358BA1C3846C900A23FAA /* SatisfyAnyOfTest.swift in Sources */, 1F925F05195C18B700ED456B /* EqualTest.swift in Sources */, 1F4A566D1A3B3159009E1637 /* ObjCBeKindOfTest.m in Sources */, DD72EC641A93874A002F7651 /* AllPassTest.swift in Sources */, 7B5358C51C39184200A23FAA /* ObjCSatisfyAnyOfTest.m in Sources */, 1F4A569D1A3B3565009E1637 /* ObjCMatchTest.m in Sources */, 1F925EE9195C124400ED456B /* BeAnInstanceOfTest.swift in Sources */, 29EA59631B551ED2002D767E /* ThrowErrorTest.swift in Sources */, 1F4A566A1A3B3108009E1637 /* ObjCBeAnInstanceOfTest.m in Sources */, 472FD13B1B9E0CFE00C7B8DA /* HaveCountTest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F5DF1501BDCA0CE00C3A531 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 1F5DF1791BDCA0F500C3A531 /* BeCloseTo.swift in Sources */, 1F5DF16C1BDCA0F500C3A531 /* AssertionRecorder.swift in Sources */, 1F5DF1881BDCA0F500C3A531 /* MatcherProtocols.swift in Sources */, 1F5DF16E1BDCA0F500C3A531 /* NimbleXCTestHandler.swift in Sources */, 1F5DF1751BDCA0F500C3A531 /* FailureMessage.swift in Sources */, 1F5DF1801BDCA0F500C3A531 /* BeLessThanOrEqual.swift in Sources */, 1F5DF18A1BDCA0F500C3A531 /* ThrowError.swift in Sources */, 1F5DF1891BDCA0F500C3A531 /* RaisesException.swift in Sources */, 1F5DF1761BDCA0F500C3A531 /* AllPass.swift in Sources */, 1F5DF1861BDCA0F500C3A531 /* HaveCount.swift in Sources */, 1F5DF1811BDCA0F500C3A531 /* BeLogical.swift in Sources */, 1F5DF1741BDCA0F500C3A531 /* Expression.swift in Sources */, 1F5DF1911BDCA0F500C3A531 /* ObjCMatcher.swift in Sources */, 1F5DF1781BDCA0F500C3A531 /* BeAnInstanceOf.swift in Sources */, 1F5DF1771BDCA0F500C3A531 /* BeAKindOf.swift in Sources */, 1F5DF17F1BDCA0F500C3A531 /* BeLessThan.swift in Sources */, 1F5DF17C1BDCA0F500C3A531 /* BeGreaterThan.swift in Sources */, 1F5DF1831BDCA0F500C3A531 /* Contain.swift in Sources */, 1F5DF1731BDCA0F500C3A531 /* ObjCExpectation.swift in Sources */, 1F5DF1851BDCA0F500C3A531 /* Equal.swift in Sources */, 1F5DF18F1BDCA0F500C3A531 /* AsyncMatcherWrapper.swift in Sources */, 1F5DF1711BDCA0F500C3A531 /* DSL+Wait.swift in Sources */, 1F5DF17D1BDCA0F500C3A531 /* BeGreaterThanOrEqualTo.swift in Sources */, 1FC494AC1C29CBA40010975C /* NimbleEnvironment.swift in Sources */, 1F5DF18E1BDCA0F500C3A531 /* Stringers.swift in Sources */, 1F5DF1AD1BDCA16E00C3A531 /* NMBExceptionCapture.m in Sources */, 1F5DF16D1BDCA0F500C3A531 /* AdapterProtocols.swift in Sources */, 1F5DF17B1BDCA0F500C3A531 /* BeginWith.swift in Sources */, 1F5DF17E1BDCA0F500C3A531 /* BeIdenticalTo.swift in Sources */, 1F5DF17A1BDCA0F500C3A531 /* BeEmpty.swift in Sources */, 1F5DF18C1BDCA0F500C3A531 /* Async.swift in Sources */, 1F5DF1821BDCA0F500C3A531 /* BeNil.swift in Sources */, 1F5DF1AC1BDCA16E00C3A531 /* DSL.m in Sources */, 1F5DF16F1BDCA0F500C3A531 /* AssertionDispatcher.swift in Sources */, 1F5DF1841BDCA0F500C3A531 /* EndWith.swift in Sources */, 1F5DF18D1BDCA0F500C3A531 /* SourceLocation.swift in Sources */, 1F5DF1701BDCA0F500C3A531 /* DSL.swift in Sources */, 1F5DF1721BDCA0F500C3A531 /* Expectation.swift in Sources */, 7B5358C01C38479700A23FAA /* SatisfyAnyOf.swift in Sources */, 1F5DF18B1BDCA0F500C3A531 /* Functional.swift in Sources */, 1F5DF1871BDCA0F500C3A531 /* Match.swift in Sources */, 1F5DF1901BDCA0F500C3A531 /* MatcherFunc.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F5DF15A1BDCA0CE00C3A531 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 1F5DF1A31BDCA10200C3A531 /* BeLogicalTest.swift in Sources */, 1F5DF1951BDCA10200C3A531 /* utils.swift in Sources */, 1F5DF1981BDCA10200C3A531 /* BeAKindOfTest.swift in Sources */, 1F5DF19B1BDCA10200C3A531 /* BeEmptyTest.swift in Sources */, 7B5358BC1C3846C900A23FAA /* SatisfyAnyOfTest.swift in Sources */, 1F5DF1A11BDCA10200C3A531 /* BeLessThanOrEqualToTest.swift in Sources */, 1F5DF1961BDCA10200C3A531 /* ObjectWithLazyProperty.swift in Sources */, 1F5DF1AB1BDCA10200C3A531 /* ThrowErrorTest.swift in Sources */, 1F5DF1A51BDCA10200C3A531 /* ContainTest.swift in Sources */, 1F5DF19E1BDCA10200C3A531 /* BeGreaterThanTest.swift in Sources */, 1F5DF1A21BDCA10200C3A531 /* BeLessThanTest.swift in Sources */, 1F5DF1921BDCA10200C3A531 /* AsynchronousTest.swift in Sources */, 1F5DF1A91BDCA10200C3A531 /* MatchTest.swift in Sources */, 1F5DF1A81BDCA10200C3A531 /* HaveCountTest.swift in Sources */, 1F5DF1971BDCA10200C3A531 /* AllPassTest.swift in Sources */, 1F5DF19C1BDCA10200C3A531 /* BeginWithTest.swift in Sources */, 1F5DF1A01BDCA10200C3A531 /* BeIdenticalToTest.swift in Sources */, 1F5DF19A1BDCA10200C3A531 /* BeCloseToTest.swift in Sources */, 1F5DF1A61BDCA10200C3A531 /* EndWithTest.swift in Sources */, 1F5DF1A71BDCA10200C3A531 /* EqualTest.swift in Sources */, 1F5DF1931BDCA10200C3A531 /* SynchronousTests.swift in Sources */, 1F5DF19D1BDCA10200C3A531 /* BeGreaterThanOrEqualToTest.swift in Sources */, 1F5DF1A41BDCA10200C3A531 /* BeNilTest.swift in Sources */, 1F5DF1AA1BDCA10200C3A531 /* RaisesExceptionTest.swift in Sources */, 1F5DF1941BDCA10200C3A531 /* UserDescriptionTest.swift in Sources */, 1F5DF19F1BDCA10200C3A531 /* BeIdenticalToObjectTest.swift in Sources */, 1F5DF1991BDCA10200C3A531 /* BeAnInstanceOfTest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F925EA8195C0D6300ED456B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 1FD8CD411968AB07008ED995 /* BeCloseTo.swift in Sources */, 1FD8CD751968AB07008ED995 /* MatcherFunc.swift in Sources */, 1FD8CD371968AB07008ED995 /* Expectation.swift in Sources */, 1FD8CD331968AB07008ED995 /* NimbleXCTestHandler.swift in Sources */, 1F43728E1A1B343F00EB80F8 /* Stringers.swift in Sources */, 1F43728C1A1B343C00EB80F8 /* SourceLocation.swift in Sources */, 1FD8CD4F1968AB07008ED995 /* BeLessThanOrEqual.swift in Sources */, 1FDBD8681AF8A4FF0089F27B /* AssertionDispatcher.swift in Sources */, 1F43728B1A1B343900EB80F8 /* Functional.swift in Sources */, 1FD8CD3D1968AB07008ED995 /* BeAnInstanceOf.swift in Sources */, 1FD8CD511968AB07008ED995 /* BeLogical.swift in Sources */, 1F0FEA9B1AF32DA4001E554E /* ObjCExpectation.swift in Sources */, 1FD8CD671968AB07008ED995 /* NMBExceptionCapture.m in Sources */, DA9E8C831A414BB9002633C2 /* DSL+Wait.swift in Sources */, DDB1BC7A1A92235600F743C3 /* AllPass.swift in Sources */, 1FD8CD3F1968AB07008ED995 /* BeAKindOf.swift in Sources */, 1FD8CD2F1968AB07008ED995 /* AssertionRecorder.swift in Sources */, DDB4D5EE19FE43C200E9D9FE /* Match.swift in Sources */, 29EA59671B551EE6002D767E /* ThrowError.swift in Sources */, 1FD8CD5B1968AB07008ED995 /* Equal.swift in Sources */, 1FD8CD4D1968AB07008ED995 /* BeLessThan.swift in Sources */, 1FD8CD471968AB07008ED995 /* BeGreaterThan.swift in Sources */, 1FD8CD311968AB07008ED995 /* AdapterProtocols.swift in Sources */, 1FC494AB1C29CBA40010975C /* NimbleEnvironment.swift in Sources */, 1FD8CD5F1968AB07008ED995 /* RaisesException.swift in Sources */, 1FD8CD571968AB07008ED995 /* Contain.swift in Sources */, 1FD8CD491968AB07008ED995 /* BeGreaterThanOrEqualTo.swift in Sources */, 1FD8CD711968AB07008ED995 /* AsyncMatcherWrapper.swift in Sources */, 1FD8CD451968AB07008ED995 /* BeginWith.swift in Sources */, 1FD8CD4B1968AB07008ED995 /* BeIdenticalTo.swift in Sources */, 1FD8CD631968AB07008ED995 /* DSL.m in Sources */, 1FD8CD431968AB07008ED995 /* BeEmpty.swift in Sources */, 1FD8CD531968AB07008ED995 /* BeNil.swift in Sources */, 1FD8CD6B1968AB07008ED995 /* Async.swift in Sources */, 1FD8CD591968AB07008ED995 /* EndWith.swift in Sources */, 1FD8CD5D1968AB07008ED995 /* MatcherProtocols.swift in Sources */, 1FD8CD771968AB07008ED995 /* ObjCMatcher.swift in Sources */, 1FD8CD351968AB07008ED995 /* DSL.swift in Sources */, 7B5358BF1C38479700A23FAA /* SatisfyAnyOf.swift in Sources */, 1FD8CD391968AB07008ED995 /* Expression.swift in Sources */, 1FD8CD3B1968AB07008ED995 /* FailureMessage.swift in Sources */, 472FD1391B9E0A9700C7B8DA /* HaveCount.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F925EB3195C0D6300ED456B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 1F4A569B1A3B3539009E1637 /* ObjCEqualTest.m in Sources */, 1F925EED195C12C800ED456B /* RaisesExceptionTest.swift in Sources */, 1F925F00195C187600ED456B /* EndWithTest.swift in Sources */, 1F1B5AD51963E13900CA8BF9 /* BeAKindOfTest.swift in Sources */, 1F925F0F195C18F500ED456B /* BeLessThanOrEqualToTest.swift in Sources */, 1F4A56671A3B305F009E1637 /* ObjCAsyncTest.m in Sources */, 1F925EFD195C186800ED456B /* BeginWithTest.swift in Sources */, 1F925EE2195C0DFD00ED456B /* utils.swift in Sources */, DDB4D5F119FE442800E9D9FE /* MatchTest.swift in Sources */, 1F4A56741A3B3210009E1637 /* ObjCBeginWithTest.m in Sources */, 1F4A56831A3B336F009E1637 /* ObjCBeLessThanOrEqualToTest.m in Sources */, 1F925F03195C189500ED456B /* ContainTest.swift in Sources */, 1F4A56891A3B33CB009E1637 /* ObjCBeFalsyTest.m in Sources */, 1F4A568F1A3B342B009E1637 /* ObjCBeFalseTest.m in Sources */, 1F925F12195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift in Sources */, 1F925EF0195C136500ED456B /* BeLogicalTest.swift in Sources */, 1F4A56A11A3B359E009E1637 /* ObjCRaiseExceptionTest.m in Sources */, 1F925F0C195C18E100ED456B /* BeLessThanTest.swift in Sources */, 1F9DB8FC1A74E793002E96AD /* ObjCBeEmptyTest.m in Sources */, 1FB90099195EC4B8001D7FAE /* BeIdenticalToTest.swift in Sources */, 1F4A56771A3B3253009E1637 /* ObjCBeGreaterThanTest.m in Sources */, 1F925EFA195C175000ED456B /* BeNilTest.swift in Sources */, 1F4A56711A3B319F009E1637 /* ObjCBeCloseToTest.m in Sources */, 1F4A56981A3B34AA009E1637 /* ObjCEndWithTest.m in Sources */, 1F4A567D1A3B3311009E1637 /* ObjCBeIdenticalToTest.m in Sources */, 965B0D0D1B62C06D0005AE66 /* UserDescriptionTest.swift in Sources */, 965B0D0A1B62B8ED0005AE66 /* ObjCUserDescriptionTest.m in Sources */, 1F4A56921A3B344A009E1637 /* ObjCBeNilTest.m in Sources */, 1F8A37B11B7C5042001C8357 /* ObjCSyncTest.m in Sources */, 1F4A56951A3B346F009E1637 /* ObjCContainTest.m in Sources */, 1F299EAC19627B2D002641AF /* BeEmptyTest.swift in Sources */, 1F925EF7195C147800ED456B /* BeCloseToTest.swift in Sources */, 1F4A567A1A3B32E3009E1637 /* ObjCBeGreaterThanOrEqualToTest.m in Sources */, 1F4A568C1A3B3407009E1637 /* ObjCBeTrueTest.m in Sources */, DDEFAEB51A93CBE6005CA37A /* ObjCAllPassTest.m in Sources */, 1F4A56801A3B333F009E1637 /* ObjCBeLessThanTest.m in Sources */, 1F925EE7195C121200ED456B /* AsynchronousTest.swift in Sources */, 1F0648CD19639F5A001F9C46 /* ObjectWithLazyProperty.swift in Sources */, 1F4A56861A3B33A0009E1637 /* ObjCBeTruthyTest.m in Sources */, DD9A9A9019CF43AD00706F49 /* BeIdenticalToObjectTest.swift in Sources */, 1F0648D51963AAB2001F9C46 /* SynchronousTests.swift in Sources */, 4793854E1BA0BB2500296F85 /* ObjCHaveCount.m in Sources */, 1F925F09195C18CF00ED456B /* BeGreaterThanTest.swift in Sources */, 7B5358BB1C3846C900A23FAA /* SatisfyAnyOfTest.swift in Sources */, 1F925F06195C18B700ED456B /* EqualTest.swift in Sources */, 1F4A566E1A3B3159009E1637 /* ObjCBeKindOfTest.m in Sources */, DD72EC651A93874A002F7651 /* AllPassTest.swift in Sources */, 7B5358C61C39184200A23FAA /* ObjCSatisfyAnyOfTest.m in Sources */, 1F4A569E1A3B3565009E1637 /* ObjCMatchTest.m in Sources */, 1F925EEA195C124400ED456B /* BeAnInstanceOfTest.swift in Sources */, 29EA59641B551ED2002D767E /* ThrowErrorTest.swift in Sources */, 1F4A566B1A3B3108009E1637 /* ObjCBeAnInstanceOfTest.m in Sources */, 472FD13A1B9E0A9F00C7B8DA /* HaveCountTest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 1F1A74371940169200FFFC47 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F1A74281940169200FFFC47 /* Nimble-iOS */; targetProxy = 1F1A74361940169200FFFC47 /* PBXContainerItemProxy */; }; 1F5DF1611BDCA0CE00C3A531 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F5DF1541BDCA0CE00C3A531 /* Nimble-tvOS */; targetProxy = 1F5DF1601BDCA0CE00C3A531 /* PBXContainerItemProxy */; }; 1F6BB82B1968BFF9009F1DBB /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F1A74281940169200FFFC47 /* Nimble-iOS */; targetProxy = 1F6BB82A1968BFF9009F1DBB /* PBXContainerItemProxy */; }; 1F925EA5195C0C8500ED456B /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F1A74281940169200FFFC47 /* Nimble-iOS */; targetProxy = 1F925EA4195C0C8500ED456B /* PBXContainerItemProxy */; }; 1F925EA7195C0C8500ED456B /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F1A74281940169200FFFC47 /* Nimble-iOS */; targetProxy = 1F925EA6195C0C8500ED456B /* PBXContainerItemProxy */; }; 1F925EBA195C0D6300ED456B /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F925EAC195C0D6300ED456B /* Nimble-OSX */; targetProxy = 1F925EB9195C0D6300ED456B /* PBXContainerItemProxy */; }; 1F9B7BFE1968AD760094EB8F /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F925EAC195C0D6300ED456B /* Nimble-OSX */; targetProxy = 1F9B7BFD1968AD760094EB8F /* PBXContainerItemProxy */; }; 1F9B7C001968AD760094EB8F /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F925EAC195C0D6300ED456B /* Nimble-OSX */; targetProxy = 1F9B7BFF1968AD760094EB8F /* PBXContainerItemProxy */; }; 1F9B7C021968AD820094EB8F /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F925EAC195C0D6300ED456B /* Nimble-OSX */; targetProxy = 1F9B7C011968AD820094EB8F /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 1F1A743D1940169200FFFC47 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_MODULES_AUTOLINK = NO; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; 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; IPHONEOS_DEPLOYMENT_TARGET = 7.0; METAL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TARGETED_DEVICE_FAMILY = "1,2,3"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; 1F1A743E1940169200FFFC47 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_MODULES_AUTOLINK = NO; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; CURRENT_PROJECT_VERSION = 1; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; 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; IPHONEOS_DEPLOYMENT_TARGET = 7.0; METAL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2,3"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Release; }; 1F1A74401940169200FFFC47 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(DEVELOPER_FRAMEWORKS_DIR)", ); GCC_TREAT_WARNINGS_AS_ERRORS = YES; INFOPLIST_FILE = Nimble/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; ONLY_ACTIVE_ARCH = NO; OTHER_LDFLAGS = ( "-weak_framework", XCTest, "-weak-lswiftXCTest", ); PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_MODULE_NAME = Nimble; PRODUCT_NAME = Nimble; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 1F1A74411940169200FFFC47 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(DEVELOPER_FRAMEWORKS_DIR)", ); GCC_TREAT_WARNINGS_AS_ERRORS = YES; INFOPLIST_FILE = Nimble/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_LDFLAGS = ( "-weak_framework", XCTest, "-weak-lswiftXCTest", ); PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_MODULE_NAME = Nimble; PRODUCT_NAME = Nimble; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OBJC_BRIDGING_HEADER = ""; }; name = Release; }; 1F1A74431940169200FFFC47 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = NimbleTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; METAL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = NimbleTests; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OBJC_BRIDGING_HEADER = "NimbleTests/objc/NimbleTests-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 1F1A74441940169200FFFC47 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", ); INFOPLIST_FILE = NimbleTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; METAL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = NimbleTests; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OBJC_BRIDGING_HEADER = "NimbleTests/objc/NimbleTests-Bridging-Header.h"; }; name = Release; }; 1F5DF1661BDCA0CE00C3A531 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(DEVELOPER_FRAMEWORKS_DIR)", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = Nimble/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; OTHER_LDFLAGS = ( "-weak_framework", XCTest, "-weak-lswiftXCTest", ); PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_MODULE_NAME = Nimble; PRODUCT_NAME = Nimble; SDKROOT = appletvos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; }; 1F5DF1671BDCA0CE00C3A531 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(DEVELOPER_FRAMEWORKS_DIR)", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = Nimble/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = ( "-weak_framework", XCTest, "-weak-lswiftXCTest", ); PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_MODULE_NAME = Nimble; PRODUCT_NAME = Nimble; SDKROOT = appletvos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Release; }; 1F5DF1681BDCA0CE00C3A531 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { DEBUG_INFORMATION_FORMAT = dwarf; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = NimbleTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = NimbleTests; SDKROOT = appletvos; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; }; 1F5DF1691BDCA0CE00C3A531 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = NimbleTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = NimbleTests; SDKROOT = appletvos; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Release; }; 1F925EC1195C0D6300ED456B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(DEVELOPER_FRAMEWORKS_DIR)", ); FRAMEWORK_VERSION = A; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_TREAT_WARNINGS_AS_ERRORS = YES; INFOPLIST_FILE = Nimble/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.9; METAL_ENABLE_DEBUG_INFO = YES; OTHER_LDFLAGS = ( "-weak_framework", XCTest, "-weak-lswiftXCTest", ); PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_MODULE_NAME = Nimble; PRODUCT_NAME = Nimble; SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OBJC_BRIDGING_HEADER = ""; VALID_ARCHS = x86_64; }; name = Debug; }; 1F925EC2195C0D6300ED456B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(DEVELOPER_FRAMEWORKS_DIR)", ); FRAMEWORK_VERSION = A; GCC_TREAT_WARNINGS_AS_ERRORS = YES; INFOPLIST_FILE = Nimble/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.9; METAL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = ( "-weak_framework", XCTest, "-weak-lswiftXCTest", ); PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_MODULE_NAME = Nimble; PRODUCT_NAME = Nimble; SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OBJC_BRIDGING_HEADER = ""; VALID_ARCHS = x86_64; }; name = Release; }; 1F925EC4195C0D6300ED456B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = NimbleTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.9; METAL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = NimbleTests; SDKROOT = macosx; SWIFT_OBJC_BRIDGING_HEADER = "NimbleTests/objc/Nimble-OSXTests-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 1F925EC5195C0D6300ED456B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); INFOPLIST_FILE = NimbleTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.9; METAL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = NimbleTests; SDKROOT = macosx; SWIFT_OBJC_BRIDGING_HEADER = "NimbleTests/objc/Nimble-OSXTests-Bridging-Header.h"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 1F1A74231940169200FFFC47 /* Build configuration list for PBXProject "Nimble" */ = { isa = XCConfigurationList; buildConfigurations = ( 1F1A743D1940169200FFFC47 /* Debug */, 1F1A743E1940169200FFFC47 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 1F1A743F1940169200FFFC47 /* Build configuration list for PBXNativeTarget "Nimble-iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 1F1A74401940169200FFFC47 /* Debug */, 1F1A74411940169200FFFC47 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 1F1A74421940169200FFFC47 /* Build configuration list for PBXNativeTarget "Nimble-iOSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 1F1A74431940169200FFFC47 /* Debug */, 1F1A74441940169200FFFC47 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 1F5DF16A1BDCA0CE00C3A531 /* Build configuration list for PBXNativeTarget "Nimble-tvOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 1F5DF1661BDCA0CE00C3A531 /* Debug */, 1F5DF1671BDCA0CE00C3A531 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 1F5DF16B1BDCA0CE00C3A531 /* Build configuration list for PBXNativeTarget "Nimble-tvOSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 1F5DF1681BDCA0CE00C3A531 /* Debug */, 1F5DF1691BDCA0CE00C3A531 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 1F925EC0195C0D6300ED456B /* Build configuration list for PBXNativeTarget "Nimble-OSX" */ = { isa = XCConfigurationList; buildConfigurations = ( 1F925EC1195C0D6300ED456B /* Debug */, 1F925EC2195C0D6300ED456B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 1F925EC3195C0D6300ED456B /* Build configuration list for PBXNativeTarget "Nimble-OSXTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 1F925EC4195C0D6300ED456B /* Debug */, 1F925EC5195C0D6300ED456B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 1F1A74201940169200FFFC47 /* Project object */; } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble.xcodeproj/xcshareddata/xcschemes/Nimble-OSX.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble.xcodeproj/xcshareddata/xcschemes/Nimble-iOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/Nimble.xcodeproj/xcshareddata/xcschemes/Nimble-tvOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/AsynchronousTest.swift ================================================ import XCTest import Nimble class AsyncTest: XCTestCase { let errorToThrow = NSError(domain: NSInternalInconsistencyException, code: 42, userInfo: nil) private func doThrowError() throws -> Int { throw errorToThrow } func testToEventuallyPositiveMatches() { var value = 0 deferToMainQueue { value = 1 } expect { value }.toEventually(equal(1)) deferToMainQueue { value = 0 } expect { value }.toEventuallyNot(equal(1)) } func testToEventuallyNegativeMatches() { let value = 0 failsWithErrorMessage("expected to eventually not equal <0>, got <0>") { expect { value }.toEventuallyNot(equal(0)) } failsWithErrorMessage("expected to eventually equal <1>, got <0>") { expect { value }.toEventually(equal(1)) } failsWithErrorMessage("expected to eventually equal <1>, got an unexpected error thrown: <\(errorToThrow)>") { expect { try self.doThrowError() }.toEventually(equal(1)) } failsWithErrorMessage("expected to eventually not equal <0>, got an unexpected error thrown: <\(errorToThrow)>") { expect { try self.doThrowError() }.toEventuallyNot(equal(0)) } } func testWaitUntilPositiveMatches() { waitUntil { done in done() } waitUntil { done in deferToMainQueue { done() } } } func testWaitUntilTimesOutIfNotCalled() { failsWithErrorMessage("Waited more than 1.0 second") { waitUntil(timeout: 1) { done in return } } } func testWaitUntilTimesOutWhenExceedingItsTime() { var waiting = true failsWithErrorMessage("Waited more than 0.01 seconds") { waitUntil(timeout: 0.01) { done in dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { NSThread.sleepForTimeInterval(0.1) done() waiting = false } } } // "clear" runloop to ensure this test doesn't poison other tests repeat { NSRunLoop.mainRunLoop().runUntilDate(NSDate().dateByAddingTimeInterval(0.2)) } while(waiting) } func testWaitUntilNegativeMatches() { failsWithErrorMessage("expected to equal <2>, got <1>") { waitUntil { done in NSThread.sleepForTimeInterval(0.1) expect(1).to(equal(2)) done() } } } func testWaitUntilDetectsStalledMainThreadActivity() { let msg = "-waitUntil() timed out but was unable to run the timeout handler because the main thread is unresponsive (0.5 seconds is allow after the wait times out). Conditions that may cause this include processing blocking IO on the main thread, calls to sleep(), deadlocks, and synchronous IPC. Nimble forcefully stopped run loop which may cause future failures in test run." failsWithErrorMessage(msg) { waitUntil(timeout: 1) { done in NSThread.sleepForTimeInterval(5.0) done() } } } func testCombiningAsyncWaitUntilAndToEventuallyIsNotAllowed() { let referenceLine = __LINE__ + 9 var msg = "Unexpected exception raised: Nested async expectations are not allowed " msg += "to avoid creating flaky tests." msg += "\n\n" msg += "The call to\n\t" msg += "expect(...).toEventually(...) at \(__FILE__):\(referenceLine + 7)\n" msg += "triggered this exception because\n\t" msg += "waitUntil(...) at \(__FILE__):\(referenceLine + 1)\n" msg += "is currently managing the main run loop." failsWithErrorMessage(msg) { // reference line waitUntil(timeout: 2.0) { done in var protected: Int = 0 dispatch_async(dispatch_get_main_queue()) { protected = 1 } expect(protected).toEventually(equal(1)) done() } } } func testWaitUntilErrorsIfDoneIsCalledMultipleTimes() { waitUntil { done in deferToMainQueue { done() } } waitUntil { done in deferToMainQueue { done() expect { done() }.to(raiseException(named: "InvalidNimbleAPIUsage")) } } } func testWaitUntilMustBeInMainThread() { var executedAsyncBlock: Bool = false dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { expect { waitUntil { done in done() } }.to(raiseException(named: "InvalidNimbleAPIUsage")) executedAsyncBlock = true } expect(executedAsyncBlock).toEventually(beTruthy()) } func testToEventuallyMustBeInMainThread() { var executedAsyncBlock: Bool = false dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { expect { expect(1).toEventually(equal(2)) }.to(raiseException(named: "InvalidNimbleAPIUsage")) executedAsyncBlock = true } expect(executedAsyncBlock).toEventually(beTruthy()) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Helpers/ObjectWithLazyProperty.swift ================================================ import Foundation class ObjectWithLazyProperty { init() {} lazy var value: String = "hello" lazy var anotherValue: String = { return "world" }() } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Helpers/utils.swift ================================================ import Foundation import Nimble import XCTest func failsWithErrorMessage(messages: [String], file: String = __FILE__, line: UInt = __LINE__, preferOriginalSourceLocation: Bool = false, closure: () throws -> Void) { var filePath = file var lineNumber = line let recorder = AssertionRecorder() withAssertionHandler(recorder, closure: closure) for msg in messages { var lastFailure: AssertionRecord? var foundFailureMessage = false for assertion in recorder.assertions { lastFailure = assertion if assertion.message.stringValue == msg { foundFailureMessage = true break } } if foundFailureMessage { continue } if preferOriginalSourceLocation { if let failure = lastFailure { filePath = failure.location.file lineNumber = failure.location.line } } if let lastFailure = lastFailure { let msg = "Got failure message: \"\(lastFailure.message.stringValue)\", but expected \"\(msg)\"" XCTFail(msg, file: filePath, line: lineNumber) } else { XCTFail("expected failure message, but got none", file: filePath, line: lineNumber) } } } func failsWithErrorMessage(message: String, file: String = __FILE__, line: UInt = __LINE__, preferOriginalSourceLocation: Bool = false, closure: () -> Void) { return failsWithErrorMessage( [message], file: file, line: line, preferOriginalSourceLocation: preferOriginalSourceLocation, closure: closure ) } func failsWithErrorMessageForNil(message: String, file: String = __FILE__, line: UInt = __LINE__, preferOriginalSourceLocation: Bool = false, closure: () -> Void) { failsWithErrorMessage("\(message) (use beNil() to match nils)", file: file, line: line, preferOriginalSourceLocation: preferOriginalSourceLocation, closure: closure) } func deferToMainQueue(action: () -> Void) { dispatch_async(dispatch_get_main_queue()) { NSThread.sleepForTimeInterval(0.01) action() } } public class NimbleHelper : NSObject { class func expectFailureMessage(message: NSString, block: () -> Void, file: String, line: UInt) { failsWithErrorMessage(message as String, file: file, line: line, preferOriginalSourceLocation: true, closure: block) } class func expectFailureMessages(messages: [NSString], block: () -> Void, file: String, line: UInt) { failsWithErrorMessage(messages as! [String], file: file, line: line, preferOriginalSourceLocation: true, closure: block) } class func expectFailureMessageForNil(message: NSString, block: () -> Void, file: String, line: UInt) { failsWithErrorMessageForNil(message as String, file: file, line: line, preferOriginalSourceLocation: true, closure: block) } } extension NSDate { convenience init(dateTimeString:String) { let dateFormatter = NSDateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") let date = dateFormatter.dateFromString(dateTimeString)! self.init(timeInterval:0, sinceDate:date) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/AllPassTest.swift ================================================ import XCTest import Nimble class AllPassTest: XCTestCase { func testAllPassArray() { expect([1,2,3,4]).to(allPass({$0 < 5})) expect([1,2,3,4]).toNot(allPass({$0 > 5})) failsWithErrorMessage( "expected to all pass a condition, but failed first at element <3> in <[1, 2, 3, 4]>") { expect([1,2,3,4]).to(allPass({$0 < 3})) } failsWithErrorMessage("expected to not all pass a condition") { expect([1,2,3,4]).toNot(allPass({$0 < 5})) } failsWithErrorMessage( "expected to all be something, but failed first at element <3> in <[1, 2, 3, 4]>") { expect([1,2,3,4]).to(allPass("be something", {$0 < 3})) } failsWithErrorMessage("expected to not all be something") { expect([1,2,3,4]).toNot(allPass("be something", {$0 < 5})) } } func testAllPassMatcher() { expect([1,2,3,4]).to(allPass(beLessThan(5))) expect([1,2,3,4]).toNot(allPass(beGreaterThan(5))) failsWithErrorMessage( "expected to all be less than <3>, but failed first at element <3> in <[1, 2, 3, 4]>") { expect([1,2,3,4]).to(allPass(beLessThan(3))) } failsWithErrorMessage("expected to not all be less than <5>") { expect([1,2,3,4]).toNot(allPass(beLessThan(5))) } } func testAllPassCollectionsWithOptionalsDontWork() { failsWithErrorMessage("expected to all be nil, but failed first at element in <[nil, nil, nil]>") { expect([nil, nil, nil] as [Int?]).to(allPass(beNil())) } failsWithErrorMessage("expected to all pass a condition, but failed first at element in <[nil, nil, nil]>") { expect([nil, nil, nil] as [Int?]).to(allPass({$0 == nil})) } } func testAllPassCollectionsWithOptionalsUnwrappingOneOptionalLayer() { expect([nil, nil, nil] as [Int?]).to(allPass({$0! == nil})) expect([nil, 1, nil] as [Int?]).toNot(allPass({$0! == nil})) expect([1, 1, 1] as [Int?]).to(allPass({$0! == 1})) expect([1, 1, nil] as [Int?]).toNot(allPass({$0! == 1})) expect([1, 2, 3] as [Int?]).to(allPass({$0! < 4})) expect([1, 2, 3] as [Int?]).toNot(allPass({$0! < 3})) expect([1, 2, nil] as [Int?]).to(allPass({$0! < 3})) } func testAllPassSet() { expect(Set([1,2,3,4])).to(allPass({$0 < 5})) expect(Set([1,2,3,4])).toNot(allPass({$0 > 5})) failsWithErrorMessage("expected to not all pass a condition") { expect(Set([1,2,3,4])).toNot(allPass({$0 < 5})) } failsWithErrorMessage("expected to not all be something") { expect(Set([1,2,3,4])).toNot(allPass("be something", {$0 < 5})) } } func testAllPassWithNilAsExpectedValue() { failsWithErrorMessageForNil("expected to all pass") { expect(nil as [Int]?).to(allPass(beLessThan(5))) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/BeAKindOfTest.swift ================================================ import XCTest import Nimble class TestNull : NSNull {} class BeAKindOfTest: XCTestCase { func testPositiveMatch() { expect(TestNull()).to(beAKindOf(NSNull)) expect(NSObject()).to(beAKindOf(NSObject)) expect(NSNumber(integer:1)).toNot(beAKindOf(NSDate)) } func testFailureMessages() { failsWithErrorMessageForNil("expected to not be a kind of NSNull, got ") { expect(nil as NSNull?).toNot(beAKindOf(NSNull)) } failsWithErrorMessageForNil("expected to be a kind of NSString, got ") { expect(nil as NSString?).to(beAKindOf(NSString)) } failsWithErrorMessage("expected to be a kind of NSString, got <__NSCFNumber instance>") { expect(NSNumber(integer:1)).to(beAKindOf(NSString)) } failsWithErrorMessage("expected to not be a kind of NSNumber, got <__NSCFNumber instance>") { expect(NSNumber(integer:1)).toNot(beAKindOf(NSNumber)) } } func testSwiftTypesFailureMessages() { enum TestEnum { case One, Two } failsWithErrorMessage("beAKindOf only works on Objective-C types since the Swift compiler" + " will automatically type check Swift-only types. This expectation is redundant.") { expect(1).to(beAKindOf(Int)) } failsWithErrorMessage("beAKindOf only works on Objective-C types since the Swift compiler" + " will automatically type check Swift-only types. This expectation is redundant.") { expect("test").to(beAKindOf(String)) } failsWithErrorMessage("beAKindOf only works on Objective-C types since the Swift compiler" + " will automatically type check Swift-only types. This expectation is redundant.") { expect(TestEnum.One).to(beAKindOf(TestEnum)) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/BeAnInstanceOfTest.swift ================================================ import XCTest import Nimble class BeAnInstanceOfTest: XCTestCase { func testPositiveMatch() { expect(NSNull()).to(beAnInstanceOf(NSNull)) expect(NSNumber(integer:1)).toNot(beAnInstanceOf(NSDate)) } func testFailureMessages() { failsWithErrorMessageForNil("expected to not be an instance of NSNull, got ") { expect(nil as NSNull?).toNot(beAnInstanceOf(NSNull)) } failsWithErrorMessageForNil("expected to be an instance of NSString, got ") { expect(nil as NSString?).to(beAnInstanceOf(NSString)) } failsWithErrorMessage("expected to be an instance of NSString, got <__NSCFNumber instance>") { expect(NSNumber(integer:1)).to(beAnInstanceOf(NSString)) } failsWithErrorMessage("expected to not be an instance of NSNumber, got <__NSCFNumber instance>") { expect(NSNumber(integer:1)).toNot(beAnInstanceOf(NSNumber)) } } func testSwiftTypesFailureMessages() { enum TestEnum { case One, Two } failsWithErrorMessage("beAnInstanceOf only works on Objective-C types since the Swift compiler" + " will automatically type check Swift-only types. This expectation is redundant.") { expect(1).to(beAnInstanceOf(Int)) } failsWithErrorMessage("beAnInstanceOf only works on Objective-C types since the Swift compiler" + " will automatically type check Swift-only types. This expectation is redundant.") { expect("test").to(beAnInstanceOf(String)) } failsWithErrorMessage("beAnInstanceOf only works on Objective-C types since the Swift compiler" + " will automatically type check Swift-only types. This expectation is redundant.") { expect(TestEnum.One).to(beAnInstanceOf(TestEnum)) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/BeCloseToTest.swift ================================================ import XCTest import Nimble class BeCloseToTest: XCTestCase { func testBeCloseTo() { expect(1.2).to(beCloseTo(1.2001)) expect(1.2 as CDouble).to(beCloseTo(1.2001)) expect(1.2 as Float).to(beCloseTo(1.2001)) failsWithErrorMessage("expected to not be close to <1.2001> (within 0.0001), got <1.2000>") { expect(1.2).toNot(beCloseTo(1.2001)) } } func testBeCloseToWithin() { expect(1.2).to(beCloseTo(9.300, within: 10)) failsWithErrorMessage("expected to not be close to <1.2001> (within 1.0000), got <1.2000>") { expect(1.2).toNot(beCloseTo(1.2001, within: 1.0)) } } func testBeCloseToWithNSNumber() { expect(NSNumber(double:1.2)).to(beCloseTo(9.300, within: 10)) expect(NSNumber(double:1.2)).to(beCloseTo(NSNumber(double:9.300), within: 10)) expect(1.2).to(beCloseTo(NSNumber(double:9.300), within: 10)) failsWithErrorMessage("expected to not be close to <1.2001> (within 1.0000), got <1.2000>") { expect(NSNumber(double:1.2)).toNot(beCloseTo(1.2001, within: 1.0)) } } func testBeCloseToWithNSDate() { expect(NSDate(dateTimeString: "2015-08-26 11:43:00")).to(beCloseTo(NSDate(dateTimeString: "2015-08-26 11:43:05"), within: 10)) failsWithErrorMessage("expected to not be close to <2015-08-26 11:43:00.0050> (within 0.0040), got <2015-08-26 11:43:00.0000>") { let expectedDate = NSDate(dateTimeString: "2015-08-26 11:43:00").dateByAddingTimeInterval(0.005) expect(NSDate(dateTimeString: "2015-08-26 11:43:00")).toNot(beCloseTo(expectedDate, within: 0.004)) } } func testBeCloseToOperator() { expect(1.2) ≈ 1.2001 expect(1.2 as CDouble) ≈ 1.2001 failsWithErrorMessage("expected to be close to <1.2002> (within 0.0001), got <1.2000>") { expect(1.2) ≈ 1.2002 } } func testBeCloseToWithinOperator() { expect(1.2) ≈ (9.300, 10) expect(1.2) == (9.300, 10) failsWithErrorMessage("expected to be close to <1.0000> (within 0.1000), got <1.2000>") { expect(1.2) ≈ (1.0, 0.1) } failsWithErrorMessage("expected to be close to <1.0000> (within 0.1000), got <1.2000>") { expect(1.2) == (1.0, 0.1) } } func testPlusMinusOperator() { expect(1.2) ≈ 9.300 ± 10 expect(1.2) == 9.300 ± 10 failsWithErrorMessage("expected to be close to <1.0000> (within 0.1000), got <1.2000>") { expect(1.2) ≈ 1.0 ± 0.1 } failsWithErrorMessage("expected to be close to <1.0000> (within 0.1000), got <1.2000>") { expect(1.2) == 1.0 ± 0.1 } } func testBeCloseToArray() { expect([0.0, 1.1, 2.2]) ≈ [0.0001, 1.1001, 2.2001] expect([0.0, 1.1, 2.2]).to(beCloseTo([0.1, 1.2, 2.3], within: 0.1)) failsWithErrorMessage("expected to be close to <[0.0000, 1.0000]> (each within 0.0001), got <[0.0, 1.1]>") { expect([0.0, 1.1]) ≈ [0.0, 1.0] } failsWithErrorMessage("expected to be close to <[0.2000, 1.2000]> (each within 0.1000), got <[0.0, 1.1]>") { expect([0.0, 1.1]).to(beCloseTo([0.2, 1.2], within: 0.1)) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/BeEmptyTest.swift ================================================ import XCTest import Nimble class BeEmptyTest: XCTestCase { func testBeEmptyPositive() { expect([] as [Int]).to(beEmpty()) expect([1]).toNot(beEmpty()) expect([] as [CInt]).to(beEmpty()) expect([1] as [CInt]).toNot(beEmpty()) expect(NSDictionary() as? [Int:Int]).to(beEmpty()) expect(NSDictionary(object: 1, forKey: 1) as? [Int:Int]).toNot(beEmpty()) expect(Dictionary()).to(beEmpty()) expect(["hi": 1]).toNot(beEmpty()) expect(NSArray() as? [Int]).to(beEmpty()) expect(NSArray(array: [1]) as? [Int]).toNot(beEmpty()) expect(NSSet()).to(beEmpty()) expect(NSSet(array: [1])).toNot(beEmpty()) expect(NSString()).to(beEmpty()) expect(NSString(string: "hello")).toNot(beEmpty()) expect("").to(beEmpty()) expect("foo").toNot(beEmpty()) } func testBeEmptyNegative() { failsWithErrorMessageForNil("expected to be empty, got ") { expect(nil as NSString?).to(beEmpty()) } failsWithErrorMessageForNil("expected to not be empty, got ") { expect(nil as [CInt]?).toNot(beEmpty()) } failsWithErrorMessage("expected to not be empty, got <()>") { expect([]).toNot(beEmpty()) } failsWithErrorMessage("expected to be empty, got <[1]>") { expect([1]).to(beEmpty()) } failsWithErrorMessage("expected to not be empty, got <>") { expect("").toNot(beEmpty()) } failsWithErrorMessage("expected to be empty, got ") { expect("foo").to(beEmpty()) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/BeGreaterThanOrEqualToTest.swift ================================================ import XCTest import Nimble class BeGreaterThanOrEqualToTest: XCTestCase { func testGreaterThanOrEqualTo() { expect(10).to(beGreaterThanOrEqualTo(10)) expect(10).to(beGreaterThanOrEqualTo(2)) expect(1).toNot(beGreaterThanOrEqualTo(2)) expect(NSNumber(int:1)).toNot(beGreaterThanOrEqualTo(2)) expect(NSNumber(int:2)).to(beGreaterThanOrEqualTo(NSNumber(int:2))) expect(1).to(beGreaterThanOrEqualTo(NSNumber(int:0))) failsWithErrorMessage("expected to be greater than or equal to <2>, got <0>") { expect(0).to(beGreaterThanOrEqualTo(2)) return } failsWithErrorMessage("expected to not be greater than or equal to <1>, got <1>") { expect(1).toNot(beGreaterThanOrEqualTo(1)) return } failsWithErrorMessageForNil("expected to be greater than or equal to <-2>, got ") { expect(nil as Int?).to(beGreaterThanOrEqualTo(-2)) } failsWithErrorMessageForNil("expected to not be greater than or equal to <1>, got ") { expect(nil as Int?).toNot(beGreaterThanOrEqualTo(1)) } } func testGreaterThanOrEqualToOperator() { expect(0) >= 0 expect(1) >= 0 expect(NSNumber(int:1)) >= 1 expect(NSNumber(int:1)) >= NSNumber(int:1) failsWithErrorMessage("expected to be greater than or equal to <2>, got <1>") { expect(1) >= 2 return } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/BeGreaterThanTest.swift ================================================ import XCTest import Nimble class BeGreaterThanTest: XCTestCase { func testGreaterThan() { expect(10).to(beGreaterThan(2)) expect(1).toNot(beGreaterThan(2)) expect(NSNumber(int:3)).to(beGreaterThan(2)) expect(NSNumber(int:1)).toNot(beGreaterThan(NSNumber(int:2))) failsWithErrorMessage("expected to be greater than <2>, got <0>") { expect(0).to(beGreaterThan(2)) } failsWithErrorMessage("expected to not be greater than <0>, got <1>") { expect(1).toNot(beGreaterThan(0)) } failsWithErrorMessageForNil("expected to be greater than <-2>, got ") { expect(nil as Int?).to(beGreaterThan(-2)) } failsWithErrorMessageForNil("expected to not be greater than <0>, got ") { expect(nil as Int?).toNot(beGreaterThan(0)) } } func testGreaterThanOperator() { expect(1) > 0 expect(NSNumber(int:1)) > NSNumber(int:0) expect(NSNumber(int:1)) > 0 failsWithErrorMessage("expected to be greater than <2.0000>, got <1.0000>") { expect(1) > 2 return } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/BeIdenticalToObjectTest.swift ================================================ import XCTest import Nimble class BeIdenticalToObjectTest: XCTestCase { private class BeIdenticalToObjectTester {} private let testObjectA = BeIdenticalToObjectTester() private let testObjectB = BeIdenticalToObjectTester() func testBeIdenticalToPositive() { expect(self.testObjectA).to(beIdenticalTo(testObjectA)) } func testBeIdenticalToNegative() { expect(self.testObjectA).toNot(beIdenticalTo(testObjectB)) } func testBeIdenticalToPositiveMessage() { let message = String(format: "expected to be identical to <%p>, got <%p>", unsafeBitCast(testObjectB, Int.self), unsafeBitCast(testObjectA, Int.self)) failsWithErrorMessage(message) { expect(self.testObjectA).to(beIdenticalTo(self.testObjectB)) } } func testBeIdenticalToNegativeMessage() { let message = String(format: "expected to not be identical to <%p>, got <%p>", unsafeBitCast(testObjectA, Int.self), unsafeBitCast(testObjectA, Int.self)) failsWithErrorMessage(message) { expect(self.testObjectA).toNot(beIdenticalTo(self.testObjectA)) } } func testFailsOnNils() { let message1 = String(format: "expected to be identical to <%p>, got nil", unsafeBitCast(testObjectA, Int.self)) failsWithErrorMessageForNil(message1) { expect(nil as BeIdenticalToObjectTester?).to(beIdenticalTo(self.testObjectA)) } let message2 = String(format: "expected to not be identical to <%p>, got nil", unsafeBitCast(testObjectA, Int.self)) failsWithErrorMessageForNil(message2) { expect(nil as BeIdenticalToObjectTester?).toNot(beIdenticalTo(self.testObjectA)) } } func testOperators() { expect(self.testObjectA) === testObjectA expect(self.testObjectA) !== testObjectB } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/BeIdenticalToTest.swift ================================================ import XCTest import Nimble class BeIdenticalToTest: XCTestCase { func testBeIdenticalToPositive() { expect(NSNumber(integer:1)).to(beIdenticalTo(NSNumber(integer:1))) } func testBeIdenticalToNegative() { expect(NSNumber(integer:1)).toNot(beIdenticalTo("yo")) expect([1]).toNot(beIdenticalTo([1])) } func testBeIdenticalToPositiveMessage() { let num1 = NSNumber(integer:1) let num2 = NSNumber(integer:2) let message = NSString(format: "expected to be identical to <%p>, got <%p>", num2, num1) failsWithErrorMessage(message.description) { expect(num1).to(beIdenticalTo(num2)) } } func testBeIdenticalToNegativeMessage() { let value1 = NSArray(array: []) let value2 = NSArray(array: []) let message = NSString(format: "expected to not be identical to <%p>, got <%p>", value2, value1) failsWithErrorMessage(message.description) { expect(value1).toNot(beIdenticalTo(value2)) } } func testOperators() { expect(NSNumber(integer:1)) === NSNumber(integer:1) expect(NSNumber(integer:1)) !== NSNumber(integer:2) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/BeLessThanOrEqualToTest.swift ================================================ import XCTest import Nimble class BeLessThanOrEqualToTest: XCTestCase { func testLessThanOrEqualTo() { expect(10).to(beLessThanOrEqualTo(10)) expect(2).to(beLessThanOrEqualTo(10)) expect(2).toNot(beLessThanOrEqualTo(1)) expect(NSNumber(int:2)).to(beLessThanOrEqualTo(10)) expect(NSNumber(int:2)).toNot(beLessThanOrEqualTo(1)) expect(2).to(beLessThanOrEqualTo(NSNumber(int:10))) expect(2).toNot(beLessThanOrEqualTo(NSNumber(int:1))) failsWithErrorMessage("expected to be less than or equal to <0>, got <2>") { expect(2).to(beLessThanOrEqualTo(0)) return } failsWithErrorMessage("expected to not be less than or equal to <0>, got <0>") { expect(0).toNot(beLessThanOrEqualTo(0)) return } failsWithErrorMessageForNil("expected to be less than or equal to <2>, got ") { expect(nil as Int?).to(beLessThanOrEqualTo(2)) return } failsWithErrorMessageForNil("expected to not be less than or equal to <-2>, got ") { expect(nil as Int?).toNot(beLessThanOrEqualTo(-2)) return } } func testLessThanOrEqualToOperator() { expect(0) <= 1 expect(1) <= 1 failsWithErrorMessage("expected to be less than or equal to <1>, got <2>") { expect(2) <= 1 return } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/BeLessThanTest.swift ================================================ import XCTest import Nimble class BeLessThanTest: XCTestCase { func testLessThan() { expect(2).to(beLessThan(10)) expect(2).toNot(beLessThan(1)) expect(NSNumber(integer:2)).to(beLessThan(10)) expect(NSNumber(integer:2)).toNot(beLessThan(1)) expect(2).to(beLessThan(NSNumber(integer:10))) expect(2).toNot(beLessThan(NSNumber(integer:1))) failsWithErrorMessage("expected to be less than <0>, got <2>") { expect(2).to(beLessThan(0)) } failsWithErrorMessage("expected to not be less than <1>, got <0>") { expect(0).toNot(beLessThan(1)) } failsWithErrorMessageForNil("expected to be less than <2>, got ") { expect(nil as Int?).to(beLessThan(2)) } failsWithErrorMessageForNil("expected to not be less than <-1>, got ") { expect(nil as Int?).toNot(beLessThan(-1)) } } func testLessThanOperator() { expect(0) < 1 expect(NSNumber(int:0)) < 1 failsWithErrorMessage("expected to be less than <1.0000>, got <2.0000>") { expect(2) < 1 return } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/BeLogicalTest.swift ================================================ import XCTest import Nimble enum ConvertsToBool : BooleanType, CustomStringConvertible { case TrueLike, FalseLike var boolValue : Bool { switch self { case .TrueLike: return true case .FalseLike: return false } } var description : String { switch self { case .TrueLike: return "TrueLike" case .FalseLike: return "FalseLike" } } } class BeTruthyTest : XCTestCase { func testShouldMatchNonNilTypes() { expect(true as Bool?).to(beTruthy()) expect(1 as Int?).to(beTruthy()) } func testShouldMatchTrue() { expect(true).to(beTruthy()) failsWithErrorMessage("expected to not be truthy, got ") { expect(true).toNot(beTruthy()) } } func testShouldNotMatchNilTypes() { expect(false as Bool?).toNot(beTruthy()) expect(nil as Bool?).toNot(beTruthy()) expect(nil as Int?).toNot(beTruthy()) } func testShouldNotMatchFalse() { expect(false).toNot(beTruthy()) failsWithErrorMessage("expected to be truthy, got ") { expect(false).to(beTruthy()) } } func testShouldNotMatchNilBools() { expect(nil as Bool?).toNot(beTruthy()) failsWithErrorMessage("expected to be truthy, got ") { expect(nil as Bool?).to(beTruthy()) } } func testShouldMatchBoolConvertibleTypesThatConvertToTrue() { expect(ConvertsToBool.TrueLike).to(beTruthy()) failsWithErrorMessage("expected to not be truthy, got ") { expect(ConvertsToBool.TrueLike).toNot(beTruthy()) } } func testShouldNotMatchBoolConvertibleTypesThatConvertToFalse() { expect(ConvertsToBool.FalseLike).toNot(beTruthy()) failsWithErrorMessage("expected to be truthy, got ") { expect(ConvertsToBool.FalseLike).to(beTruthy()) } } } class BeTrueTest : XCTestCase { func testShouldMatchTrue() { expect(true).to(beTrue()) failsWithErrorMessage("expected to not be true, got ") { expect(true).toNot(beTrue()) } } func testShouldNotMatchFalse() { expect(false).toNot(beTrue()) failsWithErrorMessage("expected to be true, got ") { expect(false).to(beTrue()) } } func testShouldNotMatchNilBools() { failsWithErrorMessageForNil("expected to not be true, got ") { expect(nil as Bool?).toNot(beTrue()) } failsWithErrorMessageForNil("expected to be true, got ") { expect(nil as Bool?).to(beTrue()) } } } class BeFalsyTest : XCTestCase { func testShouldMatchNilTypes() { expect(false as Bool?).to(beFalsy()) expect(nil as Bool?).to(beFalsy()) expect(nil as Int?).to(beFalsy()) } func testShouldNotMatchTrue() { expect(true).toNot(beFalsy()) failsWithErrorMessage("expected to be falsy, got ") { expect(true).to(beFalsy()) } } func testShouldNotMatchNonNilTypes() { expect(true as Bool?).toNot(beFalsy()) expect(1 as Int?).toNot(beFalsy()) } func testShouldMatchFalse() { expect(false).to(beFalsy()) failsWithErrorMessage("expected to not be falsy, got ") { expect(false).toNot(beFalsy()) } } func testShouldMatchNilBools() { expect(nil as Bool?).to(beFalsy()) failsWithErrorMessage("expected to not be falsy, got ") { expect(nil as Bool?).toNot(beFalsy()) } } } class BeFalseTest : XCTestCase { func testShouldNotMatchTrue() { expect(true).toNot(beFalse()) failsWithErrorMessage("expected to be false, got ") { expect(true).to(beFalse()) } } func testShouldMatchFalse() { expect(false).to(beFalse()) failsWithErrorMessage("expected to not be false, got ") { expect(false).toNot(beFalse()) } } func testShouldNotMatchNilBools() { failsWithErrorMessageForNil("expected to be false, got ") { expect(nil as Bool?).to(beFalse()) } failsWithErrorMessageForNil("expected to not be false, got ") { expect(nil as Bool?).toNot(beFalse()) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/BeNilTest.swift ================================================ import XCTest import Nimble class BeNilTest: XCTestCase { func producesNil() -> Array? { return nil } func testBeNil() { expect(nil as Int?).to(beNil()) expect(1 as Int?).toNot(beNil()) expect(self.producesNil()).to(beNil()) failsWithErrorMessage("expected to not be nil, got ") { expect(nil as Int?).toNot(beNil()) } failsWithErrorMessage("expected to be nil, got <1>") { expect(1 as Int?).to(beNil()) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/BeginWithTest.swift ================================================ import XCTest import Nimble class BeginWithTest: XCTestCase { func testPositiveMatches() { expect([1, 2, 3]).to(beginWith(1)) expect([1, 2, 3]).toNot(beginWith(2)) expect("foobar").to(beginWith("foo")) expect("foobar").toNot(beginWith("oo")) expect(NSString(string: "foobar").description).to(beginWith("foo")) expect(NSString(string: "foobar").description).toNot(beginWith("oo")) expect(NSArray(array: ["a", "b"])).to(beginWith("a")) expect(NSArray(array: ["a", "b"])).toNot(beginWith("b")) } func testNegativeMatches() { failsWithErrorMessageForNil("expected to begin with , got ") { expect(nil as NSArray?).to(beginWith("b")) } failsWithErrorMessageForNil("expected to not begin with , got ") { expect(nil as NSArray?).toNot(beginWith("b")) } failsWithErrorMessage("expected to begin with <2>, got <[1, 2, 3]>") { expect([1, 2, 3]).to(beginWith(2)) } failsWithErrorMessage("expected to not begin with <1>, got <[1, 2, 3]>") { expect([1, 2, 3]).toNot(beginWith(1)) } failsWithErrorMessage("expected to begin with , got ") { expect("batman").to(beginWith("atm")) } failsWithErrorMessage("expected to not begin with , got ") { expect("batman").toNot(beginWith("bat")) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/ContainTest.swift ================================================ import XCTest import Nimble class ContainTest: XCTestCase { func testContain() { expect([1, 2, 3]).to(contain(1)) expect([1, 2, 3] as [CInt]).to(contain(1 as CInt)) expect([1, 2, 3] as Array).to(contain(1 as CInt)) expect(["foo", "bar", "baz"]).to(contain("baz")) expect([1, 2, 3]).toNot(contain(4)) expect(["foo", "bar", "baz"]).toNot(contain("ba")) expect(NSArray(array: ["a"])).to(contain("a")) expect(NSArray(array: ["a"])).toNot(contain("b")) expect(NSArray(object: 1) as NSArray?).to(contain(1)) failsWithErrorMessage("expected to contain , got <[\"a\", \"b\", \"c\"]>") { expect(["a", "b", "c"]).to(contain("bar")) } failsWithErrorMessage("expected to not contain , got <[\"a\", \"b\", \"c\"]>") { expect(["a", "b", "c"]).toNot(contain("b")) } failsWithErrorMessageForNil("expected to contain , got ") { expect(nil as [String]?).to(contain("bar")) } failsWithErrorMessageForNil("expected to not contain , got ") { expect(nil as [String]?).toNot(contain("b")) } } func testContainSubstring() { expect("foo").to(contain("o")) expect("foo").to(contain("oo")) expect("foo").toNot(contain("z")) expect("foo").toNot(contain("zz")) failsWithErrorMessage("expected to contain , got ") { expect("foo").to(contain("bar")) } failsWithErrorMessage("expected to not contain , got ") { expect("foo").toNot(contain("oo")) } } func testContainObjCSubstring() { let str = NSString(string: "foo") expect(str).to(contain(NSString(string: "o"))) expect(str).to(contain(NSString(string: "oo"))) expect(str).toNot(contain(NSString(string: "z"))) expect(str).toNot(contain(NSString(string: "zz"))) } func testVariadicArguments() { expect([1, 2, 3]).to(contain(1, 2)) expect([1, 2, 3]).toNot(contain(1, 4)) failsWithErrorMessage("expected to contain , got <[\"a\", \"b\", \"c\"]>") { expect(["a", "b", "c"]).to(contain("a", "bar")) } failsWithErrorMessage("expected to not contain , got <[\"a\", \"b\", \"c\"]>") { expect(["a", "b", "c"]).toNot(contain("bar", "b")) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/EndWithTest.swift ================================================ import XCTest import Nimble class EndWithTest: XCTestCase { func testEndWithPositives() { expect([1, 2, 3]).to(endWith(3)) expect([1, 2, 3]).toNot(endWith(2)) expect("foobar").to(endWith("bar")) expect("foobar").toNot(endWith("oo")) expect(NSString(string: "foobar").description).to(endWith("bar")) expect(NSString(string: "foobar").description).toNot(endWith("oo")) expect(NSArray(array: ["a", "b"])).to(endWith("b")) expect(NSArray(array: ["a", "b"])).toNot(endWith("a")) } func testEndWithNegatives() { failsWithErrorMessageForNil("expected to end with <2>, got ") { expect(nil as [Int]?).to(endWith(2)) } failsWithErrorMessageForNil("expected to not end with <2>, got ") { expect(nil as [Int]?).toNot(endWith(2)) } failsWithErrorMessage("expected to end with <2>, got <[1, 2, 3]>") { expect([1, 2, 3]).to(endWith(2)) } failsWithErrorMessage("expected to not end with <3>, got <[1, 2, 3]>") { expect([1, 2, 3]).toNot(endWith(3)) } failsWithErrorMessage("expected to end with , got ") { expect("batman").to(endWith("atm")) } failsWithErrorMessage("expected to not end with , got ") { expect("batman").toNot(endWith("man")) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/EqualTest.swift ================================================ import XCTest import Nimble class EqualTest: XCTestCase { func testEquality() { expect(1 as CInt).to(equal(1 as CInt)) expect(1 as CInt).to(equal(1)) expect(1).to(equal(1)) expect("hello").to(equal("hello")) expect("hello").toNot(equal("world")) expect { 1 }.to(equal(1)) failsWithErrorMessage("expected to equal , got ") { expect("hello").to(equal("world")) } failsWithErrorMessage("expected to not equal , got ") { expect("hello").toNot(equal("hello")) } } func testArrayEquality() { expect([1, 2, 3]).to(equal([1, 2, 3])) expect([1, 2, 3]).toNot(equal([1, 2])) expect([1, 2, 3]).toNot(equal([1, 2, 4])) let array1: Array = [1, 2, 3] let array2: Array = [1, 2, 3] expect(array1).to(equal(array2)) expect(array1).to(equal([1, 2, 3])) expect(array1).toNot(equal([1, 2] as Array)) expect(NSArray(array: [1, 2, 3])).to(equal(NSArray(array: [1, 2, 3]))) failsWithErrorMessage("expected to equal <[1, 2]>, got <[1, 2, 3]>") { expect([1, 2, 3]).to(equal([1, 2])) } } func testSetEquality() { expect(Set([1, 2])).to(equal(Set([1, 2]))) expect(Set()).to(equal(Set())) expect(Set()) == Set() expect(Set([1, 2])) != Set() failsWithErrorMessageForNil("expected to equal <[1, 2]>, got ") { expect(nil as Set?).to(equal(Set([1, 2]))) } failsWithErrorMessage("expected to equal <[1, 2, 3]>, got <[2, 3]>, missing <[1]>") { expect(Set([2, 3])).to(equal(Set([1, 2, 3]))) } failsWithErrorMessage("expected to equal <[1, 2, 3]>, got <[1, 2, 3, 4]>, extra <[4]>") { expect(Set([1, 2, 3, 4])).to(equal(Set([1, 2, 3]))) } failsWithErrorMessage("expected to equal <[1, 2, 3]>, got <[2, 3, 4]>, missing <[1]>, extra <[4]>") { expect(Set([2, 3, 4])).to(equal(Set([1, 2, 3]))) } failsWithErrorMessage("expected to equal <[1, 2, 3]>, got <[2, 3, 4]>, missing <[1]>, extra <[4]>") { expect(Set([2, 3, 4])) == Set([1, 2, 3]) } failsWithErrorMessage("expected to not equal <[1, 2, 3]>, got <[1, 2, 3]>") { expect(Set([1, 2, 3])) != Set([1, 2, 3]) } } func testDoesNotMatchNils() { failsWithErrorMessageForNil("expected to equal , got ") { expect(nil as String?).to(equal(nil as String?)) } failsWithErrorMessageForNil("expected to not equal , got ") { expect("foo").toNot(equal(nil as String?)) } failsWithErrorMessageForNil("expected to not equal , got ") { expect(nil as String?).toNot(equal("bar")) } failsWithErrorMessageForNil("expected to equal , got ") { expect(nil as [Int]?).to(equal(nil as [Int]?)) } failsWithErrorMessageForNil("expected to not equal <[1]>, got ") { expect(nil as [Int]?).toNot(equal([1])) } failsWithErrorMessageForNil("expected to not equal , got <[1]>") { expect([1]).toNot(equal(nil as [Int]?)) } failsWithErrorMessageForNil("expected to equal , got ") { expect(nil as [Int: Int]?).to(equal(nil as [Int: Int]?)) } failsWithErrorMessageForNil("expected to not equal <[1: 1]>, got ") { expect(nil as [Int: Int]?).toNot(equal([1: 1])) } failsWithErrorMessageForNil("expected to not equal , got <[1: 1]>") { expect([1: 1]).toNot(equal(nil as [Int: Int]?)) } } func testDictionaryEquality() { expect(["foo": "bar"]).to(equal(["foo": "bar"])) expect(["foo": "bar"]).toNot(equal(["foo": "baz"])) let actual = ["foo": "bar"] let expected = ["foo": "bar"] let unexpected = ["foo": "baz"] expect(actual).to(equal(expected)) expect(actual).toNot(equal(unexpected)) expect(NSDictionary(object: "bar", forKey: "foo")).to(equal(["foo": "bar"])) expect(NSDictionary(object: "bar", forKey: "foo")).to(equal(expected)) } func testNSObjectEquality() { expect(NSNumber(integer:1)).to(equal(NSNumber(integer:1))) expect(NSNumber(integer:1)) == NSNumber(integer:1) expect(NSNumber(integer:1)) != NSNumber(integer:2) expect { NSNumber(integer:1) }.to(equal(1)) } func testOperatorEquality() { expect("foo") == "foo" expect("foo") != "bar" failsWithErrorMessage("expected to equal , got ") { expect("hello") == "world" return } failsWithErrorMessage("expected to not equal , got ") { expect("hello") != "hello" return } } func testOperatorEqualityWithArrays() { let array1: Array = [1, 2, 3] let array2: Array = [1, 2, 3] let array3: Array = [1, 2] expect(array1) == array2 expect(array1) != array3 } func testOperatorEqualityWithDictionaries() { let dict1 = ["foo": "bar"] let dict2 = ["foo": "bar"] let dict3 = ["foo": "baz"] expect(dict1) == dict2 expect(dict1) != dict3 } func testOptionalEquality() { expect(1 as CInt?).to(equal(1)) expect(1 as CInt?).to(equal(1 as CInt?)) expect(1).toNot(equal(nil)) } func testArrayOfOptionalsEquality() { let array1: Array = [1, nil, 3] let array2: Array = [nil, 2, 3] let array3: Array = [1, nil, 3] expect(array1).toNot(equal(array2)) expect(array1).to(equal(array3)) expect(array2).toNot(equal(array3)) let allNils1: Array = [nil, nil, nil, nil] let allNils2: Array = [nil, nil, nil, nil] let notReallyAllNils: Array = [nil, nil, nil, "turtles"] expect(allNils1).to(equal(allNils2)) expect(allNils1).toNot(equal(notReallyAllNils)) let noNils1: Array = [1, 2, 3, 4, 5] let noNils2: Array = [1, 3, 5, 7, 9] expect(noNils1).toNot(equal(noNils2)) failsWithErrorMessage("expected to equal <[Optional(1), nil]>, got <[nil, Optional(2)]>") { let arrayOfOptionalInts: Array = [nil, 2] let anotherArrayOfOptionalInts: Array = [1, nil] expect(arrayOfOptionalInts).to(equal(anotherArrayOfOptionalInts)) return } } func testDictionariesWithDifferentSequences() { // see: https://github.com/Quick/Nimble/issues/61 // these dictionaries generate different orderings of sequences. let result = ["how":1, "think":1, "didnt":2, "because":1, "interesting":1, "always":1, "right":1, "such":1, "to":3, "say":1, "cool":1, "you":1, "weather":3, "be":1, "went":1, "was":2, "sometimes":1, "and":3, "mind":1, "rain":1, "whole":1, "everything":1, "weather.":1, "down":1, "kind":1, "mood.":1, "it":2, "everyday":1, "might":1, "more":1, "have":2, "person":1, "could":1, "tenth":2, "night":1, "write":1, "Youd":1, "affects":1, "of":3, "Who":1, "us":1, "an":1, "I":4, "my":1, "much":2, "wrong.":1, "peacefully.":1, "amazing":3, "would":4, "just":1, "grade.":1, "Its":2, "The":2, "had":1, "that":1, "the":5, "best":1, "but":1, "essay":1, "for":1, "summer":2, "your":1, "grade":1, "vary":1, "pretty":1, "at":1, "rain.":1, "about":1, "allow":1, "thought":1, "in":1, "sleep":1, "a":1, "hot":1, "really":1, "beach":1, "life.":1, "we":1, "although":1] let storyCount = ["The":2, "summer":2, "of":3, "tenth":2, "grade":1, "was":2, "the":5, "best":1, "my":1, "life.":1, "I":4, "went":1, "to":3, "beach":1, "everyday":1, "and":3, "we":1, "had":1, "amazing":3, "weather.":1, "weather":3, "didnt":2, "really":1, "vary":1, "much":2, "always":1, "pretty":1, "hot":1, "although":1, "sometimes":1, "at":1, "night":1, "it":2, "would":4, "rain.":1, "mind":1, "rain":1, "because":1, "cool":1, "everything":1, "down":1, "allow":1, "us":1, "sleep":1, "peacefully.":1, "Its":2, "how":1, "affects":1, "your":1, "mood.":1, "Who":1, "have":2, "thought":1, "that":1, "could":1, "write":1, "a":1, "whole":1, "essay":1, "just":1, "about":1, "in":1, "grade.":1, "kind":1, "right":1, "Youd":1, "think":1, "for":1, "such":1, "an":1, "interesting":1, "person":1, "might":1, "more":1, "say":1, "but":1, "you":1, "be":1, "wrong.":1] expect(result).to(equal(storyCount)) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/HaveCountTest.swift ================================================ import XCTest import Nimble class HaveCountTest: XCTestCase { func testHaveCountForArray() { expect([1, 2, 3]).to(haveCount(3)) expect([1, 2, 3]).notTo(haveCount(1)) failsWithErrorMessage("expected to have [1, 2, 3] with count 1, got 3") { expect([1, 2, 3]).to(haveCount(1)) } failsWithErrorMessage("expected to not have [1, 2, 3] with count 3, got 3") { expect([1, 2, 3]).notTo(haveCount(3)) } } func testHaveCountForDictionary() { let dictionary = ["1":1, "2":2, "3":3] expect(dictionary).to(haveCount(3)) expect(dictionary).notTo(haveCount(1)) failsWithErrorMessage("expected to have \(dictionary) with count 1, got 3") { expect(dictionary).to(haveCount(1)) } failsWithErrorMessage("expected to not have \(dictionary) with count 3, got 3") { expect(dictionary).notTo(haveCount(3)) } } func testHaveCountForSet() { let set = Set([1, 2, 3]) expect(set).to(haveCount(3)) expect(set).notTo(haveCount(1)) failsWithErrorMessage("expected to have \(set) with count 1, got 3") { expect(set).to(haveCount(1)) } failsWithErrorMessage("expected to not have \(set) with count 3, got 3") { expect(set).notTo(haveCount(3)) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/MatchTest.swift ================================================ import XCTest import Nimble class MatchTest:XCTestCase { func testMatchPositive() { expect("11:14").to(match("\\d{2}:\\d{2}")) } func testMatchNegative() { expect("hello").toNot(match("\\d{2}:\\d{2}")) } func testMatchPositiveMessage() { let message = "expected to match <\\d{2}:\\d{2}>, got " failsWithErrorMessage(message) { expect("hello").to(match("\\d{2}:\\d{2}")) } } func testMatchNegativeMessage() { let message = "expected to not match <\\d{2}:\\d{2}>, got <11:14>" failsWithErrorMessage(message) { expect("11:14").toNot(match("\\d{2}:\\d{2}")) } } func testMatchNils() { failsWithErrorMessageForNil("expected to match <\\d{2}:\\d{2}>, got ") { expect(nil as String?).to(match("\\d{2}:\\d{2}")) } failsWithErrorMessageForNil("expected to not match <\\d{2}:\\d{2}>, got ") { expect(nil as String?).toNot(match("\\d{2}:\\d{2}")) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/RaisesExceptionTest.swift ================================================ import XCTest import Nimble class RaisesExceptionTest: XCTestCase { var anException = NSException(name: "laugh", reason: "Lulz", userInfo: ["key": "value"]) func testPositiveMatches() { expect { self.anException.raise() }.to(raiseException()) expect { self.anException.raise() }.to(raiseException(named: "laugh")) expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz")) expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz", userInfo: ["key": "value"])) } func testPositiveMatchesWithClosures() { expect { self.anException.raise() }.to(raiseException { (exception: NSException) in expect(exception.name).to(equal("laugh")) }) expect { self.anException.raise() }.to(raiseException(named: "laugh") { (exception: NSException) in expect(exception.name).to(beginWith("lau")) }) expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz") { (exception: NSException) in expect(exception.name).to(beginWith("lau")) }) expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz", userInfo: ["key": "value"]) { (exception: NSException) in expect(exception.name).to(beginWith("lau")) }) expect { self.anException.raise() }.to(raiseException(named: "laugh") { (exception: NSException) in expect(exception.name).toNot(beginWith("as")) }) expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz") { (exception: NSException) in expect(exception.name).toNot(beginWith("df")) }) expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz", userInfo: ["key": "value"]) { (exception: NSException) in expect(exception.name).toNot(beginWith("as")) }) } func testNegativeMatches() { failsWithErrorMessage("expected to raise exception with name , got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.to(raiseException(named: "foo")) } failsWithErrorMessage("expected to raise exception with name with reason , got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "bar")) } failsWithErrorMessage( "expected to raise exception with name with reason with userInfo <{k = v;}>, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz", userInfo: ["k": "v"])) } failsWithErrorMessage("expected to raise any exception, got no exception") { expect { self.anException }.to(raiseException()) } failsWithErrorMessage("expected to not raise any exception, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.toNot(raiseException()) } failsWithErrorMessage("expected to raise exception with name with reason , got no exception") { expect { self.anException }.to(raiseException(named: "laugh", reason: "Lulz")) } failsWithErrorMessage("expected to raise exception with name with reason , got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.to(raiseException(named: "bar", reason: "Lulz")) } failsWithErrorMessage("expected to not raise exception with name , got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.toNot(raiseException(named: "laugh")) } failsWithErrorMessage("expected to not raise exception with name with reason , got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.toNot(raiseException(named: "laugh", reason: "Lulz")) } failsWithErrorMessage("expected to not raise exception with name with reason with userInfo <{key = value;}>, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.toNot(raiseException(named: "laugh", reason: "Lulz", userInfo: ["key": "value"])) } } func testNegativeMatchesDoNotCallClosureWithoutException() { failsWithErrorMessage("expected to raise exception that satisfies block, got no exception") { expect { self.anException }.to(raiseException { (exception: NSException) in expect(exception.name).to(equal("foo")) }) } failsWithErrorMessage("expected to raise exception with name that satisfies block, got no exception") { expect { self.anException }.to(raiseException(named: "foo") { (exception: NSException) in expect(exception.name).to(equal("foo")) }) } failsWithErrorMessage("expected to raise exception with name with reason that satisfies block, got no exception") { expect { self.anException }.to(raiseException(named: "foo", reason: "ha") { (exception: NSException) in expect(exception.name).to(equal("foo")) }) } failsWithErrorMessage("expected to raise exception with name with reason with userInfo <{}> that satisfies block, got no exception") { expect { self.anException }.to(raiseException(named: "foo", reason: "Lulz", userInfo: [:]) { (exception: NSException) in expect(exception.name).to(equal("foo")) }) } failsWithErrorMessage("expected to not raise any exception, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.toNot(raiseException()) } } func testNegativeMatchesWithClosure() { failsWithErrorMessage("expected to raise exception that satisfies block, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.to(raiseException { (exception: NSException) in expect(exception.name).to(equal("foo")) }) } let innerFailureMessage = "expected to begin with , got " failsWithErrorMessage([innerFailureMessage, "expected to raise exception with name that satisfies block, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }"]) { expect { self.anException.raise() }.to(raiseException(named: "laugh") { (exception: NSException) in expect(exception.name).to(beginWith("fo")) }) } failsWithErrorMessage([innerFailureMessage, "expected to raise exception with name that satisfies block, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }"]) { expect { self.anException.raise() }.to(raiseException(named: "lol") { (exception: NSException) in expect(exception.name).to(beginWith("fo")) }) } failsWithErrorMessage([innerFailureMessage, "expected to raise exception with name with reason that satisfies block, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }"]) { expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz") { (exception: NSException) in expect(exception.name).to(beginWith("fo")) }) } failsWithErrorMessage([innerFailureMessage, "expected to raise exception with name with reason that satisfies block, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }"]) { expect { self.anException.raise() }.to(raiseException(named: "lol", reason: "wrong") { (exception: NSException) in expect(exception.name).to(beginWith("fo")) }) } failsWithErrorMessage([innerFailureMessage, "expected to raise exception with name with reason with userInfo <{key = value;}> that satisfies block, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }"]) { expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz", userInfo: ["key": "value"]) { (exception: NSException) in expect(exception.name).to(beginWith("fo")) }) } failsWithErrorMessage([innerFailureMessage, "expected to raise exception with name with reason with userInfo <{}> that satisfies block, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }"]) { expect { self.anException.raise() }.to(raiseException(named: "lol", reason: "Lulz", userInfo: [:]) { (exception: NSException) in expect(exception.name).to(beginWith("fo")) }) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/SatisfyAnyOfTest.swift ================================================ import XCTest import Nimble class SatisfyAnyOfTest: XCTestCase { func testSatisfyAnyOf() { expect(2).to(satisfyAnyOf(equal(2), equal(3))) expect(2).toNot(satisfyAnyOf(equal(3), equal("turtles"))) expect([1,2,3]).to(satisfyAnyOf(equal([1,2,3]), allPass({$0 < 4}), haveCount(3))) expect("turtle").toNot(satisfyAnyOf(contain("a"), endWith("magic"))) expect(82.0).toNot(satisfyAnyOf(beLessThan(10.5), beGreaterThan(100.75), beCloseTo(50.1))) expect(false).to(satisfyAnyOf(beTrue(), beFalse())) expect(true).to(satisfyAnyOf(beTruthy(), beFalsy())) failsWithErrorMessage( "expected to match one of: {equal <3>}, or {equal <4>}, or {equal <5>}, got 2") { expect(2).to(satisfyAnyOf(equal(3), equal(4), equal(5))) } failsWithErrorMessage( "expected to match one of: {all be less than 4, but failed first at element <5> in <[5, 6, 7]>}, or {equal <[1, 2, 3, 4]>}, got [5, 6, 7]") { expect([5,6,7]).to(satisfyAnyOf(allPass("be less than 4", {$0 < 4}), equal([1,2,3,4]))) } failsWithErrorMessage( "expected to match one of: {be true}, got false") { expect(false).to(satisfyAnyOf(beTrue())) } failsWithErrorMessage( "expected to not match one of: {be less than <10.5000>}, or {be greater than <100.7500>}, or {be close to <50.1000> (within 0.0001)}, got 50.10001") { expect(50.10001).toNot(satisfyAnyOf(beLessThan(10.5), beGreaterThan(100.75), beCloseTo(50.1))) } } func testOperatorOr() { expect(2).to(equal(2) || equal(3)) expect(2).toNot(equal(3) || equal("turtles")) expect("turtle").toNot(contain("a") || endWith("magic")) expect(82.0).toNot(beLessThan(10.5) || beGreaterThan(100.75)) expect(false).to(beTrue() || beFalse()) expect(true).to(beTruthy() || beFalsy()) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/Matchers/ThrowErrorTest.swift ================================================ import XCTest import Nimble enum Error : ErrorType { case Laugh case Cry } enum EquatableError : ErrorType { case Parameterized(x: Int) } extension EquatableError : Equatable { } func ==(lhs: EquatableError, rhs: EquatableError) -> Bool { switch (lhs, rhs) { case (.Parameterized(let l), .Parameterized(let r)): return l == r } } enum CustomDebugStringConvertibleError : ErrorType { case A case B } extension CustomDebugStringConvertibleError : CustomDebugStringConvertible { var debugDescription : String { return "code=\(_code)" } } class ThrowErrorTest: XCTestCase { func testPositiveMatches() { expect { throw Error.Laugh }.to(throwError()) expect { throw Error.Laugh }.to(throwError(Error.Laugh)) expect { throw Error.Laugh }.to(throwError(errorType: Error.self)) expect { throw EquatableError.Parameterized(x: 1) }.to(throwError(EquatableError.Parameterized(x: 1))) } func testPositiveMatchesWithClosures() { // Generic typed closure expect { throw EquatableError.Parameterized(x: 42) }.to(throwError { error in guard case EquatableError.Parameterized(let x) = error else { fail(); return } expect(x) >= 1 }) // Explicit typed closure expect { throw EquatableError.Parameterized(x: 42) }.to(throwError { (error: EquatableError) in guard case .Parameterized(let x) = error else { fail(); return } expect(x) >= 1 }) // Typed closure over errorType argument expect { throw EquatableError.Parameterized(x: 42) }.to(throwError(errorType: EquatableError.self) { error in guard case .Parameterized(let x) = error else { fail(); return } expect(x) >= 1 }) // Typed closure over error argument expect { throw Error.Laugh }.to(throwError(Error.Laugh) { (error: Error) in expect(error._domain).to(beginWith("Nim")) }) // Typed closure over error argument expect { throw Error.Laugh }.to(throwError(Error.Laugh) { (error: Error) in expect(error._domain).toNot(beginWith("as")) }) } func testNegativeMatches() { // Same case, different arguments failsWithErrorMessage("expected to throw error , got ") { expect { throw EquatableError.Parameterized(x: 1) }.to(throwError(EquatableError.Parameterized(x: 2))) } // Same case, different arguments failsWithErrorMessage("expected to throw error , got ") { expect { throw EquatableError.Parameterized(x: 1) }.to(throwError(EquatableError.Parameterized(x: 2))) } // Different case failsWithErrorMessage("expected to throw error , got ") { expect { throw Error.Laugh }.to(throwError(Error.Cry)) } // Different case with closure failsWithErrorMessage("expected to throw error that satisfies block, got ") { expect { throw Error.Laugh }.to(throwError(Error.Cry) { _ in return }) } // Different case, implementing CustomDebugStringConvertible failsWithErrorMessage("expected to throw error , got ") { expect { throw CustomDebugStringConvertibleError.A }.to(throwError(CustomDebugStringConvertibleError.B)) } } func testPositiveNegatedMatches() { // No error at all expect { return }.toNot(throwError()) // Different case expect { throw Error.Laugh }.toNot(throwError(Error.Cry)) } func testNegativeNegatedMatches() { // No error at all failsWithErrorMessage("expected to not throw any error, got ") { expect { throw Error.Laugh }.toNot(throwError()) } // Different error failsWithErrorMessage("expected to not throw error , got ") { expect { throw Error.Laugh }.toNot(throwError(Error.Laugh)) } } func testNegativeMatchesDoNotCallClosureWithoutError() { failsWithErrorMessage("expected to throw error that satisfies block, got no error") { expect { return }.to(throwError { error in fail() }) } failsWithErrorMessage("expected to throw error that satisfies block, got no error") { expect { return }.to(throwError(Error.Laugh) { error in fail() }) } } func testNegativeMatchesWithClosure() { let innerFailureMessage = "expected to equal , got " let closure = { (error: Error) in expect(error._domain).to(equal("foo")) } failsWithErrorMessage([innerFailureMessage, "expected to throw error from type that satisfies block, got "]) { expect { throw Error.Laugh }.to(throwError(closure: closure)) } failsWithErrorMessage([innerFailureMessage, "expected to throw error that satisfies block, got "]) { expect { throw Error.Laugh }.to(throwError(Error.Laugh, closure: closure)) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/SynchronousTests.swift ================================================ import XCTest import Nimble class SynchronousTest: XCTestCase { let errorToThrow = NSError(domain: NSInternalInconsistencyException, code: 42, userInfo: nil) private func doThrowError() throws -> Int { throw errorToThrow } func testFailAlwaysFails() { failsWithErrorMessage("My error message") { fail("My error message") } failsWithErrorMessage("fail() always fails") { fail() } } func testUnexpectedErrorsThrownFails() { failsWithErrorMessage("expected to equal <1>, got an unexpected error thrown: <\(errorToThrow)>") { expect { try self.doThrowError() }.to(equal(1)) } failsWithErrorMessage("expected to not equal <1>, got an unexpected error thrown: <\(errorToThrow)>") { expect { try self.doThrowError() }.toNot(equal(1)) } } func testToMatchesIfMatcherReturnsTrue() { expect(1).to(MatcherFunc { expr, failure in true }) expect{1}.to(MatcherFunc { expr, failure in true }) } func testToProvidesActualValueExpression() { var value: Int? expect(1).to(MatcherFunc { expr, failure in value = try expr.evaluate(); return true }) expect(value).to(equal(1)) } func testToProvidesAMemoizedActualValueExpression() { var callCount = 0 expect{ callCount++ }.to(MatcherFunc { expr, failure in try expr.evaluate() try expr.evaluate() return true }) expect(callCount).to(equal(1)) } func testToProvidesAMemoizedActualValueExpressionIsEvaluatedAtMatcherControl() { var callCount = 0 expect{ callCount++ }.to(MatcherFunc { expr, failure in expect(callCount).to(equal(0)) try expr.evaluate() return true }) expect(callCount).to(equal(1)) } func testToMatchAgainstLazyProperties() { expect(ObjectWithLazyProperty().value).to(equal("hello")) expect(ObjectWithLazyProperty().value).toNot(equal("world")) expect(ObjectWithLazyProperty().anotherValue).to(equal("world")) expect(ObjectWithLazyProperty().anotherValue).toNot(equal("hello")) } // repeated tests from to() for toNot() func testToNotMatchesIfMatcherReturnsTrue() { expect(1).toNot(MatcherFunc { expr, failure in false }) expect{1}.toNot(MatcherFunc { expr, failure in false }) } func testToNotProvidesActualValueExpression() { var value: Int? expect(1).toNot(MatcherFunc { expr, failure in value = try expr.evaluate(); return false }) expect(value).to(equal(1)) } func testToNotProvidesAMemoizedActualValueExpression() { var callCount = 0 expect{ callCount++ }.toNot(MatcherFunc { expr, failure in try expr.evaluate() try expr.evaluate() return false }) expect(callCount).to(equal(1)) } func testToNotProvidesAMemoizedActualValueExpressionIsEvaluatedAtMatcherControl() { var callCount = 0 expect{ callCount++ }.toNot(MatcherFunc { expr, failure in expect(callCount).to(equal(0)) try expr.evaluate() return false }) expect(callCount).to(equal(1)) } func testToNotNegativeMatches() { failsWithErrorMessage("expected to not match, got <1>") { expect(1).toNot(MatcherFunc { expr, failure in true }) } } func testNotToMatchesLikeToNot() { expect(1).notTo(MatcherFunc { expr, failure in false }) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/UserDescriptionTest.swift ================================================ import XCTest import Nimble class UserDescriptionTest: XCTestCase { func testToMatcher_CustomFailureMessage() { failsWithErrorMessage( "These aren't equal!\n" + "expected to match, got <1>") { expect(1).to(MatcherFunc { expr, failure in false }, description: "These aren't equal!") } } func testNotToMatcher_CustomFailureMessage() { failsWithErrorMessage( "These aren't equal!\n" + "expected to not match, got <1>") { expect(1).notTo(MatcherFunc { expr, failure in true }, description: "These aren't equal!") } } func testToNotMatcher_CustomFailureMessage() { failsWithErrorMessage( "These aren't equal!\n" + "expected to not match, got <1>") { expect(1).toNot(MatcherFunc { expr, failure in true }, description: "These aren't equal!") } } func testToEventuallyMatch_CustomFailureMessage() { failsWithErrorMessage( "These aren't eventually equal!\n" + "expected to eventually equal <1>, got <0>") { expect { 0 }.toEventually(equal(1), description: "These aren't eventually equal!") } } func testToEventuallyNotMatch_CustomFailureMessage() { failsWithErrorMessage( "These are eventually equal!\n" + "expected to eventually not equal <1>, got <1>") { expect { 1 }.toEventuallyNot(equal(1), description: "These are eventually equal!") } } func testToNotEventuallyMatch_CustomFailureMessage() { failsWithErrorMessage( "These are eventually equal!\n" + "expected to eventually not equal <1>, got <1>") { expect { 1 }.toEventuallyNot(equal(1), description: "These are eventually equal!") } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/Nimble-OSXTests-Bridging-Header.h ================================================ // // Use this file to import your target's public headers that you would like to expose to Swift. // ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/NimbleSpecHelper.h ================================================ @import Nimble; #import "NimbleTests-Swift.h" // Use this when you want to verify the failure message for when an expectation fails #define expectFailureMessage(MSG, BLOCK) \ [NimbleHelper expectFailureMessage:(MSG) block:(BLOCK) file:@(__FILE__) line:__LINE__]; #define expectFailureMessages(MSGS, BLOCK) \ [NimbleHelper expectFailureMessages:(MSGS) block:(BLOCK) file:@(__FILE__) line:__LINE__]; // Use this when you want to verify the failure message with the nil message postfixed // to it: " (use beNil() to match nils)" #define expectNilFailureMessage(MSG, BLOCK) \ [NimbleHelper expectFailureMessageForNil:(MSG) block:(BLOCK) file:@(__FILE__) line:__LINE__]; ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/NimbleTests-Bridging-Header.h ================================================ // // Use this file to import your target's public headers that you would like to expose to Swift. // ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCAllPassTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCAllPassTest : XCTestCase @end @implementation ObjCAllPassTest - (void)testPositiveMatches { expect(@[@1, @2, @3,@4]).to(allPass(beLessThan(@5))); expect(@[@1, @2, @3,@4]).toNot(allPass(beGreaterThan(@5))); expect([NSSet setWithArray:@[@1, @2, @3,@4]]).to(allPass(beLessThan(@5))); expect([NSSet setWithArray:@[@1, @2, @3,@4]]).toNot(allPass(beGreaterThan(@5))); } - (void)testNegativeMatches { expectFailureMessage(@"expected to all be less than <3.0000>, but failed first at element" " <3.0000> in <[1.0000, 2.0000, 3.0000, 4.0000]>", ^{ expect(@[@1, @2, @3,@4]).to(allPass(beLessThan(@3))); }); expectFailureMessage(@"expected to not all be less than <5.0000>", ^{ expect(@[@1, @2, @3,@4]).toNot(allPass(beLessThan(@5))); }); expectFailureMessage(@"expected to not all be less than <5.0000>", ^{ expect([NSSet setWithArray:@[@1, @2, @3,@4]]).toNot(allPass(beLessThan(@5))); }); expectFailureMessage(@"allPass only works with NSFastEnumeration" " (NSArray, NSSet, ...) of NSObjects, got <3.0000>", ^{ expect(@3).to(allPass(beLessThan(@5))); }); expectFailureMessage(@"allPass only works with NSFastEnumeration" " (NSArray, NSSet, ...) of NSObjects, got <3.0000>", ^{ expect(@3).toNot(allPass(beLessThan(@5))); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCAsyncTest.m ================================================ #import #import #import "NimbleSpecHelper.h" @interface ObjCAsyncTest : XCTestCase @end @implementation ObjCAsyncTest - (void)testAsync { __block id obj = @1; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ obj = nil; }); expect(obj).toEventually(beNil()); } - (void)testAsyncWithCustomTimeout { __block id obj = nil; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ obj = @1; }); expect(obj).withTimeout(5).toEventuallyNot(beNil()); } - (void)testAsyncCallback { waitUntil(^(void (^done)(void)){ done(); }); expectFailureMessage(@"Waited more than 1.0 second", ^{ waitUntil(^(void (^done)(void)){ /* ... */ }); }); expectFailureMessage(@"Waited more than 0.01 seconds", ^{ waitUntilTimeout(0.01, ^(void (^done)(void)){ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [NSThread sleepForTimeInterval:0.1]; done(); }); }); }); expectFailureMessage(@"expected to equal , got ", ^{ waitUntil(^(void (^done)(void)){ [NSThread sleepForTimeInterval:0.1]; expect(@"hello").to(equal(@"goodbye")); done(); }); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCBeAnInstanceOfTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeAnInstanceOfTest : XCTestCase @end @implementation ObjCBeAnInstanceOfTest - (void)testPositiveMatches { NSNull *obj = [NSNull null]; expect(obj).to(beAnInstanceOf([NSNull class])); expect(@1).toNot(beAnInstanceOf([NSNull class])); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be an instance of NSNull, got <__NSCFNumber instance>", ^{ expect(@1).to(beAnInstanceOf([NSNull class])); }); expectFailureMessage(@"expected to not be an instance of NSNull, got ", ^{ expect([NSNull null]).toNot(beAnInstanceOf([NSNull class])); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to be an instance of NSNull, got ", ^{ expect(nil).to(beAnInstanceOf([NSNull class])); }); expectNilFailureMessage(@"expected to not be an instance of NSNull, got ", ^{ expect(nil).toNot(beAnInstanceOf([NSNull class])); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCBeCloseToTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeCloseToTest : XCTestCase @end @implementation ObjCBeCloseToTest - (void)testPositiveMatches { expect(@1.2).to(beCloseTo(@1.2001)); expect(@1.2).to(beCloseTo(@2).within(10)); expect(@2).toNot(beCloseTo(@1)); expect(@1.00001).toNot(beCloseTo(@1).within(0.00000001)); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be close to <0.0000> (within 0.0010), got <1.0000>", ^{ expect(@1).to(beCloseTo(@0)); }); expectFailureMessage(@"expected to not be close to <0.0000> (within 0.0010), got <0.0001>", ^{ expect(@(0.0001)).toNot(beCloseTo(@0)); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to be close to <0.0000> (within 0.0010), got ", ^{ expect(nil).to(beCloseTo(@0)); }); expectNilFailureMessage(@"expected to not be close to <0.0000> (within 0.0010), got ", ^{ expect(nil).toNot(beCloseTo(@0)); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCBeEmptyTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeEmptyTest : XCTestCase @end @implementation ObjCBeEmptyTest - (void)testPositiveMatches { expect(@[]).to(beEmpty()); expect(@"").to(beEmpty()); expect(@{}).to(beEmpty()); expect([NSSet set]).to(beEmpty()); expect([NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory]).to(beEmpty()); expect(@[@1, @2]).toNot(beEmpty()); expect(@"a").toNot(beEmpty()); expect(@{@"key": @"value"}).toNot(beEmpty()); expect([NSSet setWithObject:@1]).toNot(beEmpty()); NSHashTable *table = [NSHashTable hashTableWithOptions:NSPointerFunctionsStrongMemory]; [table addObject:@1]; expect(table).toNot(beEmpty()); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be empty, got ", ^{ expect(@"foo").to(beEmpty()); }); expectFailureMessage(@"expected to be empty, got <(1)>", ^{ expect(@[@1]).to(beEmpty()); }); expectFailureMessage(@"expected to be empty, got <{key = value;}>", ^{ expect(@{@"key": @"value"}).to(beEmpty()); }); expectFailureMessage(@"expected to be empty, got <{(1)}>", ^{ expect([NSSet setWithObject:@1]).to(beEmpty()); }); NSHashTable *table = [NSHashTable hashTableWithOptions:NSPointerFunctionsStrongMemory]; [table addObject:@1]; NSString *tableString = [[table description] stringByReplacingOccurrencesOfString:@"\n" withString:@""]; expectFailureMessage(([NSString stringWithFormat:@"expected to be empty, got <%@>", tableString]), ^{ expect(table).to(beEmpty()); }); expectFailureMessage(@"expected to not be empty, got <>", ^{ expect(@"").toNot(beEmpty()); }); expectFailureMessage(@"expected to not be empty, got <()>", ^{ expect(@[]).toNot(beEmpty()); }); expectFailureMessage(@"expected to not be empty, got <{}>", ^{ expect(@{}).toNot(beEmpty()); }); expectFailureMessage(@"expected to not be empty, got <{(1)}>", ^{ expect([NSSet setWithObject:@1]).toNot(beEmpty()); }); expectFailureMessage(@"expected to not be empty, got ", ^{ expect([NSHashTable hashTableWithOptions:NSPointerFunctionsStrongMemory]).toNot(beEmpty()); }); } - (void)testItDoesNotMatchNil { expectNilFailureMessage(@"expected to be empty, got ", ^{ expect(nil).to(beEmpty()); }); expectNilFailureMessage(@"expected to not be empty, got ", ^{ expect(nil).toNot(beEmpty()); }); } - (void)testItReportsTypesItMatchesAgainst { expectFailureMessage(@"expected to be empty (only works for NSArrays, NSSets, NSDictionaries, NSHashTables, and NSStrings), got __NSCFNumber type", ^{ expect(@1).to(beEmpty()); }); expectFailureMessage(@"expected to not be empty (only works for NSArrays, NSSets, NSDictionaries, NSHashTables, and NSStrings), got __NSCFNumber type", ^{ expect(@1).toNot(beEmpty()); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCBeFalseTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeFalseTest : XCTestCase @end @implementation ObjCBeFalseTest - (void)testPositiveMatches { expect(@NO).to(beFalse()); expect(@YES).toNot(beFalse()); } - (void)testNegativeMatches { expectNilFailureMessage(@"expected to be false, got ", ^{ expect(nil).to(beFalse()); }); expectNilFailureMessage(@"expected to not be false, got ", ^{ expect(nil).toNot(beFalse()); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCBeFalsyTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeFalsyTest : XCTestCase @end @implementation ObjCBeFalsyTest - (void)testPositiveMatches { expect(@NO).to(beFalsy()); expect(@YES).toNot(beFalsy()); expect(nil).to(beFalsy()); } - (void)testNegativeMatches { expectFailureMessage(@"expected to not be falsy, got ", ^{ expect(nil).toNot(beFalsy()); }); expectFailureMessage(@"expected to be falsy, got <1.0000>", ^{ expect(@1).to(beFalsy()); }); expectFailureMessage(@"expected to be truthy, got <0.0000>", ^{ expect(@NO).to(beTruthy()); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCBeGreaterThanOrEqualToTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeGreaterThanOrEqualToTest : XCTestCase @end @implementation ObjCBeGreaterThanOrEqualToTest - (void)testPositiveMatches { expect(@2).to(beGreaterThanOrEqualTo(@2)); expect(@2).toNot(beGreaterThanOrEqualTo(@3)); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be greater than or equal to <0.0000>, got <-1.0000>", ^{ expect(@(-1)).to(beGreaterThanOrEqualTo(@0)); }); expectFailureMessage(@"expected to not be greater than or equal to <1.0000>, got <2.0000>", ^{ expect(@2).toNot(beGreaterThanOrEqualTo(@(1))); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to be greater than or equal to <-1.0000>, got ", ^{ expect(nil).to(beGreaterThanOrEqualTo(@(-1))); }); expectNilFailureMessage(@"expected to not be greater than or equal to <1.0000>, got ", ^{ expect(nil).toNot(beGreaterThanOrEqualTo(@(1))); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCBeGreaterThanTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeGreaterThanTest : XCTestCase @end @implementation ObjCBeGreaterThanTest - (void)testPositiveMatches { expect(@2).to(beGreaterThan(@1)); expect(@2).toNot(beGreaterThan(@2)); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be greater than <0.0000>, got <-1.0000>", ^{ expect(@(-1)).to(beGreaterThan(@(0))); }); expectFailureMessage(@"expected to not be greater than <1.0000>, got <0.0000>", ^{ expect(@0).toNot(beGreaterThan(@(1))); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to be greater than <-1.0000>, got ", ^{ expect(nil).to(beGreaterThan(@(-1))); }); expectNilFailureMessage(@"expected to not be greater than <1.0000>, got ", ^{ expect(nil).toNot(beGreaterThan(@(1))); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCBeIdenticalToTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeIdenticalToTest : XCTestCase @end @implementation ObjCBeIdenticalToTest - (void)testPositiveMatches { NSNull *obj = [NSNull null]; expect(obj).to(beIdenticalTo([NSNull null])); expect(@2).toNot(beIdenticalTo(@3)); } - (void)testNegativeMatches { NSNull *obj = [NSNull null]; expectFailureMessage(([NSString stringWithFormat:@"expected to be identical to <%p>, got <%p>", obj, @2]), ^{ expect(@2).to(beIdenticalTo(obj)); }); expectFailureMessage(([NSString stringWithFormat:@"expected to not be identical to <%p>, got <%p>", obj, obj]), ^{ expect(obj).toNot(beIdenticalTo(obj)); }); } - (void)testNilMatches { NSNull *obj = [NSNull null]; expectNilFailureMessage(@"expected to be identical to nil, got nil", ^{ expect(nil).to(beIdenticalTo(nil)); }); expectNilFailureMessage(([NSString stringWithFormat:@"expected to not be identical to <%p>, got nil", obj]), ^{ expect(nil).toNot(beIdenticalTo(obj)); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCBeKindOfTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeKindOfTest : XCTestCase @end @implementation ObjCBeKindOfTest - (void)testPositiveMatches { NSMutableArray *array = [NSMutableArray array]; expect(array).to(beAKindOf([NSArray class])); expect(@1).toNot(beAKindOf([NSNull class])); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be a kind of NSNull, got <__NSCFNumber instance>", ^{ expect(@1).to(beAKindOf([NSNull class])); }); expectFailureMessage(@"expected to not be a kind of NSNull, got ", ^{ expect([NSNull null]).toNot(beAKindOf([NSNull class])); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to be a kind of NSNull, got ", ^{ expect(nil).to(beAKindOf([NSNull class])); }); expectNilFailureMessage(@"expected to not be a kind of NSNull, got ", ^{ expect(nil).toNot(beAKindOf([NSNull class])); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCBeLessThanOrEqualToTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeLessThanOrEqualToTest : XCTestCase @end @implementation ObjCBeLessThanOrEqualToTest - (void)testPositiveMatches { expect(@2).to(beLessThanOrEqualTo(@2)); expect(@2).toNot(beLessThanOrEqualTo(@1)); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be less than or equal to <1.0000>, got <2.0000>", ^{ expect(@2).to(beLessThanOrEqualTo(@1)); }); expectFailureMessage(@"expected to not be less than or equal to <1.0000>, got <1.0000>", ^{ expect(@1).toNot(beLessThanOrEqualTo(@1)); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to be less than or equal to <1.0000>, got ", ^{ expect(nil).to(beLessThanOrEqualTo(@1)); }); expectNilFailureMessage(@"expected to not be less than or equal to <-1.0000>, got ", ^{ expect(nil).toNot(beLessThanOrEqualTo(@(-1))); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCBeLessThanTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeLessThanTest : XCTestCase @end @implementation ObjCBeLessThanTest - (void)testPositiveMatches { expect(@2).to(beLessThan(@3)); expect(@2).toNot(beLessThan(@2)); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be less than <0.0000>, got <-1.0000>", ^{ expect(@(-1)).to(beLessThan(@0)); }); expectFailureMessage(@"expected to not be less than <1.0000>, got <0.0000>", ^{ expect(@0).toNot(beLessThan(@1)); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to be less than <-1.0000>, got ", ^{ expect(nil).to(beLessThan(@(-1))); }); expectNilFailureMessage(@"expected to not be less than <1.0000>, got ", ^{ expect(nil).toNot(beLessThan(@1)); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCBeNilTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeNilTest : XCTestCase @end @implementation ObjCBeNilTest - (void)testPositiveMatches { expect(nil).to(beNil()); expect(@NO).toNot(beNil()); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be nil, got <1.0000>", ^{ expect(@1).to(beNil()); }); expectFailureMessage(@"expected to not be nil, got ", ^{ expect(nil).toNot(beNil()); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCBeTrueTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeTrueTest : XCTestCase @end @implementation ObjCBeTrueTest - (void)testPositiveMatches { expect(@YES).to(beTrue()); expect(@NO).toNot(beTrue()); expect(nil).toNot(beTrue()); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be true, got <0.0000>", ^{ expect(@NO).to(beTrue()); }); expectFailureMessage(@"expected to be true, got ", ^{ expect(nil).to(beTrue()); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCBeTruthyTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeTruthyTest : XCTestCase @end @implementation ObjCBeTruthyTest - (void)testPositiveMatches { expect(@YES).to(beTruthy()); expect(@NO).toNot(beTruthy()); expect(nil).toNot(beTruthy()); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be truthy, got ", ^{ expect(nil).to(beTruthy()); }); expectFailureMessage(@"expected to not be truthy, got <1.0000>", ^{ expect(@1).toNot(beTruthy()); }); expectFailureMessage(@"expected to be truthy, got <0.0000>", ^{ expect(@NO).to(beTruthy()); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCBeginWithTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeginWithTest : XCTestCase @end @implementation ObjCBeginWithTest - (void)testPositiveMatches { expect(@"hello world!").to(beginWith(@"hello")); expect(@"hello world!").toNot(beginWith(@"world")); NSArray *array = @[@1, @2]; expect(array).to(beginWith(@1)); expect(array).toNot(beginWith(@2)); } - (void)testNegativeMatches { expectFailureMessage(@"expected to begin with , got ", ^{ expect(@"foo").to(beginWith(@"bar")); }); expectFailureMessage(@"expected to not begin with , got ", ^{ expect(@"foo").toNot(beginWith(@"foo")); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to begin with <1>, got ", ^{ expect(nil).to(beginWith(@1)); }); expectNilFailureMessage(@"expected to not begin with <1>, got ", ^{ expect(nil).toNot(beginWith(@1)); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCContainTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCContainTest : XCTestCase @end @implementation ObjCContainTest - (void)testPositiveMatches { NSArray *array = @[@1, @2]; expect(array).to(contain(@1)); expect(array).toNot(contain(@"HI")); expect(@"String").to(contain(@"Str")); expect(@"Other").toNot(contain(@"Str")); } - (void)testNegativeMatches { expectFailureMessage(@"expected to contain , got <(1,2)>", ^{ expect((@[@1, @2])).to(contain(@3)); }); expectFailureMessage(@"expected to not contain , got <(1,2)>", ^{ expect((@[@1, @2])).toNot(contain(@2)); }); expectFailureMessage(@"expected to contain , got ", ^{ expect(@"la").to(contain(@"hi")); }); expectFailureMessage(@"expected to not contain , got ", ^{ expect(@"hihihi").toNot(contain(@"hi")); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to contain <3.0000>, got ", ^{ expect(nil).to(contain(@3)); }); expectNilFailureMessage(@"expected to not contain <3.0000>, got ", ^{ expect(nil).toNot(contain(@3)); }); expectNilFailureMessage(@"expected to contain , got ", ^{ expect(nil).to(contain(@"hi")); }); expectNilFailureMessage(@"expected to not contain , got ", ^{ expect(nil).toNot(contain(@"hi")); }); } - (void)testVariadicArguments { NSArray *array = @[@1, @2]; expect(array).to(contain(@1, @2)); expect(array).toNot(contain(@"HI", @"whale")); expect(@"String").to(contain(@"Str", @"ng")); expect(@"Other").toNot(contain(@"Str", @"Oth")); expectFailureMessage(@"expected to contain , got <(a,b,c)>", ^{ expect(@[@"a", @"b", @"c"]).to(contain(@"a", @"bar")); }); expectFailureMessage(@"expected to not contain , got <(a,b,c)>", ^{ expect(@[@"a", @"b", @"c"]).toNot(contain(@"bar", @"b")); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCEndWithTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCEndWithTest : XCTestCase @end @implementation ObjCEndWithTest - (void)testPositiveMatches { NSArray *array = @[@1, @2]; expect(@"hello world!").to(endWith(@"world!")); expect(@"hello world!").toNot(endWith(@"hello")); expect(array).to(endWith(@2)); expect(array).toNot(endWith(@1)); expect(@1).toNot(contain(@"foo")); } - (void)testNegativeMatches { expectFailureMessage(@"expected to end with , got ", ^{ expect(@"hello world!").to(endWith(@"?")); }); expectFailureMessage(@"expected to not end with , got ", ^{ expect(@"hello world!").toNot(endWith(@"!")); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to end with <1>, got ", ^{ expect(nil).to(endWith(@1)); }); expectNilFailureMessage(@"expected to not end with <1>, got ", ^{ expect(nil).toNot(endWith(@1)); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCEqualTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCEqualTest : XCTestCase @end @implementation ObjCEqualTest - (void)testPositiveMatches { expect(@1).to(equal(@1)); expect(@1).toNot(equal(@2)); expect(@1).notTo(equal(@2)); expect(@"hello").to(equal(@"hello")); } - (void)testNegativeMatches { expectFailureMessage(@"expected to equal <2.0000>, got <1.0000>", ^{ expect(@1).to(equal(@2)); }); expectFailureMessage(@"expected to not equal <1.0000>, got <1.0000>", ^{ expect(@1).toNot(equal(@1)); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to equal , got ", ^{ expect(nil).to(equal(nil)); }); expectNilFailureMessage(@"expected to not equal , got ", ^{ expect(nil).toNot(equal(nil)); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCHaveCount.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCHaveCountTest : XCTestCase @end @implementation ObjCHaveCountTest - (void)testHaveCountForNSArray { expect(@[@1, @2, @3]).to(haveCount(@3)); expect(@[@1, @2, @3]).notTo(haveCount(@1)); expect(@[]).to(haveCount(@0)); expect(@[@1]).notTo(haveCount(@0)); expectFailureMessage(@"expected to have (1,2,3) with count 1, got 3", ^{ expect(@[@1, @2, @3]).to(haveCount(@1)); }); expectFailureMessage(@"expected to not have (1,2,3) with count 3, got 3", ^{ expect(@[@1, @2, @3]).notTo(haveCount(@3)); }); } - (void)testHaveCountForNSDictionary { expect(@{@"1":@1, @"2":@2, @"3":@3}).to(haveCount(@3)); expect(@{@"1":@1, @"2":@2, @"3":@3}).notTo(haveCount(@1)); expectFailureMessage(@"expected to have {1 = 1;2 = 2;3 = 3;} with count 1, got 3", ^{ expect(@{@"1":@1, @"2":@2, @"3":@3}).to(haveCount(@1)); }); expectFailureMessage(@"expected to not have {1 = 1;2 = 2;3 = 3;} with count 3, got 3", ^{ expect(@{@"1":@1, @"2":@2, @"3":@3}).notTo(haveCount(@3)); }); } - (void)testHaveCountForNSHashtable { NSHashTable *const table = [NSHashTable hashTableWithOptions:NSPointerFunctionsStrongMemory]; [table addObject:@1]; [table addObject:@2]; [table addObject:@3]; expect(table).to(haveCount(@3)); expect(table).notTo(haveCount(@1)); NSString *msg = [NSString stringWithFormat: @"expected to have %@with count 1, got 3", [table.description stringByReplacingOccurrencesOfString:@"\n" withString:@""]]; expectFailureMessage(msg, ^{ expect(table).to(haveCount(@1)); }); msg = [NSString stringWithFormat: @"expected to not have %@with count 3, got 3", [table.description stringByReplacingOccurrencesOfString:@"\n" withString:@""]]; expectFailureMessage(msg, ^{ expect(table).notTo(haveCount(@3)); }); } - (void)testHaveCountForNSSet { NSSet *const set = [NSSet setWithArray:@[@1, @2, @3]]; expect(set).to(haveCount(@3)); expect(set).notTo(haveCount(@1)); expectFailureMessage(@"expected to have {(3,1,2)} with count 1, got 3", ^{ expect(set).to(haveCount(@1)); }); expectFailureMessage(@"expected to not have {(3,1,2)} with count 3, got 3", ^{ expect(set).notTo(haveCount(@3)); }); } - (void)testHaveCountForUnsupportedTypes { expectFailureMessage(@"expected to get type of NSArray, NSSet, NSDictionary, or NSHashTable, got __NSCFConstantString", ^{ expect(@"string").to(haveCount(@6)); }); expectFailureMessage(@"expected to get type of NSArray, NSSet, NSDictionary, or NSHashTable, got __NSCFNumber", ^{ expect(@1).to(haveCount(@6)); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCMatchTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCMatchTest : XCTestCase @end @implementation ObjCMatchTest - (void)testPositiveMatches { expect(@"11:14").to(match(@"\\d{2}:\\d{2}")); expect(@"hello").toNot(match(@"\\d{2}:\\d{2}")); } - (void)testNegativeMatches { expectFailureMessage(@"expected to match <\\d{2}:\\d{2}>, got ", ^{ expect(@"hello").to(match(@"\\d{2}:\\d{2}")); }); expectFailureMessage(@"expected to not match <\\d{2}:\\d{2}>, got <11:22>", ^{ expect(@"11:22").toNot(match(@"\\d{2}:\\d{2}")); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to match <\\d{2}:\\d{2}>, got ", ^{ expect(nil).to(match(@"\\d{2}:\\d{2}")); }); expectNilFailureMessage(@"expected to not match <\\d{2}:\\d{2}>, got ", ^{ expect(nil).toNot(match(@"\\d{2}:\\d{2}")); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCRaiseExceptionTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCRaiseExceptionTest : XCTestCase @end @implementation ObjCRaiseExceptionTest - (void)testPositiveMatches { __block NSException *exception = [NSException exceptionWithName:NSInvalidArgumentException reason:@"No food" userInfo:@{@"key": @"value"}]; expectAction(^{ @throw exception; }).to(raiseException()); expectAction(^{ [exception raise]; }).to(raiseException()); expectAction(^{ [exception raise]; }).to(raiseException().named(NSInvalidArgumentException)); expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). reason(@"No food")); expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). reason(@"No food"). userInfo(@{@"key": @"value"})); expectAction(^{ }).toNot(raiseException()); } - (void)testPositiveMatchesWithBlocks { __block NSException *exception = [NSException exceptionWithName:NSInvalidArgumentException reason:@"No food" userInfo:@{@"key": @"value"}]; expectAction(^{ [exception raise]; }).to(raiseException(). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(NSInvalidArgumentException)); })); expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(NSInvalidArgumentException)); })); expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). reason(@"No food"). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(NSInvalidArgumentException)); })); expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). reason(@"No food"). userInfo(@{@"key": @"value"}). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(NSInvalidArgumentException)); })); } - (void)testNegativeMatches { __block NSException *exception = [NSException exceptionWithName:NSInvalidArgumentException reason:@"No food" userInfo:@{@"key": @"value"}]; expectFailureMessage(@"expected to raise any exception, got no exception", ^{ expectAction(^{ }).to(raiseException()); }); expectFailureMessage(@"expected to raise exception with name , got no exception", ^{ expectAction(^{ }).to(raiseException(). named(@"foo")); }); expectFailureMessage(@"expected to raise exception with name with reason , got no exception", ^{ expectAction(^{ }).to(raiseException(). named(NSInvalidArgumentException). reason(@"cakes")); }); expectFailureMessage(@"expected to raise exception with name with reason with userInfo <{k = v;}>, got no exception", ^{ expectAction(^{ }).to(raiseException(). named(NSInvalidArgumentException). reason(@"No food"). userInfo(@{@"k": @"v"})); }); expectFailureMessage(@"expected to not raise any exception, got NSException { name=NSInvalidArgumentException, reason='No food', userInfo=[key: value] }", ^{ expectAction(^{ [exception raise]; }).toNot(raiseException()); }); } - (void)testNegativeMatchesWithPassingBlocks { __block NSException *exception = [NSException exceptionWithName:NSInvalidArgumentException reason:@"No food" userInfo:@{@"key": @"value"}]; expectFailureMessage(@"expected to raise exception that satisfies block, got no exception", ^{ expect(exception).to(raiseException(). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(@"LOL")); })); }); NSString *outerFailureMessage = @"expected to raise exception that satisfies block, got NSException { name=NSInvalidArgumentException, reason='No food', userInfo=[key: value] }"; expectFailureMessages((@[outerFailureMessage]), ^{ expectAction(^{ [exception raise]; }).to(raiseException(). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(NSInvalidArgumentException)); })); }); outerFailureMessage = @"expected to raise exception with name that satisfies block, got NSException { name=NSInvalidArgumentException, reason='No food', userInfo=[key: value] }"; expectFailureMessages((@[outerFailureMessage]), ^{ expectAction(^{ [exception raise]; }).to(raiseException(). named(@"foo"). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(NSInvalidArgumentException)); })); }); outerFailureMessage = @"expected to raise exception with name with reason that satisfies block, got NSException { name=NSInvalidArgumentException, reason='No food', userInfo=[key: value] }"; expectFailureMessages((@[outerFailureMessage]), ^{ expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). reason(@"bar"). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(NSInvalidArgumentException)); })); }); outerFailureMessage = @"expected to raise exception with name with reason with userInfo <{}> that satisfies block, got NSException { name=NSInvalidArgumentException, reason='No food', userInfo=[key: value] }"; expectFailureMessages((@[outerFailureMessage]), ^{ expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). reason(@"No food"). userInfo(@{}). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(NSInvalidArgumentException)); })); }); } - (void)testNegativeMatchesWithNegativeBlocks { __block NSException *exception = [NSException exceptionWithName:NSInvalidArgumentException reason:@"No food" userInfo:@{@"key": @"value"}]; NSString *outerFailureMessage; NSString const *innerFailureMessage = @"expected to equal , got "; outerFailureMessage = @"expected to raise exception with name that satisfies block, got NSException { name=NSInvalidArgumentException, reason='No food', userInfo=[key: value] }"; expectFailureMessages((@[outerFailureMessage, innerFailureMessage]), ^{ expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(@"foo")); })); }); outerFailureMessage = @"expected to raise exception with name with reason that satisfies block, got NSException { name=NSInvalidArgumentException, reason='No food', userInfo=[key: value] }"; expectFailureMessages((@[outerFailureMessage, innerFailureMessage]), ^{ expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). reason(@"No food"). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(@"foo")); })); }); outerFailureMessage = @"expected to raise exception with name with reason with userInfo <{key = value;}> that satisfies block, got NSException { name=NSInvalidArgumentException, reason='No food', userInfo=[key: value] }"; expectFailureMessages((@[outerFailureMessage, innerFailureMessage]), ^{ expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). reason(@"No food"). userInfo(@{@"key": @"value"}). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(@"foo")); })); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCSatisfyAnyOfTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCSatisfyAnyOfTest : XCTestCase @end @implementation ObjCSatisfyAnyOfTest - (void)testPositiveMatches { expect(@2).to(satisfyAnyOf(equal(@2), equal(@3))); expect(@2).toNot(satisfyAnyOf(equal(@3), equal(@16))); expect(@[@1, @2, @3]).to(satisfyAnyOf(equal(@[@1, @2, @3]), allPass(beLessThan(@4)))); expect(@NO).to(satisfyAnyOf(beTrue(), beFalse())); expect(@YES).to(satisfyAnyOf(beTrue(), beFalse())); } - (void)testNegativeMatches { expectFailureMessage(@"expected to match one of: {equal <3.0000>}, or {equal <4.0000>}, or {equal <5.0000>}, got 2", ^{ expect(@2).to(satisfyAnyOf(equal(@3), equal(@4), equal(@5))); }); expectFailureMessage(@"expected to match one of: {all be less than <4.0000>, but failed first at element" " <5.0000> in <[5.0000, 6.0000, 7.0000]>}, or {equal <(1,2,3,4)>}, got (5,6,7)", ^{ expect(@[@5, @6, @7]).to(satisfyAnyOf(allPass(beLessThan(@4)), equal(@[@1, @2, @3, @4]))); }); expectFailureMessage(@"satisfyAnyOf must be called with at least one matcher", ^{ expect(@"turtles").to(satisfyAnyOf()); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCSyncTest.m ================================================ #import #import #import "NimbleSpecHelper.h" @interface ObjCSyncTest : XCTestCase @end @implementation ObjCSyncTest - (void)testFailureExpectation { expectFailureMessage(@"fail() always fails", ^{ fail(); }); expectFailureMessage(@"This always fails", ^{ failWithMessage(@"This always fails"); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/NimbleTests/objc/ObjCUserDescriptionTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCUserDescriptionTest : XCTestCase @end @implementation ObjCUserDescriptionTest - (void)testToWithDescription { expectFailureMessage(@"These are equal!\n" "expected to equal <2.0000>, got <1.0000>", ^{ expect(@1).toWithDescription(equal(@2), @"These are equal!"); }); } - (void)testToNotWithDescription { expectFailureMessage(@"These aren't equal!\n" "expected to not equal <1.0000>, got <1.0000>", ^{ expect(@1).toNotWithDescription(equal(@1), @"These aren't equal!"); }); } - (void)testNotToWithDescription { expectFailureMessage(@"These aren't equal!\n" "expected to not equal <1.0000>, got <1.0000>", ^{ expect(@1).notToWithDescription(equal(@1), @"These aren't equal!"); }); } - (void)testToEventuallyWithDescription { expectFailureMessage(@"These are equal!\n" "expected to eventually equal <2.0000>, got <1.0000>", ^{ expect(@1).toEventuallyWithDescription(equal(@2), @"These are equal!"); }); } - (void)testToEventuallyNotWithDescription { expectFailureMessage(@"These aren't equal!\n" "expected to eventually not equal <1.0000>, got <1.0000>", ^{ expect(@1).toEventuallyNotWithDescription(equal(@1), @"These aren't equal!"); }); } - (void)testToNotEventuallyWithDescription { expectFailureMessage(@"These aren't equal!\n" "expected to eventually not equal <1.0000>, got <1.0000>", ^{ expect(@1).toNotEventuallyWithDescription(equal(@1), @"These aren't equal!"); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/README.md ================================================ # Nimble Use Nimble to express the expected outcomes of Swift or Objective-C expressions. Inspired by [Cedar](https://github.com/pivotal/cedar). ```swift // Swift expect(1 + 1).to(equal(2)) expect(1.2).to(beCloseTo(1.1, within: 0.1)) expect(3) > 2 expect("seahorse").to(contain("sea")) expect(["Atlantic", "Pacific"]).toNot(contain("Mississippi")) expect(ocean.isClean).toEventually(beTruthy()) ``` # How to Use Nimble **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [Some Background: Expressing Outcomes Using Assertions in XCTest](#some-background-expressing-outcomes-using-assertions-in-xctest) - [Nimble: Expectations Using `expect(...).to`](#nimble-expectations-using-expectto) - [Custom Failure Messages](#custom-failure-messages) - [Type Checking](#type-checking) - [Operator Overloads](#operator-overloads) - [Lazily Computed Values](#lazily-computed-values) - [C Primitives](#c-primitives) - [Asynchronous Expectations](#asynchronous-expectations) - [Objective-C Support](#objective-c-support) - [Disabling Objective-C Shorthand](#disabling-objective-c-shorthand) - [Built-in Matcher Functions](#built-in-matcher-functions) - [Equivalence](#equivalence) - [Identity](#identity) - [Comparisons](#comparisons) - [Types/Classes](#typesclasses) - [Truthiness](#truthiness) - [Swift Error Handling](#swift-error-handling) - [Exceptions](#exceptions) - [Collection Membership](#collection-membership) - [Strings](#strings) - [Checking if all elements of a collection pass a condition](#checking-if-all-elements-of-a-collection-pass-a-condition) - [Verify collection count](#verify-collection-count) - [Matching a value to any of a group of matchers](#matching-a-value-to-any-of-a-group-of-matchers) - [Writing Your Own Matchers](#writing-your-own-matchers) - [Lazy Evaluation](#lazy-evaluation) - [Type Checking via Swift Generics](#type-checking-via-swift-generics) - [Customizing Failure Messages](#customizing-failure-messages) - [Supporting Objective-C](#supporting-objective-c) - [Properly Handling `nil` in Objective-C Matchers](#properly-handling-nil-in-objective-c-matchers) - [Installing Nimble](#installing-nimble) - [Installing Nimble as a Submodule](#installing-nimble-as-a-submodule) - [Installing Nimble via CocoaPods](#installing-nimble-via-cocoapods) - [Using Nimble without XCTest](#using-nimble-without-xctest) # Some Background: Expressing Outcomes Using Assertions in XCTest Apple's Xcode includes the XCTest framework, which provides assertion macros to test whether code behaves properly. For example, to assert that `1 + 1 = 2`, XCTest has you write: ```swift // Swift XCTAssertEqual(1 + 1, 2, "expected one plus one to equal two") ``` Or, in Objective-C: ```objc // Objective-C XCTAssertEqual(1 + 1, 2, @"expected one plus one to equal two"); ``` XCTest assertions have a couple of drawbacks: 1. **Not enough macros.** There's no easy way to assert that a string contains a particular substring, or that a number is less than or equal to another. 2. **It's hard to write asynchronous tests.** XCTest forces you to write a lot of boilerplate code. Nimble addresses these concerns. # Nimble: Expectations Using `expect(...).to` Nimble allows you to express expectations using a natural, easily understood language: ```swift // Swift import Nimble expect(seagull.squawk).to(equal("Squee!")) ``` ```objc // Objective-C @import Nimble; expect(seagull.squawk).to(equal(@"Squee!")); ``` > The `expect` function autocompletes to include `file:` and `line:`, but these parameters are optional. Use the default values to have Xcode highlight the correct line when an expectation is not met. To perform the opposite expectation--to assert something is *not* equal--use `toNot` or `notTo`: ```swift // Swift import Nimble expect(seagull.squawk).toNot(equal("Oh, hello there!")) expect(seagull.squawk).notTo(equal("Oh, hello there!")) ``` ```objc // Objective-C @import Nimble; expect(seagull.squawk).toNot(equal(@"Oh, hello there!")); expect(seagull.squawk).notTo(equal(@"Oh, hello there!")); ``` ## Custom Failure Messages Would you like to add more information to the test's failure messages? Use the `description` optional argument to add your own text: ```swift // Swift expect(1 + 1).to(equal(3)) // failed - expected to equal <3>, got <2> expect(1 + 1).to(equal(3), description: "Make sure libKindergartenMath is loaded") // failed - Make sure libKindergartenMath is loaded // expected to equal <3>, got <2> ``` Or the *WithDescription version in Objective-C: ```objc // Objective-C @import Nimble; expect(@(1+1)).to(equal(@3)); // failed - expected to equal <3.0000>, got <2.0000> expect(@(1+1)).toWithDescription(equal(@3), @"Make sure libKindergartenMath is loaded"); // failed - Make sure libKindergartenMath is loaded // expected to equal <3.0000>, got <2.0000> ``` ## Type Checking Nimble makes sure you don't compare two types that don't match: ```swift // Swift // Does not compile: expect(1 + 1).to(equal("Squee!")) ``` > Nimble uses generics--only available in Swift--to ensure type correctness. That means type checking is not available when using Nimble in Objective-C. :sob: ## Operator Overloads Tired of so much typing? With Nimble, you can use overloaded operators like `==` for equivalence, or `>` for comparisons: ```swift // Swift // Passes if squawk does not equal "Hi!": expect(seagull.squawk) != "Hi!" // Passes if 10 is greater than 2: expect(10) > 2 ``` > Operator overloads are only available in Swift, so you won't be able to use this syntax in Objective-C. :broken_heart: ## Lazily Computed Values The `expect` function doesn't evaluate the value it's given until it's time to match. So Nimble can test whether an expression raises an exception once evaluated: ```swift // Swift // Note: Swift currently doesn't have exceptions. // Only Objective-C code can raise exceptions // that Nimble will catch. // (see https://github.com/Quick/Nimble/issues/220#issuecomment-172667064) let exception = NSException( name: NSInternalInconsistencyException, reason: "Not enough fish in the sea.", userInfo: ["something": "is fishy"]) expect { exception.raise() }.to(raiseException()) // Also, you can customize raiseException to be more specific expect { exception.raise() }.to(raiseException(named: NSInternalInconsistencyException)) expect { exception.raise() }.to(raiseException( named: NSInternalInconsistencyException, reason: "Not enough fish in the sea")) expect { exception.raise() }.to(raiseException( named: NSInternalInconsistencyException, reason: "Not enough fish in the sea", userInfo: ["something": "is fishy"])) ``` Objective-C works the same way, but you must use the `expectAction` macro when making an expectation on an expression that has no return value: ```objc // Objective-C NSException *exception = [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Not enough fish in the sea." userInfo:nil]; expectAction(^{ [exception raise]; }).to(raiseException()); // Use the property-block syntax to be more specific. expectAction(^{ [exception raise]; }).to(raiseException().named(NSInternalInconsistencyException)); expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInternalInconsistencyException). reason("Not enough fish in the sea")); expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInternalInconsistencyException). reason("Not enough fish in the sea"). userInfo(@{@"something": @"is fishy"})); // You can also pass a block for custom matching of the raised exception expectAction(exception.raise()).to(raiseException().satisfyingBlock(^(NSException *exception) { expect(exception.name).to(beginWith(NSInternalInconsistencyException)); })); ``` ## C Primitives Some testing frameworks make it hard to test primitive C values. In Nimble, it just works: ```swift // Swift let actual: CInt = 1 let expectedValue: CInt = 1 expect(actual).to(equal(expectedValue)) ``` In fact, Nimble uses type inference, so you can write the above without explicitly specifying both types: ```swift // Swift expect(1 as CInt).to(equal(1)) ``` > In Objective-C, Nimble only supports Objective-C objects. To make expectations on primitive C values, wrap then in an object literal: ```objc expect(@(1 + 1)).to(equal(@2)); ``` ## Asynchronous Expectations In Nimble, it's easy to make expectations on values that are updated asynchronously. Just use `toEventually` or `toEventuallyNot`: ```swift // Swift dispatch_async(dispatch_get_main_queue()) { ocean.add("dolphins") ocean.add("whales") } expect(ocean).toEventually(contain("dolphins", "whales")) ``` ```objc // Objective-C dispatch_async(dispatch_get_main_queue(), ^{ [ocean add:@"dolphins"]; [ocean add:@"whales"]; }); expect(ocean).toEventually(contain(@"dolphins", @"whales")); ``` Note: toEventually triggers its polls on the main thread. Blocking the main thread will cause Nimble to stop the run loop. This can cause test pollution for whatever incomplete code that was running on the main thread. Blocking the main thread can be caused by blocking IO, calls to sleep(), deadlocks, and synchronous IPC. In the above example, `ocean` is constantly re-evaluated. If it ever contains dolphins and whales, the expectation passes. If `ocean` still doesn't contain them, even after being continuously re-evaluated for one whole second, the expectation fails. Sometimes it takes more than a second for a value to update. In those cases, use the `timeout` parameter: ```swift // Swift // Waits three seconds for ocean to contain "starfish": expect(ocean).toEventually(contain("starfish"), timeout: 3) ``` ```objc // Objective-C // Waits three seconds for ocean to contain "starfish": expect(ocean).withTimeout(3).toEventually(contain(@"starfish")); ``` You can also provide a callback by using the `waitUntil` function: ```swift // Swift waitUntil { done in // do some stuff that takes a while... NSThread.sleepForTimeInterval(0.5) done() } ``` ```objc // Objective-C waitUntil(^(void (^done)(void)){ // do some stuff that takes a while... [NSThread sleepForTimeInterval:0.5]; done(); }); ``` `waitUntil` also optionally takes a timeout parameter: ```swift // Swift waitUntil(timeout: 10) { done in // do some stuff that takes a while... NSThread.sleepForTimeInterval(1) done() } ``` ```objc // Objective-C waitUntilTimeout(10, ^(void (^done)(void)){ // do some stuff that takes a while... [NSThread sleepForTimeInterval:1]; done(); }); ``` Note: waitUntil triggers its timeout code on the main thread. Blocking the main thread will cause Nimble to stop the run loop to continue. This can cause test pollution for whatever incomplete code that was running on the main thread. Blocking the main thread can be caused by blocking IO, calls to sleep(), deadlocks, and synchronous IPC. ## Objective-C Support Nimble has full support for Objective-C. However, there are two things to keep in mind when using Nimble in Objective-C: 1. All parameters passed to the `expect` function, as well as matcher functions like `equal`, must be Objective-C objects: ```objc // Objective-C @import Nimble; expect(@(1 + 1)).to(equal(@2)); expect(@"Hello world").to(contain(@"world")); ``` 2. To make an expectation on an expression that does not return a value, such as `-[NSException raise]`, use `expectAction` instead of `expect`: ```objc // Objective-C expectAction(^{ [exception raise]; }).to(raiseException()); ``` ## Disabling Objective-C Shorthand Nimble provides a shorthand for expressing expectations using the `expect` function. To disable this shorthand in Objective-C, define the `NIMBLE_DISABLE_SHORT_SYNTAX` macro somewhere in your code before importing Nimble: ```objc #define NIMBLE_DISABLE_SHORT_SYNTAX 1 @import Nimble; NMB_expect(^{ return seagull.squawk; }, __FILE__, __LINE__).to(NMB_equal(@"Squee!")); ``` > Disabling the shorthand is useful if you're testing functions with names that conflict with Nimble functions, such as `expect` or `equal`. If that's not the case, there's no point in disabling the shorthand. # Built-in Matcher Functions Nimble includes a wide variety of matcher functions. ## Equivalence ```swift // Swift // Passes if actual is equivalent to expected: expect(actual).to(equal(expected)) expect(actual) == expected // Passes if actual is not equivalent to expected: expect(actual).toNot(equal(expected)) expect(actual) != expected ``` ```objc // Objective-C // Passes if actual is equivalent to expected: expect(actual).to(equal(expected)) // Passes if actual is not equivalent to expected: expect(actual).toNot(equal(expected)) ``` Values must be `Equatable`, `Comparable`, or subclasses of `NSObject`. `equal` will always fail when used to compare one or more `nil` values. ## Identity ```swift // Swift // Passes if actual has the same pointer address as expected: expect(actual).to(beIdenticalTo(expected)) expect(actual) === expected // Passes if actual does not have the same pointer address as expected: expect(actual).toNot(beIdenticalTo(expected)) expect(actual) !== expected ``` ```objc // Objective-C // Passes if actual has the same pointer address as expected: expect(actual).to(beIdenticalTo(expected)); // Passes if actual does not have the same pointer address as expected: expect(actual).toNot(beIdenticalTo(expected)); ``` ## Comparisons ```swift // Swift expect(actual).to(beLessThan(expected)) expect(actual) < expected expect(actual).to(beLessThanOrEqualTo(expected)) expect(actual) <= expected expect(actual).to(beGreaterThan(expected)) expect(actual) > expected expect(actual).to(beGreaterThanOrEqualTo(expected)) expect(actual) >= expected ``` ```objc // Objective-C expect(actual).to(beLessThan(expected)); expect(actual).to(beLessThanOrEqualTo(expected)); expect(actual).to(beGreaterThan(expected)); expect(actual).to(beGreaterThanOrEqualTo(expected)); ``` > Values given to the comparison matchers above must implement `Comparable`. Because of how computers represent floating point numbers, assertions that two floating point numbers be equal will sometimes fail. To express that two numbers should be close to one another within a certain margin of error, use `beCloseTo`: ```swift // Swift expect(actual).to(beCloseTo(expected, within: delta)) ``` ```objc // Objective-C expect(actual).to(beCloseTo(expected).within(delta)); ``` For example, to assert that `10.01` is close to `10`, you can write: ```swift // Swift expect(10.01).to(beCloseTo(10, within: 0.1)) ``` ```objc // Objective-C expect(@(10.01)).to(beCloseTo(@10).within(0.1)); ``` There is also an operator shortcut available in Swift: ```swift // Swift expect(actual) ≈ expected expect(actual) ≈ (expected, delta) ``` (Type Option-x to get ≈ on a U.S. keyboard) The former version uses the default delta of 0.0001. Here is yet another way to do this: ```swift // Swift expect(actual) ≈ expected ± delta expect(actual) == expected ± delta ``` (Type Option-Shift-= to get ± on a U.S. keyboard) If you are comparing arrays of floating point numbers, you'll find the following useful: ```swift // Swift expect([0.0, 2.0]) ≈ [0.0001, 2.0001] expect([0.0, 2.0]).to(beCloseTo([0.1, 2.1], within: 0.1)) ``` > Values given to the `beCloseTo` matcher must be coercable into a `Double`. ## Types/Classes ```swift // Swift // Passes if instance is an instance of aClass: expect(instance).to(beAnInstanceOf(aClass)) // Passes if instance is an instance of aClass or any of its subclasses: expect(instance).to(beAKindOf(aClass)) ``` ```objc // Objective-C // Passes if instance is an instance of aClass: expect(instance).to(beAnInstanceOf(aClass)); // Passes if instance is an instance of aClass or any of its subclasses: expect(instance).to(beAKindOf(aClass)); ``` > Instances must be Objective-C objects: subclasses of `NSObject`, or Swift objects bridged to Objective-C with the `@objc` prefix. For example, to assert that `dolphin` is a kind of `Mammal`: ```swift // Swift expect(dolphin).to(beAKindOf(Mammal)) ``` ```objc // Objective-C expect(dolphin).to(beAKindOf([Mammal class])); ``` > `beAnInstanceOf` uses the `-[NSObject isMemberOfClass:]` method to test membership. `beAKindOf` uses `-[NSObject isKindOfClass:]`. ## Truthiness ```swift // Passes if actual is not nil, true, or an object with a boolean value of true: expect(actual).to(beTruthy()) // Passes if actual is only true (not nil or an object conforming to BooleanType true): expect(actual).to(beTrue()) // Passes if actual is nil, false, or an object with a boolean value of false: expect(actual).to(beFalsy()) // Passes if actual is only false (not nil or an object conforming to BooleanType false): expect(actual).to(beFalse()) // Passes if actual is nil: expect(actual).to(beNil()) ``` ```objc // Objective-C // Passes if actual is not nil, true, or an object with a boolean value of true: expect(actual).to(beTruthy()); // Passes if actual is only true (not nil or an object conforming to BooleanType true): expect(actual).to(beTrue()); // Passes if actual is nil, false, or an object with a boolean value of false: expect(actual).to(beFalsy()); // Passes if actual is only false (not nil or an object conforming to BooleanType false): expect(actual).to(beFalse()); // Passes if actual is nil: expect(actual).to(beNil()); ``` ## Swift Error Handling If you're using Swift 2.0+, you can use the `throwError` matcher to check if an error is thrown. ```swift // Swift // Passes if somethingThatThrows() throws an ErrorType: expect{ try somethingThatThrows() }.to(throwError()) // Passes if somethingThatThrows() throws an error with a given domain: expect{ try somethingThatThrows() }.to(throwError { (error: ErrorType) in expect(error._domain).to(equal(NSCocoaErrorDomain)) }) // Passes if somethingThatThrows() throws an error with a given case: expect{ try somethingThatThrows() }.to(throwError(NSCocoaError.PropertyListReadCorruptError)) // Passes if somethingThatThrows() throws an error with a given type: expect{ try somethingThatThrows() }.to(throwError(errorType: MyError.self)) ``` Note: This feature is only available in Swift. ## Exceptions ```swift // Swift // Passes if actual, when evaluated, raises an exception: expect(actual).to(raiseException()) // Passes if actual raises an exception with the given name: expect(actual).to(raiseException(named: name)) // Passes if actual raises an exception with the given name and reason: expect(actual).to(raiseException(named: name, reason: reason)) // Passes if actual raises an exception and it passes expectations in the block // (in this case, if name begins with 'a r') expect { exception.raise() }.to(raiseException { (exception: NSException) in expect(exception.name).to(beginWith("a r")) }) ``` ```objc // Objective-C // Passes if actual, when evaluated, raises an exception: expect(actual).to(raiseException()) // Passes if actual raises an exception with the given name expect(actual).to(raiseException().named(name)) // Passes if actual raises an exception with the given name and reason: expect(actual).to(raiseException().named(name).reason(reason)) // Passes if actual raises an exception and it passes expectations in the block // (in this case, if name begins with 'a r') expect(actual).to(raiseException().satisfyingBlock(^(NSException *exception) { expect(exception.name).to(beginWith(@"a r")); })); ``` Note: Swift currently doesn't have exceptions (see [#220](https://github.com/Quick/Nimble/issues/220#issuecomment-172667064)). Only Objective-C code can raise exceptions that Nimble will catch. ## Collection Membership ```swift // Swift // Passes if all of the expected values are members of actual: expect(actual).to(contain(expected...)) // Passes if actual is an empty collection (it contains no elements): expect(actual).to(beEmpty()) ``` ```objc // Objective-C // Passes if expected is a member of actual: expect(actual).to(contain(expected)); // Passes if actual is an empty collection (it contains no elements): expect(actual).to(beEmpty()); ``` > In Swift `contain` takes any number of arguments. The expectation passes if all of them are members of the collection. In Objective-C, `contain` only takes one argument [for now](https://github.com/Quick/Nimble/issues/27). For example, to assert that a list of sea creature names contains "dolphin" and "starfish": ```swift // Swift expect(["whale", "dolphin", "starfish"]).to(contain("dolphin", "starfish")) ``` ```objc // Objective-C expect(@[@"whale", @"dolphin", @"starfish"]).to(contain(@"dolphin")); expect(@[@"whale", @"dolphin", @"starfish"]).to(contain(@"starfish")); ``` > `contain` and `beEmpty` expect collections to be instances of `NSArray`, `NSSet`, or a Swift collection composed of `Equatable` elements. To test whether a set of elements is present at the beginning or end of an ordered collection, use `beginWith` and `endWith`: ```swift // Swift // Passes if the elements in expected appear at the beginning of actual: expect(actual).to(beginWith(expected...)) // Passes if the the elements in expected come at the end of actual: expect(actual).to(endWith(expected...)) ``` ```objc // Objective-C // Passes if the elements in expected appear at the beginning of actual: expect(actual).to(beginWith(expected)); // Passes if the the elements in expected come at the end of actual: expect(actual).to(endWith(expected)); ``` > `beginWith` and `endWith` expect collections to be instances of `NSArray`, or ordered Swift collections composed of `Equatable` elements. Like `contain`, in Objective-C `beginWith` and `endWith` only support a single argument [for now](https://github.com/Quick/Nimble/issues/27). ## Strings ```swift // Swift // Passes if actual contains substring expected: expect(actual).to(contain(expected)) // Passes if actual begins with substring: expect(actual).to(beginWith(expected)) // Passes if actual ends with substring: expect(actual).to(endWith(expected)) // Passes if actual is an empty string, "": expect(actual).to(beEmpty()) // Passes if actual matches the regular expression defined in expected: expect(actual).to(match(expected)) ``` ```objc // Objective-C // Passes if actual contains substring expected: expect(actual).to(contain(expected)); // Passes if actual begins with substring: expect(actual).to(beginWith(expected)); // Passes if actual ends with substring: expect(actual).to(endWith(expected)); // Passes if actual is an empty string, "": expect(actual).to(beEmpty()); // Passes if actual matches the regular expression defined in expected: expect(actual).to(match(expected)) ``` ## Checking if all elements of a collection pass a condition ```swift // Swift // with a custom function: expect([1,2,3,4]).to(allPass({$0 < 5})) // with another matcher: expect([1,2,3,4]).to(allPass(beLessThan(5))) ``` ```objc // Objective-C expect(@[@1, @2, @3,@4]).to(allPass(beLessThan(@5))); ``` For Swift the actual value has to be a SequenceType, e.g. an array, a set or a custom seqence type. For Objective-C the actual value has to be a NSFastEnumeration, e.g. NSArray and NSSet, of NSObjects and only the variant which uses another matcher is available here. ## Verify collection count ```swift // passes if actual collection's count is equal to expected expect(actual).to(haveCount(expected)) // passes if actual collection's count is not equal to expected expect(actual).notTo(haveCount(expected)) ``` ```objc // passes if actual collection's count is equal to expected expect(actual).to(haveCount(expected)) // passes if actual collection's count is not equal to expected expect(actual).notTo(haveCount(expected)) ``` For Swift the actual value must be a `CollectionType` such as array, dictionary or set. For Objective-C the actual value has to be one of the following classes `NSArray`, `NSDictionary`, `NSSet`, `NSHashTable` or one of their subclasses. ## Matching a value to any of a group of matchers ```swift // passes if actual is either less than 10 or greater than 20 expect(actual).to(satisfyAnyOf(beLessThan(10), beGreaterThan(20))) // can include any number of matchers -- the following will pass // **be careful** -- too many matchers can be the sign of an unfocused test expect(6).to(satisfyAnyOf(equal(2), equal(3), equal(4), equal(5), equal(6), equal(7))) // in Swift you also have the option to use the || operator to achieve a similar function expect(82).to(beLessThan(50) || beGreaterThan(80)) ``` ```objc // passes if actual is either less than 10 or greater than 20 expect(actual).to(satisfyAnyOf(beLessThan(@10), beGreaterThan(@20))) // can include any number of matchers -- the following will pass // **be careful** -- too many matchers can be the sign of an unfocused test expect(@6).to(satisfyAnyOf(equal(@2), equal(@3), equal(@4), equal(@5), equal(@6), equal(@7))) ``` Note: This matcher allows you to chain any number of matchers together. This provides flexibility, but if you find yourself chaining many matchers together in one test, consider whether you could instead refactor that single test into multiple, more precisely focused tests for better coverage. # Writing Your Own Matchers In Nimble, matchers are Swift functions that take an expected value and return a `MatcherFunc` closure. Take `equal`, for example: ```swift // Swift public func equal(expectedValue: T?) -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "equal <\(expectedValue)>" return actualExpression.evaluate() == expectedValue } } ``` The return value of a `MatcherFunc` closure is a `Bool` that indicates whether the actual value matches the expectation: `true` if it does, or `false` if it doesn't. > The actual `equal` matcher function does not match when either `actual` or `expected` are nil; the example above has been edited for brevity. Since matchers are just Swift functions, you can define them anywhere: at the top of your test file, in a file shared by all of your tests, or in an Xcode project you distribute to others. > If you write a matcher you think everyone can use, consider adding it to Nimble's built-in set of matchers by sending a pull request! Or distribute it yourself via GitHub. For examples of how to write your own matchers, just check out the [`Matchers` directory](https://github.com/Quick/Nimble/tree/master/Nimble/Matchers) to see how Nimble's built-in set of matchers are implemented. You can also check out the tips below. ## Lazy Evaluation `actualExpression` is a lazy, memoized closure around the value provided to the `expect` function. The expression can either be a closure or a value directly passed to `expect(...)`. In order to determine whether that value matches, custom matchers should call `actualExpression.evaluate()`: ```swift // Swift public func beNil() -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be nil" return actualExpression.evaluate() == nil } } ``` In the above example, `actualExpression` is not `nil`--it is a closure that returns a value. The value it returns, which is accessed via the `evaluate()` method, may be `nil`. If that value is `nil`, the `beNil` matcher function returns `true`, indicating that the expectation passed. Use `expression.isClosure` to determine if the expression will be invoking a closure to produce its value. ## Type Checking via Swift Generics Using Swift's generics, matchers can constrain the type of the actual value passed to the `expect` function by modifying the return type. For example, the following matcher, `haveDescription`, only accepts actual values that implement the `Printable` protocol. It checks their `description` against the one provided to the matcher function, and passes if they are the same: ```swift // Swift public func haveDescription(description: String) -> MatcherFunc { return MatcherFunc { actual, failureMessage in return actual.evaluate().description == description } } ``` ## Customizing Failure Messages By default, Nimble outputs the following failure message when an expectation fails: ``` expected to match, got <\(actual)> ``` You can customize this message by modifying the `failureMessage` struct from within your `MatcherFunc` closure. To change the verb "match" to something else, update the `postfixMessage` property: ```swift // Swift // Outputs: expected to be under the sea, got <\(actual)> failureMessage.postfixMessage = "be under the sea" ``` You can change how the `actual` value is displayed by updating `failureMessage.actualValue`. Or, to remove it altogether, set it to `nil`: ```swift // Swift // Outputs: expected to be under the sea failureMessage.actualValue = nil failureMessage.postfixMessage = "be under the sea" ``` ## Supporting Objective-C To use a custom matcher written in Swift from Objective-C, you'll have to extend the `NMBObjCMatcher` class, adding a new class method for your custom matcher. The example below defines the class method `+[NMBObjCMatcher beNilMatcher]`: ```swift // Swift extension NMBObjCMatcher { public class func beNilMatcher() -> NMBObjCMatcher { return NMBObjCMatcher { actualBlock, failureMessage, location in let block = ({ actualBlock() as NSObject? }) let expr = Expression(expression: block, location: location) return beNil().matches(expr, failureMessage: failureMessage) } } } ``` The above allows you to use the matcher from Objective-C: ```objc // Objective-C expect(actual).to([NMBObjCMatcher beNilMatcher]()); ``` To make the syntax easier to use, define a C function that calls the class method: ```objc // Objective-C FOUNDATION_EXPORT id beNil() { return [NMBObjCMatcher beNilMatcher]; } ``` ### Properly Handling `nil` in Objective-C Matchers When supporting Objective-C, make sure you handle `nil` appropriately. Like [Cedar](https://github.com/pivotal/cedar/issues/100), **most matchers do not match with nil**. This is to bring prevent test writers from being surprised by `nil` values where they did not expect them. Nimble provides the `beNil` matcher function for test writer that want to make expectations on `nil` objects: ```objc // Objective-C expect(nil).to(equal(nil)); // fails expect(nil).to(beNil()); // passes ``` If your matcher does not want to match with nil, you use `NonNilMatcherFunc` and the `canMatchNil` constructor on `NMBObjCMatcher`. Using both types will automatically generate expected value failure messages when they're nil. ```swift public func beginWith(startingElement: T) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "begin with <\(startingElement)>" if let actualValue = actualExpression.evaluate() { var actualGenerator = actualValue.generate() return actualGenerator.next() == startingElement } return false } } extension NMBObjCMatcher { public class func beginWithMatcher(expected: AnyObject) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let actual = actualExpression.evaluate() let expr = actualExpression.cast { $0 as? NMBOrderedCollection } return beginWith(expected).matches(expr, failureMessage: failureMessage) } } } ``` # Installing Nimble > Nimble can be used on its own, or in conjunction with its sister project, [Quick](https://github.com/Quick/Quick). To install both Quick and Nimble, follow [the installation instructions in the Quick README](https://github.com/Quick/Quick#how-to-install-quick). Nimble can currently be installed in one of two ways: using CocoaPods, or with git submodules. ## Installing Nimble as a Submodule To use Nimble as a submodule to test your iOS or OS X applications, follow these 4 easy steps: 1. Clone the Nimble repository 2. Add Nimble.xcodeproj to the Xcode workspace for your project 3. Link Nimble.framework to your test target 4. Start writing expectations! For more detailed instructions on each of these steps, read [How to Install Quick](https://github.com/Quick/Quick#how-to-install-quick). Ignore the steps involving adding Quick to your project in order to install just Nimble. ## Installing Nimble via CocoaPods To use Nimble in CocoaPods to test your iOS or OS X applications, add Nimble to your podfile and add the ```use_frameworks!``` line to enable Swift support for Cocoapods. ```ruby platform :ios, '8.0' source 'https://github.com/CocoaPods/Specs.git' # Whatever pods you need for your app go here target 'YOUR_APP_NAME_HERE_Tests', :exclusive => true do use_frameworks! pod 'Nimble', '~> 3.0.0' end ``` Finally run `pod install`. ## Using Nimble without XCTest Nimble is integrated with XCTest to allow it work well when used in Xcode test bundles, however it can also be used in a standalone app. After installing Nimble using one of the above methods, there are two additional steps required to make this work. 1. Create a custom assertion handler and assign an instance of it to the global `NimbleAssertionHandler` variable. For example: ```swift class MyAssertionHandler : AssertionHandler { func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { if (!assertion) { print("Expectation failed: \(message.stringValue)") } } } ``` ```swift // Somewhere before you use any assertions NimbleAssertionHandler = MyAssertionHandler() ``` 2. Add a post-build action to fix an issue with the Swift XCTest support library being unnecessarily copied into your app * Edit your scheme in Xcode, and navigate to Build -> Post-actions * Click the "+" icon and select "New Run Script Action" * Open the "Provide build settings from" dropdown and select your target * Enter the following script contents: ``` rm "${SWIFT_STDLIB_TOOL_DESTINATION_DIR}/libswiftXCTest.dylib" ``` You can now use Nimble assertions in your code and handle failures as you see fit. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/circle.yml ================================================ machine: xcode: version: "7.0" test: override: - NIMBLE_RUNTIME_IOS_SDK_VERSION=9.0 ./test ios - NIMBLE_RUNTIME_OSX_SDK_VERSION=10.10 ./test osx ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/script/release ================================================ #!/usr/bin/env sh REMOTE_BRANCH=master POD_NAME=Nimble PODSPEC=Nimble.podspec GITHUB_TAGS_URL=https://github.com/Quick/Nimble/tags CARTHAGE_FRAMEWORK_NAME=Nimble CARTHAGE=${CARTHAGE:-carthage} POD=${COCOAPODS:-pod} function help { echo "Usage: release VERSION RELEASE_NOTES [-f]" echo echo "VERSION should be the version to release, should not include the 'v' prefix" echo "RELEASE_NOTES should be a file that lists all the release notes for this version" echo " if file does not exist, creates a git-style commit with a diff as a comment" echo echo "FLAGS" echo " -f Forces override of tag" echo echo " Example: ./release 1.0.0-rc.2 ./release-notes.txt" echo echo "HINT: use 'git diff ...HEAD' to build the release notes" echo exit 2 } function die { echo "[ERROR] $@" echo exit 1 } if [ $# -lt 2 ]; then help fi VERSION=$1 RELEASE_NOTES=$2 FORCE_TAG=$3 VERSION_TAG="v$VERSION" echo "-> Verifying Local Directory for Release" if [ -z "`which $CARTHAGE`" ]; then die "Carthage is required to produce a release. Aborting." fi echo " > Carthage is installed" if [ -z "`which $POD`" ]; then die "Cocoapods is required to produce a release. Aborting." fi echo " > Cocoapods is installed" echo " > Is this a reasonable tag?" echo $VERSION_TAG | grep -q "^vv" if [ $? -eq 0 ]; then die "This tag ($VERSION) is an incorrect format. You should remove the 'v' prefix." fi echo $VERSION_TAG | grep -q -E "^v\d+\.\d+\.\d+(-\w+(\.\d)?)?\$" if [ $? -ne 0 ]; then die "This tag ($VERSION) is an incorrect format. It should be in 'v{MAJOR}.{MINOR}.{PATCH}(-{PRERELEASE_NAME}.{PRERELEASE_VERSION})' form." fi echo " > Is this version ($VERSION) unique?" git describe --exact-match "$VERSION_TAG" > /dev/null 2>&1 if [ $? -eq 0 ]; then if [ -z "$FORCE_TAG" ]; then die "This tag ($VERSION) already exists. Aborting. Append '-f' to override" else echo " > NO, but force was specified." fi else echo " > Yes, tag is unique" fi if [ ! -f "$RELEASE_NOTES" ]; then echo " > Failed to find $RELEASE_NOTES. Prompting editor" RELEASE_NOTES=.release-changes LATEST_TAG=`git for-each-ref refs/tags --sort=-refname --format="%(refname:short)" | grep -E "^v\d+\.\d+\.\d+(-\w+(\.\d)?)?\$" | ruby -e 'puts STDIN.read.split("\n").sort { |a,b| Gem::Version.new(a.gsub(/^v/, "")) <=> Gem::Version.new(b.gsub(/^v/, "")) }.last'` echo " > Latest tag ${LATEST_TAG}" echo "${POD_NAME} v$VERSION" > $RELEASE_NOTES echo "================" >> $RELEASE_NOTES echo >> $RELEASE_NOTES echo "# Changelog from ${LATEST_TAG}..HEAD" >> $RELEASE_NOTES git log ${LATEST_TAG}..HEAD | sed -e 's/^/# /' >> $RELEASE_NOTES $EDITOR $RELEASE_NOTES diff -q $RELEASE_NOTES ${RELEASE_NOTES}.backup > /dev/null 2>&1 STATUS=$? rm ${RELEASE_NOTES}.backup if [ $STATUS -eq 0 ]; then rm $RELEASE_NOTES die "No changes in release notes file. Aborting." fi fi echo " > Release notes: $RELEASE_NOTES" if [ ! -f "$PODSPEC" ]; then die "Cannot find podspec: $PODSPEC. Aborting." fi echo " > Podspec exists" git config --get user.signingkey > /dev/null || { echo "[ERROR] No PGP found to sign tag. Aborting." echo echo " Creating a release requires signing the tag for security purposes. This allows users to verify the git cloned tree is from a trusted source." echo " From a security perspective, it is not considered safe to trust the commits (including Author & Signed-off fields). It is easy for any" echo " intermediate between you and the end-users to modify the git repository." echo echo " While not all users may choose to verify the PGP key for tagged releases. It is a good measure to ensure 'this is an official release'" echo " from the official maintainers." echo echo " If you're creating your PGP key for the first time, use RSA with at least 4096 bits." echo echo "Related resources:" echo " - Configuring your system for PGP: https://git-scm.com/book/tr/v2/Git-Tools-Signing-Your-Work" echo " - Why: http://programmers.stackexchange.com/questions/212192/what-are-the-advantages-and-disadvantages-of-cryptographically-signing-commits-a" echo exit 2 } echo " > Found PGP key for git" # Verify cocoapods trunk ownership pod trunk me | grep -q "$POD_NAME" || die "You do not have access to pod repository $POD_NAME. Aborting." echo " > Verified ownership to $POD_NAME pod" echo "--- Releasing version $VERSION (tag: $VERSION_TAG)..." function restore_podspec { if [ -f "${PODSPEC}.backup" ]; then mv -f ${PODSPEC}{.backup,} fi } echo "-> Ensuring no differences to origin/$REMOTE_BRANCH" git fetch origin || die "Failed to fetch origin" git diff --quiet HEAD "origin/$REMOTE_BRANCH" || die "HEAD is not aligned to origin/$REMOTE_BRANCH. Cannot update version safely" # Don't build binaries: see https://github.com/Carthage/Carthage/issues/924 # echo "-> Building Carthage release" # $CARTHAGE build --no-skip-current || die "Failed to build framework for carthage" echo "-> Setting podspec version" cat "$PODSPEC" | grep 's.version' | grep -q "\"$VERSION\"" SET_PODSPEC_VERSION=$? if [ $SET_PODSPEC_VERSION -eq 0 ]; then echo " > Podspec already set to $VERSION. Skipping." else sed -i.backup "s/s.version *= *\".*\"/s.version = \"$VERSION\"/g" "$PODSPEC" || { restore_podspec die "Failed to update version in podspec" } git add ${PODSPEC} || { restore_podspec; die "Failed to add ${PODSPEC} to INDEX"; } git commit -m "Bumping version to $VERSION" || { restore_podspec; die "Failed to push updated version: $VERSION"; } fi if [ -z "$FORCE_TAG" ]; then echo "-> Tagging version" git tag -s "$VERSION_TAG" -F "$RELEASE_NOTES" || die "Failed to tag version" echo "-> Pushing tag to origin" git push origin "$VERSION_TAG" || die "Failed to push tag '$VERSION_TAG' to origin" else echo "-> Tagging version (force)" git tag -f -s "$VERSION_TAG" -F "$RELEASE_NOTES" || die "Failed to tag version" echo "-> Pushing tag to origin (force)" git push origin "$VERSION_TAG" -f || die "Failed to push tag '$VERSION_TAG' to origin" fi if [ $SET_PODSPEC_VERSION -ne 0 ]; then rm $RELEASE_NOTES git push origin "$REMOTE_BRANCH" || die "Failed to push to origin" echo " > Pushed version to origin" fi echo echo "---------------- Released as $VERSION_TAG ----------------" echo # Don't build binaries: see https://github.com/Carthage/Carthage/issues/924 # echo "Archiving carthage release..." # $CARTHAGE archive "$CARTHAGE_FRAMEWORK_NAME" || die "Failed to archive framework for carthage" echo echo "Pushing to pod trunk..." $POD trunk push "$PODSPEC" echo echo "================ Finalizing the Release ================" echo echo " - Go to $GITHUB_TAGS_URL and mark this as a release." echo " - Paste the contents of $RELEASE_NOTES into the release notes. Tweak for Github styling." # echo " - Attach ${CARTHAGE_FRAMEWORK_NAME}.framework.zip to it." echo " - Announce!" rm ${PODSPEC}.backup ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Nimble/test ================================================ #!/bin/sh BUILD_DIR=`pwd`/build LATEST_IOS_SDK_VERSION=`xcodebuild -showsdks | grep iphonesimulator | cut -d ' ' -f 4 | ruby -e 'puts STDIN.read.chomp.split("\n").last'` LATEST_OSX_SDK_VERSION=`xcodebuild -showsdks | grep 'macosx' | cut -d ' ' -f 3 | ruby -e 'puts STDIN.read.chomp.split("\n").last'` BUILD_IOS_SDK_VERSION=${NIMBLE_BUILD_IOS_SDK_VERSION:-$LATEST_IOS_SDK_VERSION} RUNTIME_IOS_SDK_VERSION=${NIMBLE_RUNTIME_IOS_SDK_VERSION:-$LATEST_IOS_SDK_VERSION} BUILD_OSX_SDK_VERSION=${NIMBLE_BUILD_OSX_SDK_VERSION:-$LATEST_OSX_SDK_VERSION} set -e GREEN="\x1B[01;92m" CLEAR="\x1B[0m" function color_if_overridden { local actual=$1 local env_var=$2 if [ -z "$env_var" ]; then printf "$actual" else printf "$GREEN$actual$CLEAR" fi } function print_env { echo "=== Environment ===" echo " iOS:" echo " Latest iOS SDK: $LATEST_IOS_SDK_VERSION" echo " Building with iOS SDK: `color_if_overridden $BUILD_IOS_SDK_VERSION $NIMBLE_BUILD_IOS_SDK_VERSION`" echo " Running with iOS SDK: `color_if_overridden $RUNTIME_IOS_SDK_VERSION $NIMBLE_RUNTIME_IOS_SDK_VERSION`" echo echo " Mac OS X:" echo " Latest OS X SDK: $LATEST_OSX_SDK_VERSION" echo " Building with OS X SDK: `color_if_overridden $BUILD_OSX_SDK_VERSION $NIMBLE_BUILD_OSX_SDK_VERSION`" echo echo "======= END =======" echo } function run { echo "$GREEN==>$CLEAR $@" "$@" } function test_ios { run osascript -e 'tell app "iOS Simulator" to quit' run xcodebuild -project Nimble.xcodeproj -scheme "Nimble-iOS" -configuration "Debug" -sdk "iphonesimulator$BUILD_IOS_SDK_VERSION" -destination "name=iPad Air,OS=$RUNTIME_IOS_SDK_VERSION" build test run osascript -e 'tell app "iOS Simulator" to quit' run xcodebuild -project Nimble.xcodeproj -scheme "Nimble-iOS" -configuration "Debug" -sdk "iphonesimulator$BUILD_IOS_SDK_VERSION" -destination "name=iPhone 5s,OS=$RUNTIME_IOS_SDK_VERSION" build test } function test_osx { run xcodebuild -project Nimble.xcodeproj -scheme "Nimble-OSX" -configuration "Debug" -sdk "macosx$BUILD_OSX_SDK_VERSION" build test } function test() { test_ios test_osx } function clean { run rm -rf ~/Library/Developer/Xcode/DerivedData\; true } function help { echo "Usage: $0 COMMANDS" echo echo "COMMANDS:" echo " clean - Cleans the derived data directory of Xcode. Assumes default location" echo " ios - Runs the tests as an iOS device" echo " osx - Runs the tests on Mac OS X 10.10 (Yosemite and newer only)" echo " all - Runs both ios and osx tests" echo " help - Displays this help" echo exit 1 } function main { print_env for arg in $@ do case "$arg" in clean) clean ;; ios) test_ios ;; osx) test_osx ;; test) test ;; all) test ;; help) help ;; esac done if [ $# -eq 0 ]; then clean test fi } main $@ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/.gitignore ================================================ # Xcode # build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata *.xccheckout *.moved-aside DerivedData *.hmap *.ipa *.xcuserstate *.xcscmblueprint # CocoaPods # # We recommend against adding the Pods directory to your .gitignore. However # you should judge for yourself, the pros and cons are mentioned at: # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control # # Pods/ # Carthage # # Add this line if you want to avoid checking in source code from Carthage dependencies. # Carthage/Checkouts Carthage/Build # Mac OS X .DS_Store # Quick Quick.framework.zip ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/.gitmodules ================================================ [submodule "Externals/Nimble"] path = Externals/Nimble url = https://github.com/Quick/Nimble.git ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/.travis.yml ================================================ osx_image: xcode7 language: objective-c before_install: git submodule update --init --recursive script: "rake" ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/CONTRIBUTING.md ================================================ **Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)* - [Welcome to Quick!](#welcome-to-quick!) - [Reporting Bugs](#reporting-bugs) - [Building the Project](#building-the-project) - [Pull Requests](#pull-requests) - [Style Conventions](#style-conventions) - [Core Members](#core-members) - [Code of Conduct](#code-of-conduct) - [Creating a Release](#creating-a-release) # Welcome to Quick! We're building a testing framework for a new generation of Swift and Objective-C developers. Quick should be easy to use and easy to maintain. Let's keep things simple and well-tested. ## Reporting Bugs Nothing is off-limits. If you're having a problem, we want to hear about it. - See a crash? File an issue. - Code isn't compiling, but you don't know why? Sounds like you should submit a new issue, bud. - Went to the kitchen, only to forget why you went in the first place? Better submit an issue. Be sure to include in your issue: - Your Xcode version (eg - Xcode 7.0.1 7A1001) - Your version of Quick / Nimble (eg - v0.7.0 or git sha `7d0b8c21357839a8c5228863b77faecf709254a9`) - What are the steps to reproduce this issue? ## Building the Project - After cloning the repository, run `git submodule update --init` to pull the Nimble submodule. - Use `Quick.xcworkspace` to work on Quick. The workspace includes Nimble, which is used in Quick's tests. ## Pull Requests - Nothing is trivial. Submit pull requests for anything: typos, whitespace, you name it. - Not all pull requests will be merged, but all will be acknowledged. If no one has provided feedback on your request, ping one of the owners by name. - Make sure your pull request includes any necessary updates to the README or other documentation. - Be sure the unit tests for both the OS X and iOS targets of both Quick and Nimble pass before submitting your pull request. You can run all the iOS and OS X unit tests using `rake`. - The `master` branch will always support the stable Xcode version. Other branches will point to their corresponding versions they support. - If you're making a configuration change, make sure to edit both the xcode project and the podspec file. ### Style Conventions - Indent using 4 spaces. - Keep lines 100 characters or shorter. Break long statements into shorter ones over multiple lines. - In Objective-C, use `#pragma mark -` to mark public, internal, protocol, and superclass methods. See `QuickSpec.m` for an example. ## Core Members If a few of your pull requests have been merged, and you'd like a controlling stake in the project, file an issue asking for write access to the repository. ### Code of Conduct Your conduct as a core member is your own responsibility, but here are some "ground rules": - Feel free to push whatever you want to master, and (if you have ownership permissions) to create any repositories you'd like. Ideally, however, all changes should be submitted as GitHub pull requests. No one should merge their own pull request, unless no other core members respond for at least a few days. Pull requests should be issued from personal forks. The Quick repo should be reserved for long-running feature branches. If you'd like to create a new repository, it'd be nice if you created a GitHub issue and gathered some feedback first. - It'd be awesome if you could review, provide feedback on, and close issues or pull requests submitted to the project. Please provide kind, constructive feedback. Please don't be sarcastic or snarky. ## Creating a Release The process is relatively straight forward, but here's is a useful checklist for tagging: - Look at changes from the previously tagged release and write release notes: `git log v0.4.0...HEAD` - Run the release script: `./script/release A.B.C release-notes-file` - Go to [github releases](https://github.com/Quick/Quick/releases) and mark the tagged commit as a release. - Use the same release notes you created for the tag, but tweak up formatting for github. - Attach the carthage release `Quick.framework.zip` to the release. - Announce! ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Documentation/ArrangeActAssert.md ================================================ # Effective Tests Using XCTest: Arrange, Act, and Assert Whether you're using XCTest, Quick, or another testing framework, you can write effective unit tests by following a simple pattern: 1. Arrange 2. Act 3. Assert ## Using Arrange, Act, and Assert For example, let's look at a simple class called `Banana`: ```swift // Banana/Banana.swift /** A delicious banana. Tastes better if you peel it first. */ public class Banana { private var isPeeled = false /** Peels the banana. */ public func peel() { isPeeled = true } /** You shouldn't eat a banana unless it's been peeled. */ public var isEdible: Bool { return isPeeled } } ``` Let's verify the `Banana.peel()` method does what it's supposed to: ```swift // BananaTests/BananaTests.swift class BananaTests: XCTestCase { func testPeel() { // Arrange: Create the banana we'll be peeling. let banana = Banana() // Act: Peel the banana. banana.peel() // Assert: Verify that the banana is now edible. XCTAssertTrue(banana.isEdible) } } ``` ## Using Clear Test Names Our `testPeel()` makes sure that, if the `Banana.peel()` method ever stops working right, we'll know. This usually happens when our application code changes, which either means: 1. We accidentally broke our application code, so we have to fix the application code 2. We changed how our application code works--maybe because we're adding a new feature--so we have to change the test code If our tests start breaking, how do we know which one of these cases applies? It might surprise you that **the name of the test** is our best indication. Good test names: 1. Are clear about what is being tested. 2. Are clear about when the test should pass or fail. Is our `testPeel()` method clearly named? Let's make it clearer: ```diff // BananaTests.swift -func testPeel() { +func testPeel_makesTheBananaEdible() { // Arrange: Create the banana we'll be peeling. let banana = Banana() // Act: Peel the banana. banana.peel() // Assert: Verify that the banana is now edible. XCTAssertTrue(banana.isEdible) } ``` The new name: 1. Is clear about what is being tested: `testPeel` indicates it's the `Banana.peel()` method. 2. Is clear about when the test should pass: `makesTheBananaEdible` indicates the banana is edible once the method has been called. ## Testing Conditions Let's say we want to offer people bananas, using a function called `offer()`: ```swift // Banana/Offer.swift /** Given a banana, returns a string that can be used to offer someone the banana. */ public func offer(banana: Banana) -> String { if banana.isEdible { return "Hey, want a banana?" } else { return "Hey, want me to peel this banana for you?" } } ``` Our application code does one of two things: 1. Either it offers a banana that's already been peeled... 2. ...or it offers an unpeeled banana. Let's write tests for these two cases: ```swift // BananaTests/OfferTests.swift class OfferTests: XCTestCase { func testOffer_whenTheBananaIsPeeled_offersTheBanana() { // Arrange: Create a banana and peel it. let banana = Banana() banana.peel() // Act: Create the string used to offer the banana. let message = offer(banana) // Assert: Verify it's the right string. XCTAssertEqual(message, "Hey, want a banana?") } func testOffer_whenTheBananaIsntPeeled_offersToPeelTheBanana() { // Arrange: Create a banana. let banana = Banana() // Act: Create the string used to offer the banana. let message = offer(banana) // Assert: Verify it's the right string. XCTAssertEqual(message, "Hey, want me to peel this banana for you?") } } ``` Our test names clearly indicate the **conditions** under which our tests should pass: in the case that `whenTheBananaIsntPeeled`, `offer()` should `offersTheBanana`. And if the banana isn't peeled? Well, we have a test for that, too! Notice that we have one test per `if` statement in our application code. This is a great pattern when writing tests: it makes sure every set of conditions is tested. If one of those conditions no longer works, or needs to be changed, we'll know exactly which test needs to be looked at. ## Shorter "Arrange" Steps with `XCTestCase.setUp()` Both of our `OfferTests` tests contain the same "Arrange" code: they both create a banana. We should move that code into a single place. Why? 1. As-is, if we change the `Banana` initializer, we'll have to change every test that creates a banana. 2. Our test methods will be shorter--which is a good thing if (and **only if**) that makes the tests easier to read. Let's move the `Banana` initialization into the `XCTestCase.setUp()` method, which is called once before every test method. ```diff // OfferTests.swift class OfferTests: XCTestCase { + var banana: Banana! + + override func setUp() { + super.setUp() + banana = Banana() + } + func testOffer_whenTheBananaIsPeeled_offersTheBanana() { - // Arrange: Create a banana and peel it. - let banana = Banana() + // Arrange: Peel the banana. banana.peel() // Act: Create the string used to offer the banana. let message = offer(banana) // Assert: Verify it's the right string. XCTAssertEqual(message, "Hey, want a banana?") } func testOffer_whenTheBananaIsntPeeled_offersToPeelTheBanana() { - // Arrange: Create a banana. - let banana = Banana() - // Act: Create the string used to offer the banana. let message = offer(banana) // Assert: Verify it's the right string. XCTAssertEqual(message, "Hey, want me to peel this banana for you?") } } ``` ## Sharing "Arrange" Code Across Multiple Tests If you find yourself using the same "arrange" steps across multiple tests, you may want to define a helper function within your test target: ```swift // BananaTests/BananaHelpers.swift internal func createNewPeeledBanana() -> Banana { let banana = Banana() banana.peel() return banana } ``` > Use a function to define your helpers: functions can't be subclassed, nor can they retain any state. Subclassing and mutable state can make your tests harder to read. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Documentation/BehavioralTesting.md ================================================ # Don't Test Code, Instead Verify Behavior Tests should only fail if the application **behaves differently**. They should test *what* the application code does, not *how* it does those things. - Tests that verify *what* an application does are **behavioral tests**. - Tests that break if the application code changes, even if the behavior remains the same, are **brittle tests**. Let's say we have a banana database, called `GorillaDB`. `GorillaDB` is a key-value store for bananas. We can save bananas: ```swift let database = GorillaDB() let banana = Banana() database.save(banana: banana, key: "my-banana") ``` And we can restore bananas from disk later: ```swift let banana = database.load(key: "my-banana") ``` ## Brittle Tests How can we test this behavior? One way would be to check the size of the database after we save a banana: ```swift // GorillaDBTests.swift func testSave_savesTheBananaToTheDatabase() { // Arrange: Create a database and get its original size. let database = GorillaDB() let originalSize = database.size // Act: Save a banana to the database. let banana = Banana() database.save(banana: banana, key: "test-banana") // Assert: The size of the database should have increased by one. XCTAssertEqual(database.size, originalSize + 1) } ``` Imagine, however, that the source code of `GorillaDB` changes. In order to make reading bananas from the database faster, it maintains a cache of the most frequently used bananas. `GorillaDB.size` grows as the size of the cache grows, and our test fails: ![](http://cl.ly/image/0G2s3B3d2F3O/Screen%20Shot%202015-02-23%20at%204.07.32%20PM.png) ## Behavioral Tests The key to writing behavioral tests is determining exactly what you're expecting your application code to do. In the context of our `testSave_savesTheBananaToTheDatabase` test: what is the behavior we expect when we "save" a banana to the database? "Saving" implies, to me, that we can load it later. So instead of testing that the size of the database increases, we should test that we can load a banana. ```diff // GorillaDBTests.swift func testSave_savesTheBananaToTheDatabase() { // Arrange: Create a database and get its original size. let database = GorillaDB() - let originalSize = database.size // Act: Save a banana to the database. let banana = Banana() database.save(banana: banana, key: "test-banana") - // Assert: The size of the database should have increased by one. - XCTAssertEqual(database.size, originalSize + 1) + // Assert: The bananas saved to and loaded from the database should be the same. + XCTAssertEqual(database.load(key: "test-banana"), banana) } ``` The key to writing behavioral tests is asking: - What exactly should this application code do? - Is my test verifying *only* that behavior? Or could it fail due to other aspects of how the code works? ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Documentation/ConfiguringQuick.md ================================================ # Configuring How Quick Behaves You can customize how Quick behaves by subclassing `QuickConfiguration` and overriding the `QuickConfiguration.Type.configure()` class method: ```swift // Swift import Quick class ProjectDataTestConfiguration: QuickConfiguration { override class func configure(configuration: Configuration) { // ...set options on the configuration object here. } } ``` ```objc // Objective-C #import QuickConfigurationBegin(ProjectDataTestConfiguration) + (void)configure:(Configuration *configuration) { // ...set options on the configuration object here. } QuickConfigurationEnd ``` Projects may include several configurations. Quick does not make any guarantee about the order in which those configurations are executed. ## Adding Global `beforeEach` and `afterEach` Closures Using `QuickConfiguration.beforeEach` and `QuickConfiguration.afterEach`, you can specify closures to be run before or after *every* example in a test suite: ```swift // Swift import Quick import Sea class FinConfiguration: QuickConfiguration { override class func configure(configuration: Configuration) { configuration.beforeEach { Dorsal.sharedFin().height = 0 } } } ``` ```objc // Objective-C #import #import "Dorsal.h" QuickConfigurationBegin(FinConfiguration) + (void)configure:(Configuration *)configuration { [configuration beforeEach:^{ [Dorsal sharedFin].height = 0; }]; } QuickConfigurationEnd ``` In addition, Quick allows you to access metadata regarding the current example being run: ```swift // Swift import Quick class SeaConfiguration: QuickConfiguration { override class func configure(configuration: Configuration) { configuration.beforeEach { exampleMetadata in // ...use the example metadata object to access the current example name, and more. } } } ``` ```objc // Objective-C #import QuickConfigurationBegin(SeaConfiguration) + (void)configure:(Configuration *)configuration { [configuration beforeEachWithMetadata:^(ExampleMetadata *data) { // ...use the example metadata object to access the current example name, and more. }]; } QuickConfigurationEnd ``` ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Documentation/InstallingFileTemplates.md ================================================ # Installing Quick File Templates The Quick repository includes file templates for both Swift and Objective-C specs. ## Alcatraz Quick templates can be installed via [Alcatraz](https://github.com/supermarin/Alcatraz), a package manager for Xcode. Just search for the templates from the Package Manager window. ![](http://f.cl.ly/items/3T3q0G1j0b2t1V0M0T04/Screen%20Shot%202014-06-27%20at%202.01.10%20PM.png) ## Manually via the Rakefile To manually install the templates, just clone the repository and run the `templates:install` rake task: ```sh $ git clone git@github.com:Quick/Quick.git $ rake templates:install ``` Uninstalling is easy, too: ```sh $ rake templates:uninstall ``` ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Documentation/InstallingQuick.md ================================================ # Installing Quick > **If you're using Xcode 6.2 & Swift 1.1,** use Quick `v0.2.*`. > New releases are developed on the `swift-1.1` branch. > > **If you're using Xcode 6.3 & Swift 1.2,** use Quick `v0.3.*`. > New releases are developed on the `master` branch. > > **If you're using Xcode 7.0 & Swift 2.0,** use the latest version of Quick--`v0.6.0` at the time of writing. > New releases are developed on the `swift-2.0` branch. Quick provides the syntax to define examples and example groups. Nimble provides the `expect(...).to` assertion syntax. You may use either one, or both, in your tests. There are three recommended ways of linking Quick to your tests: 1. [Git Submodules](#git-submodules) 2. [CocoaPods](#cocoapods) 3. [Carthage](#carthage) Choose one and follow the instructions below. Once you've completed them, you should be able to `import Quick` from within files in your test target. ## Git Submodules To link Quick and Nimble using Git submodules: 1. Add submodule for Quick. 2. If you don't already have a `.xcworkspace` for your project, create one. ([Here's how](https://developer.apple.com/library/ios/recipes/xcode_help-structure_navigator/articles/Adding_an_Existing_Project_to_a_Workspace.html)) 3. Add `Quick.xcodeproj` to your project's `.xcworkspace`. 4. Add `Nimble.xcodeproj` to your project's `.xcworkspace`. It exists in `path/to/Quick/Externals/Nimble`. By adding Nimble from Quick's dependencies (as opposed to adding directly as a submodule), you'll ensure that you're using the correct version of Nimble for whatever version of Quick you're using. 5. Link `Quick.framework` and `Nimble.framework` in your test target's "Link Binary with Libraries" build phase. First, if you don't already have one, create a directory for your Git submodules. Let's assume you have a directory named `Vendor`. **Step One:** Download Quick and Nimble as Git submodules: ```sh git submodule add git@github.com:Quick/Quick.git Vendor/Quick git submodule add git@github.com:Quick/Nimble.git Vendor/Nimble git submodule update --init --recursive ``` **Step Two:** Add the `Quick.xcodeproj` and `Nimble.xcodeproj` files downloaded above to your project's `.xcworkspace`. For example, this is `Guanaco.xcworkspace`, the workspace for a project that is tested using Quick and Nimble: ![](http://f.cl.ly/items/2b2R0e1h09003u2f0Z3U/Screen%20Shot%202015-02-27%20at%202.19.37%20PM.png) **Step Three:** Link the `Quick.framework` during your test target's `Link Binary with Libraries` build phase. You should see two `Quick.frameworks`; one is for OS X, and the other is for iOS. ![](http://cl.ly/image/2L0G0H1a173C/Screen%20Shot%202014-06-08%20at%204.27.48%20AM.png) Do the same for the `Nimble.framework`, and you're done! **Updating the Submodules:** If you ever want to update the Quick or Nimble submodules to latest version, enter the Quick directory and pull from the master repository: ```sh cd /path/to/your/project/Vendor/Quick git checkout master git pull --rebase origin master ``` Your Git repository will track changes to submodules. You'll want to commit the fact that you've updated the Quick submodule: ```sh cd /path/to/your/project git commit -m "Updated Quick submodule" ``` **Cloning a Repository that Includes a Quick Submodule:** After other people clone your repository, they'll have to pull down the submodules as well. They can do so by running the `git submodule update` command: ```sh git submodule update --init --recursive ``` You can read more about Git submodules [here](http://git-scm.com/book/en/Git-Tools-Submodules). ## CocoaPods First, update CocoaPods to Version 0.36.0 or newer, which is necessary to install CocoaPods using Swift. Then, add Quick and Nimble to your Podfile. Additionally, the ```use_frameworks!``` line is necessary for using Swift in CocoaPods: ```rb # Podfile use_frameworks! def testing_pods # If you're using Xcode 7 / Swift 2 pod 'Quick', '~> 0.6.0' pod 'Nimble', '2.0.0-rc.2' # If you're using Xcode 6 / Swift 1.2 pod 'Quick', '~> 0.3.0' pod 'Nimble', '~> 1.0.0' end target 'MyTests' do testing_pods end target 'MyUITests' do testing_pods end ``` Finally, download and link Quick and Nimble to your tests: ```sh pod install ``` ### Using Swift 1.2? The latest release of Quick (0.4.0) is for Swift 2 (Xcode 7), but the latest Nimble (1.0.0) is for Swift 1.2 (Xcode 6). If you want Xcode 6 do: ```sh target 'MyTests' do use_frameworks! pod 'Quick', '~>0.3.0' pod 'Nimble', '~>1.0.0' end ``` ## [Carthage](https://github.com/Carthage/Carthage) As test targets do not have the "Embedded Binaries" section, the frameworks must be added to the target's "Link Binary With Libraries" as well as a "Copy Files" build phase to copy them to the target's Frameworks destination. > As Carthage builds dynamic frameworks, you will need a valid code signing identity set up. 1. Add Quick to your [`Cartfile.private`](https://github.com/Carthage/Carthage/blob/master/Documentation/Artifacts.md#cartfileprivate): ``` github "Quick/Quick" github "Quick/Nimble" ``` 2. Run `carthage update`. 3. From your `Carthage/Build/[platform]/` directory, add both Quick and Nimble to your test target's "Link Binary With Libraries" build phase: ![](http://i.imgur.com/pBkDDk5.png) 4. For your test target, create a new build phase of type "Copy Files": ![](http://i.imgur.com/jZATIjQ.png) 5. Set the "Destination" to "Frameworks", then add both frameworks: ![](http://i.imgur.com/rpnyWGH.png) This is not "the one and only way" to use Carthage to manage dependencies. For further reference check out the [Carthage documentation](https://github.com/Carthage/Carthage/blob/master/README.md). ### (Not Recommended) Running Quick Specs on a Physical iOS Device In order to run specs written in Quick on device, you need to add `Quick.framework` and `Nimble.framework` as `Embedded Binaries` to the `Host Application` of the test target. After adding a framework as an embedded binary, Xcode will automatically link the host app against the framework. ![](http://indiedev.kapsi.fi/images/embed-in-host.png) ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Documentation/MoreResources.md ================================================ # More Resources ## Examples of Quick Specs Quick is used by many companies, open-source projects, and individuals, including [GitHub](https://github.com/github) and [ReactiveCocoa](https://github.com/ReactiveCocoa). For examples, check out: - https://github.com/ReactiveCocoa/ReactiveCocoa - https://github.com/github/Archimedes - https://github.com/libgit2/objective-git - https://github.com/jspahrsummers/RXSwift - https://github.com/artsy/eidolon - https://github.com/AshFurrow/Moya - https://github.com/nerdyc/Squeal - https://github.com/pepibumur/SugarRecord ## More on Unit Testing for OS X and iOS Apps - **[Quality Coding](http://qualitycoding.org/)**: A blog on iOS development that focuses on unit testing. - **[OCMock Tutorials](http://ocmock.org/tutorials/)**: Use OCMock when you need "fake objects" in your tests. - **[Nocilla: Stunning HTTP stubbing for iOS and Mac OS X](https://github.com/luisobo/Nocilla)**: Use this library to test code that sends requests to, and receives responses from, the Internet. - **[Pivotal Labs: Writing Beautiful Specs with Jasmine Custom Matchers](http://pivotallabs.com/writing-beautiful-specs-jasmine-custom-matchers/)**: See [the Nimble documentation](https://github.com/Quick/Nimble) for instructions on how to write custom matchers in Nimble. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Documentation/NimbleAssertions.md ================================================ # Clearer Tests Using Nimble Assertions When code doesn't work the way it's supposed to, unit tests should make it **clear** exactly what's wrong. Take the following function which, given a bunch of monkeys, only returns the silly monkeys in the bunch: ```swift public func silliest(monkeys: [Monkey]) -> [Monkey] { return monkeys.filter { $0.silliness == .VerySilly } } ``` Now let's say we have a unit test for this function: ```swift func testSilliest_whenMonkeysContainSillyMonkeys_theyreIncludedInTheResult() { let kiki = Monkey(name: "Kiki", silliness: .ExtremelySilly) let carl = Monkey(name: "Carl", silliness: .NotSilly) let jane = Monkey(name: "Jane", silliness: .VerySilly) let sillyMonkeys = silliest([kiki, carl, jane]) XCTAssertTrue(contains(sillyMonkeys, kiki)) } ``` The test fails with the following failure message: ``` XCTAssertTrue failed ``` ![](http://f.cl.ly/items/1G17453p47090y30203d/Screen%20Shot%202015-02-26%20at%209.08.27%20AM.png) The failure message leaves a lot to be desired. It leaves us wondering, "OK, so something that should have been true was false--but what?" That confusion slows us down, since we now have to spend time deciphering test code. ## Better Failure Messages, Part 1: Manually Providing `XCTAssert` Failure Messages `XCTAssert` assertions allow us to specify a failure message of our own, which certainly helps: ```diff func testSilliest_whenMonkeysContainSillyMonkeys_theyreIncludedInTheResult() { let kiki = Monkey(name: "Kiki", silliness: .ExtremelySilly) let carl = Monkey(name: "Carl", silliness: .NotSilly) let jane = Monkey(name: "Jane", silliness: .VerySilly) let sillyMonkeys = silliest([kiki, carl, jane]) - XCTAssertTrue(contains(sillyMonkeys, kiki)) + XCTAssertTrue(contains(sillyMonkeys, kiki), "Expected sillyMonkeys to contain 'Kiki'") } ``` But we have to write our own failure message. ## Better Failure Messages, Part 2: Nimble Failure Messages Nimble makes your test assertions, and their failure messages, easier to read: ```diff func testSilliest_whenMonkeysContainSillyMonkeys_theyreIncludedInTheResult() { let kiki = Monkey(name: "Kiki", silliness: .ExtremelySilly) let carl = Monkey(name: "Carl", silliness: .NotSilly) let jane = Monkey(name: "Jane", silliness: .VerySilly) let sillyMonkeys = silliest([kiki, carl, jane]) - XCTAssertTrue(contains(sillyMonkeys, kiki), "Expected sillyMonkeys to contain 'Kiki'") + expect(sillyMonkeys).to(contain(kiki)) } ``` We don't have to write our own failure message--the one provided by Nimble is already very readable: ``` expected to contain , got <[Monkey(name: Jane, silliness: VerySilly)]> ``` ![](http://f.cl.ly/items/3N2e3g2K3W123b1L1J0G/Screen%20Shot%202015-02-26%20at%2011.27.02%20AM.png) The failure message makes it clear what's wrong: we were expecting `kiki` to be included in the result of `silliest()`, but the result only contains `jane`. Now that we know exactly what's wrong, it's easy to fix the issue: ```diff public func silliest(monkeys: [Monkey]) -> [Monkey] { - return monkeys.filter { $0.silliness == .VerySilly } + return monkeys.filter { $0.silliness == .VerySilly || $0.silliness == .ExtremelySilly } } ``` Nimble provides many different kind of assertions, each with great failure messages. And unlike `XCTAssert`, you don't have to type your own failure message every time. For the full list of Nimble assertions, check out the [Nimble README](https://github.com/Quick/Nimble). Below is just a sample, to whet your appetite: ```swift expect(1 + 1).to(equal(2)) expect(1.2).to(beCloseTo(1.1, within: 0.1)) expect(3) > 2 expect("seahorse").to(contain("sea")) expect(["Atlantic", "Pacific"]).toNot(contain("Mississippi")) expect(ocean.isClean).toEventually(beTruthy()) ``` ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Documentation/QuickExamplesAndGroups.md ================================================ # Organized Tests with Quick Examples and Example Groups Quick uses a special syntax to define **examples** and **example groups**. In *[Effective Tests Using XCTest: Arrange, Act, and Assert](ArrangeActAssert.md)*, we learned that a good test method name is crucial--when a test starts failing, it's the best way to determine whether we have to fix the application code or update the test. Quick examples and example groups serve two purposes: 1. They encourage you to write descriptive test names. 2. They greatly simplify the test code in the "arrange" step of your tests. ## Examples Using `it` Examples, defined with the `it` function, use assertions to demonstrate how code should behave. These are like test methods in XCTest. `it` takes two parameters: the name of the example, and a closure. The examples below specify how the `Sea.Dolphin` class should behave. A new dolphin should be smart and friendly: ```swift // Swift import Quick import Nimble import Sea class DolphinSpec: QuickSpec { override func spec() { it("is friendly") { expect(Dolphin().isFriendly).to(beTruthy()) } it("is smart") { expect(Dolphin().isSmart).to(beTruthy()) } } } ``` ```objc // Objective-C #import #import QuickSpecBegin(DolphinSpec) it(@"is friendly", ^{ expect(@([[Dolphin new] isFriendly])).to(beTruthy()); }); it(@"is smart", ^{ expect(@([[Dolphin new] isSmart])).to(beTruthy()); }); QuickSpecEnd ``` Use descriptions to make it clear what your examples are testing. Descriptions can be of any length and use any character, including characters from languages besides English, or even emoji! :v: :sunglasses: ## Example Groups Using `describe` and `context` Example groups are logical groupings of examples. Example groups can share setup and teardown code. ### Describing Classes and Methods Using `describe` To specify the behavior of the `Dolphin` class's `click` method--in other words, to test the method works--several `it` examples can be grouped together using the `describe` function. Grouping similar examples together makes the spec easier to read: ```swift // Swift import Quick import Nimble class DolphinSpec: QuickSpec { override func spec() { describe("a dolphin") { describe("its click") { it("is loud") { let click = Dolphin().click() expect(click.isLoud).to(beTruthy()) } it("has a high frequency") { let click = Dolphin().click() expect(click.hasHighFrequency).to(beTruthy()) } } } } } ``` ```objc // Objective-C #import #import QuickSpecBegin(DolphinSpec) describe(@"a dolphin", ^{ describe(@"its click", ^{ it(@"is loud", ^{ Click *click = [[Dolphin new] click]; expect(@(click.isLoud)).to(beTruthy()); }); it(@"has a high frequency", ^{ Click *click = [[Dolphin new] click]; expect(@(click.hasHighFrequency)).to(beTruthy()); }); }); }); QuickSpecEnd ``` When these two examples are run in Xcode, they'll display the description from the `describe` and `it` functions: 1. `DolphinSpec.a_dolphin_its_click_is_loud` 2. `DolphinSpec.a_dolphin_its_click_has_a_high_frequency` Again, it's clear what each of these examples is testing. ### Sharing Setup/Teardown Code Using `beforeEach` and `afterEach` Example groups don't just make the examples clearer, they're also useful for sharing setup and teardown code among examples in a group. In the example below, the `beforeEach` function is used to create a brand new instance of a dolphin and its click before each example in the group. This ensures that both are in a "fresh" state for every example: ```swift // Swift import Quick import Nimble class DolphinSpec: QuickSpec { override func spec() { describe("a dolphin") { var dolphin: Dolphin! beforeEach { dolphin = Dolphin() } describe("its click") { var click: Click! beforeEach { click = dolphin.click() } it("is loud") { expect(click.isLoud).to(beTruthy()) } it("has a high frequency") { expect(click.hasHighFrequency).to(beTruthy()) } } } } } ``` ```objc // Objective-C #import #import QuickSpecBegin(DolphinSpec) describe(@"a dolphin", ^{ __block Dolphin *dolphin = nil; beforeEach(^{ dolphin = [Dolphin new]; }); describe(@"its click", ^{ __block Click *click = nil; beforeEach(^{ click = [dolphin click]; }); it(@"is loud", ^{ expect(@(click.isLoud)).to(beTruthy()); }); it(@"has a high frequency", ^{ expect(@(click.hasHighFrequency)).to(beTruthy()); }); }); }); QuickSpecEnd ``` Sharing setup like this might not seem like a big deal with the dolphin example, but for more complicated objects, it saves a lot of typing! To execute code *after* each example, use `afterEach`. ### Specifying Conditional Behavior Using `context` Dolphins use clicks for echolocation. When they approach something particularly interesting to them, they release a series of clicks in order to get a better idea of what it is. The tests need to show that the `click` method behaves differently in different circumstances. Normally, the dolphin just clicks once. But when the dolphin is close to something interesting, it clicks several times. This can be expressed using `context` functions: one `context` for the normal case, and one `context` for when the dolphin is close to something interesting: ```swift // Swift import Quick import Nimble class DolphinSpec: QuickSpec { override func spec() { describe("a dolphin") { var dolphin: Dolphin! beforeEach { dolphin = Dolphin() } describe("its click") { context("when the dolphin is not near anything interesting") { it("is only emitted once") { expect(dolphin!.click().count).to(equal(1)) } } context("when the dolphin is near something interesting") { beforeEach { let ship = SunkenShip() Jamaica.dolphinCove.add(ship) Jamaica.dolphinCove.add(dolphin) } it("is emitted three times") { expect(dolphin.click().count).to(equal(3)) } } } } } } ``` ```objc // Objective-C #import #import QuickSpecBegin(DolphinSpec) describe(@"a dolphin", ^{ __block Dolphin *dolphin = nil; beforeEach(^{ dolphin = [Dolphin new]; }); describe(@"its click", ^{ context(@"when the dolphin is not near anything interesting", ^{ it(@"is only emitted once", ^{ expect(@([[dolphin click] count])).to(equal(@1)); }); }); context(@"when the dolphin is near something interesting", ^{ beforeEach(^{ [[Jamaica dolphinCove] add:[SunkenShip new]]; [[Jamaica dolphinCove] add:dolphin]; }); it(@"is emitted three times", ^{ expect(@([[dolphin click] count])).to(equal(@3)); }); }); }); }); QuickSpecEnd ``` ### Test Readability: Quick and XCTest In [Effective Tests Using XCTest: Arrange, Act, and Assert](ArrangeActAssert.md), we looked at how one test per condition was a great way to organize test code. In XCTest, that leads to long test method names: ```swift func testDolphin_click_whenTheDolphinIsNearSomethingInteresting_isEmittedThreeTimes() { // ... } ``` Using Quick, the conditions are much easier to read, and we can perform setup for each example group: ```swift describe("a dolphin") { describe("its click") { context("when the dolphin is near something interesting") { it("is emitted three times") { // ... } } } } ``` ## Temporarily Disabling Examples or Groups You can temporarily disable examples or example groups that don't pass yet. The names of the examples will be printed out along with the test results, but they won't be run. You can disable an example or group by prepending `x`: ```swift // Swift xdescribe("its click") { // ...none of the code in this closure will be run. } xcontext("when the dolphin is not near anything interesting") { // ...none of the code in this closure will be run. } xit("is only emitted once") { // ...none of the code in this closure will be run. } ``` ```objc // Objective-C xdescribe(@"its click", ^{ // ...none of the code in this closure will be run. }); xcontext(@"when the dolphin is not near anything interesting", ^{ // ...none of the code in this closure will be run. }); xit(@"is only emitted once", ^{ // ...none of the code in this closure will be run. }); ``` ## Temporarily Running a Subset of Focused Examples Sometimes it helps to focus on only one or a few examples. Running one or two examples is faster than the entire suite, after all. You can run only one or two by using the `fit` function. You can also focus a group of examples using `fdescribe` or `fcontext`: ```swift fit("is loud") { // ...only this focused example will be run. } it("has a high frequency") { // ...this example is not focused, and will not be run. } fcontext("when the dolphin is near something interesting") { // ...examples in this group are also focused, so they'll be run. } ``` ```objc fit(@"is loud", { // ...only this focused example will be run. }); it(@"has a high frequency", ^{ // ...this example is not focused, and will not be run. }); fcontext(@"when the dolphin is near something interesting", ^{ // ...examples in this group are also focused, so they'll be run. }); ``` ## Global Setup/Teardown Using `beforeSuite` and `afterSuite` Some test setup needs to be performed before *any* examples are run. For these cases, use `beforeSuite` and `afterSuite`. In the example below, a database of all the creatures in the ocean is created before any examples are run. That database is torn down once all the examples have finished: ```swift // Swift import Quick class DolphinSpec: QuickSpec { override func spec() { beforeSuite { OceanDatabase.createDatabase(name: "test.db") OceanDatabase.connectToDatabase(name: "test.db") } afterSuite { OceanDatabase.teardownDatabase(name: "test.db") } describe("a dolphin") { // ... } } } ``` ```objc // Objective-C #import QuickSpecBegin(DolphinSpec) beforeSuite(^{ [OceanDatabase createDatabase:@"test.db"]; [OceanDatabase connectToDatabase:@"test.db"]; }); afterSuite(^{ [OceanDatabase teardownDatabase:@"test.db"]; }); describe(@"a dolphin", ^{ // ... }); QuickSpecEnd ``` You can specify as many `beforeSuite` and `afterSuite` as you like. All `beforeSuite` closures will be executed before any tests run, and all `afterSuite` closures will be executed after all the tests are finished. There is no guarantee as to what order these closures will be executed in. ## Accessing Metadata for the Current Example There may be some cases in which you'd like the know the name of the example that is currently being run, or how many have been run so far. Quick provides access to this metadata in `beforeEach` and `afterEach` closures. ```swift beforeEach { exampleMetadata in println("Example number \(exampleMetadata.exampleIndex) is about to be run.") } afterEach { exampleMetadata in println("Example number \(exampleMetadata.exampleIndex) has run.") } ``` ```objc beforeEachWithMetadata(^(ExampleMetadata *exampleMetadata){ NSLog(@"Example number %l is about to be run.", (long)exampleMetadata.exampleIndex); }); afterEachWithMetadata(^(ExampleMetadata *exampleMetadata){ NSLog(@"Example number %l has run.", (long)exampleMetadata.exampleIndex); }); ``` ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Documentation/QuickInObjectiveC.md ================================================ # Using Quick in Objective-C Quick works equally well in both Swift and Objective-C. There are two notes to keep in mind when using Quick in Objective-C, however, which are described below. ## The Optional Shorthand Syntax Importing Quick in an Objective-C file defines macros named `it` and `itShouldBehaveLike`, as well as functions like `context()` and `describe()`. If the project you are testing also defines symbols with these names, you may encounter confusing build failures. In that case, you can avoid namespace collision by turning off Quick's optional "shorthand" syntax: ```objc #define QUICK_DISABLE_SHORT_SYNTAX 1 #import QuickSpecBegin(DolphinSpec) // ... QuickSpecEnd ``` You must define the `QUICK_DISABLE_SHORT_SYNTAX` macro *before* importing the Quick header. ## Your Test Target Must Include At Least One Swift File The Swift stdlib will not be linked into your test target, and thus Quick will fail to execute properly, if you test target does not contain *at least one* Swift file. Without at least one Swift file, your tests will exit prematurely with the following error: ``` *** Test session exited(82) without checking in. Executable cannot be loaded for some other reason, such as a problem with a library it depends on or a code signature/entitlements mismatch. ``` To fix the problem, add a blank file called `SwiftSpec.swift` to your test target: ```swift // SwiftSpec.swift import Quick ``` > For more details on this issue, see https://github.com/Quick/Quick/issues/164. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Documentation/README.md ================================================ # Documentation Quick helps you verify how your Swift and Objective-C programs behave. Doing so effectively isn't just a matter of knowing how to use Quick, however. The guides in this directory can help you write effective tests--not just using Quick, but even XCTest or other testing frameworks. Each guide covers a particular topic. If you're completely new to unit testing, consider reading them in the order they're introduced below: - **[Setting Up Tests in Your Xcode Project](SettingUpYourXcodeProject.md)**: Read this if you're having trouble using your application code from within your test files. - **[Effective Tests Using XCTest: Arrange, Act, and Assert](ArrangeActAssert.md)**: Read this to learn how to write `XCTestCase` tests that will help you write code faster and more effectively. - **[Don't Test Code, Instead Verify Behavior](BehavioralTesting.md)**: Read this to learn what kinds of tests speed you up, and which ones will only end up slowing you down. - **[Clearer Tests Using Nimble Assertions](NimbleAssertions.md)**: Read this to learn how to use Nimble to generate better failure messages. Better failure messages help you move faster, by spending less time figuring out why a test failed. - **[Organized Tests with Quick Examples and Example Groups](QuickExamplesAndGroups.md)**: Read this to learn how Quick can help you write even more effective tests, using *examples* and *example groups*. - **[Testing OS X and iOS Applications](TestingApps.md)**: Read this to learn more about testing code that uses the AppKit and UIKit frameworks. - **[Reducing Test Boilerplate with Shared Assertions](SharedExamples.md)** Read this to learn how to share sets of assertions among your tests. - **[Configuring How Quick Behaves](ConfiguringQuick.md)**: Read this to learn how you can change how Quick behaves when running your test suite. - **[Using Quick in Objective-C](QuickInObjectiveC.md)**: Read this if you experience trouble using Quick in Objective-C. - **[Installing Quick](InstallingQuick.md)**: Read this for instructions on how to add Quick to your project, using Git submodules, CocoaPods, or Carthage. - **[Installing Quick File Templates](InstallingFileTemplates.md)**: Read this to learn how to install file templates that make writing Quick specs faster. - **[More Resources](MoreResources.md)** A list of additional resources on OS X and iOS testing. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Documentation/SettingUpYourXcodeProject.md ================================================ # Setting Up Tests in Your Xcode Project When you create a new project in Xcode 6, a unit test target is included by default. To write unit tests, you'll need to be able to use your main target's code from within your test target. ## Testing Swift Code Using Swift In order to test code written in Swift, you'll need to do three things: 1. Set "defines module" in your `.xcodeproj` to `YES`. * To do this in Xcode: Choose your project, then "Build Settings" header, then "Defines Modules" line, then select "Yes". 2. Mark any class/method/function you want to test `public`, since only `public` symbols are exported. 3. `import YourAppModuleName` in your unit tests. ```swift // MyAppTests.swift import XCTest import MyModule class MyClassTests: XCTestCase { // ... } ``` > Some developers advocate adding Swift source files to your test target. However, this leads to [subtle, hard-to-diagnose errors](https://github.com/Quick/Quick/issues/91), and is not recommended. ## Testing Objective-C Code Using Swift 1. Add a bridging header to your test target. 2. In the bridging header, import the file containing the code you'd like to test. ```objc // MyAppTests-BridgingHeader.h #import "MyClass.h" ``` You can now use the code from `MyClass.h` in your Swift test files. ## Testing Swift Code Using Objective-C 1. Bridge Swift classes and functions you'd like to test to Objective-C by using the `@objc` attribute. 2. Import your module's Swift headers in your unit tests. ```objc #import #import "MyModule-Swift.h" @interface MyClassTests: XCTestCase // ... @end ``` ## Testing Objective-C Code Using Objective-C Import the file defining the code you'd like to test from within your test target: ```objc // MyAppTests.m #import #import "MyClass.h" @interface MyClassTests: XCTestCase // ... @end ``` ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Documentation/SharedExamples.md ================================================ # Reducing Test Boilerplate with Shared Assertions In some cases, the same set of specifications apply to multiple objects. For example, consider a protocol called `Edible`. When a dolphin eats something `Edible`, the dolphin becomes happy. `Mackerel` and `Cod` are both edible. Quick allows you to easily test that a dolphin is happy to eat either one. The example below defines a set of "shared examples" for "something edible", and specifies that both mackerel and cod behave like "something edible": ```swift // Swift import Quick import Nimble class EdibleSharedExamplesConfiguration: QuickConfiguration { override class func configure(configuration: Configuration) { sharedExamples("something edible") { (sharedExampleContext: SharedExampleContext) in it("makes dolphins happy") { let dolphin = Dolphin(happy: false) let edible = sharedExampleContext()["edible"] dolphin.eat(edible) expect(dolphin.isHappy).to(beTruthy()) } } } } class MackerelSpec: QuickSpec { override func spec() { var mackerel: Mackerel! beforeEach { mackerel = Mackerel() } itBehavesLike("something edible") { ["edible": mackerel] } } } class CodSpec: QuickSpec { override func spec() { var cod: Cod! beforeEach { cod = Cod() } itBehavesLike("something edible") { ["edible": cod] } } } ``` ```objc // Objective-C #import #import QuickConfigurationBegin(EdibleSharedExamplesConfiguration) + (void)configure:(Configuration *configuration) { sharedExamples(@"something edible", ^(QCKDSLSharedExampleContext exampleContext) { it(@"makes dolphins happy") { Dolphin *dolphin = [[Dolphin alloc] init]; dolphin.happy = NO; id edible = exampleContext()[@"edible"]; [dolphin eat:edible]; expect(dolphin.isHappy).to(beTruthy()) } }); } QuickConfigurationEnd QuickSpecBegin(MackerelSpec) __block Mackerel *mackerel = nil; beforeEach(^{ mackerel = [[Mackerel alloc] init]; }); itBehavesLike(@"someting edible", ^{ return @{ @"edible": mackerel }; }); QuickSpecEnd QuickSpecBegin(CodSpec) __block Mackerel *cod = nil; beforeEach(^{ cod = [[Cod alloc] init]; }); itBehavesLike(@"someting edible", ^{ return @{ @"edible": cod }; }); QuickSpecEnd ``` Shared examples can include any number of `it`, `context`, and `describe` blocks. They save a *lot* of typing when running the same tests against several different kinds of objects. In some cases, you won't need any additional context. In Swift, you can simply use `sharedExampleFor` closures that take no parameters. This might be useful when testing some sort of global state: ```swift // Swift import Quick sharedExamplesFor("everything under the sea") { // ... } itBehavesLike("everything under the sea") ``` > In Objective-C, you'll have to pass a block that takes a `QCKDSLSharedExampleContext`, even if you don't plan on using that argument. Sorry, but that's the way the cookie crumbles! :cookie: :bomb: You can also "focus" shared examples using the `fitBehavesLike` function. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Documentation/TestingApps.md ================================================ # Testing OS X and iOS Applications *[Setting Up Tests in Your Xcode Project](SettingUpYourXcodeProject.md)* covers everything you need to know to test any Objective-C or Swift function or class. In this section, we'll go over a few additional hints for testing classes like `UIViewController` subclasses. > You can see a short lightning talk covering most of these topics [here](https://vimeo.com/115671189#t=37m50s) (the talk begins at 37'50"). ## Triggering `UIViewController` Lifecycle Events Normally, UIKit triggers lifecycle events for your view controller as it's presented within the app. When testing a `UIViewController`, however, you'll need to trigger these yourself. You can do so in one of three ways: 1. Accessing `UIViewController.view`, which triggers things like `UIViewController.viewDidLoad()`. 2. Use `UIViewController.beginAppearanceTransition()` to trigger most lifecycle events. 3. Directly calling methods like `UIViewController.viewDidLoad()` or `UIViewController.viewWillAppear()`. ```swift // Swift import Quick import Nimble import BananaApp class BananaViewControllerSpec: QuickSpec { override func spec() { var viewController: BananaViewController! beforeEach { viewController = BananaViewController() } describe(".viewDidLoad()") { beforeEach { // Method #1: Access the view to trigger BananaViewController.viewDidLoad(). let _ = viewController.view } it("sets the banana count label to zero") { // Since the label is only initialized when the view is loaded, this // would fail if we didn't access the view in the `beforeEach` above. expect(viewController.bananaCountLabel.text).to(equal("0")) } } describe("the view") { beforeEach { // Method #2: Triggers .viewDidLoad(), .viewWillAppear(), and .viewDidAppear() events. viewController.beginAppearanceTransition(true, animated: false) viewController.endAppearanceTransition() } // ... } describe(".viewWillDisappear()") { beforeEach { // Method #3: Directly call the lifecycle event. viewController.viewWillDisappear(false) } // ... } } } ``` ```objc // Objective-C #import #import #import "BananaViewController.h" QuickSpecBegin(BananaViewControllerSpec) __block BananaViewController *viewController = nil; beforeEach(^{ viewController = [[BananaViewController alloc] init]; }); describe(@"-viewDidLoad", ^{ beforeEach(^{ // Method #1: Access the view to trigger -[BananaViewController viewDidLoad]. [viewController view]; }); it(@"sets the banana count label to zero", ^{ // Since the label is only initialized when the view is loaded, this // would fail if we didn't access the view in the `beforeEach` above. expect(viewController.bananaCountLabel.text).to(equal(@"0")) }); }); describe(@"the view", ^{ beforeEach(^{ // Method #2: Triggers .viewDidLoad(), .viewWillAppear(), and .viewDidAppear() events. [viewController beginAppearanceTransition:YES animated:NO]; [viewController endAppearanceTransition]; }); // ... }); describe(@"-viewWillDisappear", ^{ beforeEach(^{ // Method #3: Directly call the lifecycle event. [viewController viewWillDisappear:NO]; }); // ... }); QuickSpecEnd ``` ## Initializing View Controllers Defined in Storyboards To initialize view controllers defined in a storyboard, you'll need to assign a **Storyboard ID** to the view controller: ![](http://f.cl.ly/items/2X2G381K1h1l2B2Q0g3L/Screen%20Shot%202015-02-27%20at%2011.58.06%20AM.png) Once you've done so, you can instantiate the view controller from within your tests: ```swift // Swift var viewController: BananaViewController! beforeEach { // 1. Instantiate the storyboard. By default, it's name is "Main.storyboard". // You'll need to use a different string here if the name of your storyboard is different. let storyboard = UIStoryboard(name: "Main", bundle: nil) // 2. Use the storyboard to instantiate the view controller. viewController = storyboard.instantiateViewControllerWithIdentifier( "BananaViewControllerID") as! BananaViewController } ``` ```objc // Objective-C __block BananaViewController *viewController = nil; beforeEach(^{ // 1. Instantiate the storyboard. By default, it's name is "Main.storyboard". // You'll need to use a different string here if the name of your storyboard is different. UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; // 2. Use the storyboard to instantiate the view controller. viewController = [storyboard instantiateViewControllerWithIdentifier:@"BananaViewControllerID"]; }); ``` ## Triggering UIControl Events Like Button Taps Buttons and other UIKit classes inherit from `UIControl`, which defines methods that allow us to send control events, like button taps, programmatically. To test behavior that occurs when a button is tapped, you can write: ```swift // Swift describe("the 'more bananas' button") { it("increments the banana count label when tapped") { viewController.moreButton.sendActionsForControlEvents( UIControlEvents.TouchUpInside) expect(viewController.bananaCountLabel.text).to(equal("1")) } } ``` ```objc // Objective-C describe(@"the 'more bananas' button", ^{ it(@"increments the banana count label when tapped", ^{ [viewController.moreButton sendActionsForControlEvents:UIControlEventTouchUpInside]; expect(viewController.bananaCountLabel.text).to(equal(@"1")); }); }); ``` ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/.gitignore ================================================ .DS_Store xcuserdata/ build/ .idea DerivedData/ Nimble.framework.zip # Carthage # # Add this line if you want to avoid checking in source code from Carthage dependencies. # Carthage/Checkouts Carthage/Build ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/.travis.yml ================================================ osx_image: xcode7 language: objective-c env: matrix: - NIMBLE_RUNTIME_IOS_SDK_VERSION=9.0 TYPE=ios - NIMBLE_RUNTIME_OSX_SDK_VERSION=10.10 TYPE=osx script: ./test $TYPE ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/CONTRIBUTING.md ================================================ - [Welcome to Nimble!](#welcome-to-nimble!) - [Reporting Bugs](#reporting-bugs) - [Building the Project](#building-the-project) - [Pull Requests](#pull-requests) - [Style Conventions](#style-conventions) - [Core Members](#core-members) - [Code of Conduct](#code-of-conduct) # Welcome to Nimble! We're building a testing framework for a new generation of Swift and Objective-C developers. Nimble should be easy to use and easy to maintain. Let's keep things simple and well-tested. **tl;dr:** If you've added a file to the project, make sure it's included in both the OS X and iOS targets. ## Reporting Bugs Nothing is off-limits. If you're having a problem, we want to hear about it. - See a crash? File an issue. - Code isn't compiling, but you don't know why? Sounds like you should submit a new issue, bud. - Went to the kitchen, only to forget why you went in the first place? Better submit an issue. Be sure to include in your issue: - Your Xcode version (eg - Xcode 7.0.1 7A1001) - Your version of Nimble (eg - v2.0.0 or git sha `20a3f3b4e63cc8d97c92c4164bf36f2a2c9a6e1b`) - What are the steps to reproduce this issue? ## Building the Project - Use `Nimble.xcodeproj` to work on Nimble. ## Pull Requests - Nothing is trivial. Submit pull requests for anything: typos, whitespace, you name it. - Not all pull requests will be merged, but all will be acknowledged. If no one has provided feedback on your request, ping one of the owners by name. - Make sure your pull request includes any necessary updates to the README or other documentation. - Be sure the unit tests for both the OS X and iOS targets of Nimble before submitting your pull request. You can run all the OS X & iOS unit tests using `./test`. - If you've added a file to the project, make sure it's included in both the OS X and iOS targets. - The `master` branch will always support the stable Xcode version. Other branches will point to their corresponding versions they support. - If you're making a configuration change, make sure to edit both the xcode project and the podspec file. ### Style Conventions - Indent using 4 spaces. - Keep lines 100 characters or shorter. Break long statements into shorter ones over multiple lines. - In Objective-C, use `#pragma mark -` to mark public, internal, protocol, and superclass methods. ## Core Members If a few of your pull requests have been merged, and you'd like a controlling stake in the project, file an issue asking for write access to the repository. ### Code of Conduct Your conduct as a core member is your own responsibility, but here are some "ground rules": - Feel free to push whatever you want to master, and (if you have ownership permissions) to create any repositories you'd like. Ideally, however, all changes should be submitted as GitHub pull requests. No one should merge their own pull request, unless no other core members respond for at least a few days. If you'd like to create a new repository, it'd be nice if you created a GitHub issue and gathered some feedback first. - It'd be awesome if you could review, provide feedback on, and close issues or pull requests submitted to the project. Please provide kind, constructive feedback. Please don't be sarcastic or snarky. ### Creating a Release The process is relatively straight forward, but here's is a useful checklist for tagging: - Look at changes from the previously tagged release and write release notes: `git log v0.4.0...HEAD` - Run the release script: `./script/release A.B.C release-notes-file` - Go to [github releases](https://github.com/Quick/Nimble/releases) and mark the tagged commit as a release. - Use the same release notes you created for the tag, but tweak up formatting for github. - Attach the carthage release `Nimble.framework.zip` to the release. - Announce! ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/LICENSE.md ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2014 Quick Team Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Adapters/AdapterProtocols.swift ================================================ import Foundation /// Protocol for the assertion handler that Nimble uses for all expectations. public protocol AssertionHandler { func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) } /// Global backing interface for assertions that Nimble creates. /// Defaults to a private test handler that passes through to XCTest. /// /// If XCTest is not available, you must assign your own assertion handler /// before using any matchers, otherwise Nimble will abort the program. /// /// @see AssertionHandler public var NimbleAssertionHandler: AssertionHandler = { () -> AssertionHandler in return isXCTestAvailable() ? NimbleXCTestHandler() : NimbleXCTestUnavailableHandler() }() ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Adapters/AssertionDispatcher.swift ================================================ /// AssertionDispatcher allows multiple AssertionHandlers to receive /// assertion messages. /// /// @warning Does not fully dispatch if one of the handlers raises an exception. /// This is possible with XCTest-based assertion handlers. /// public class AssertionDispatcher: AssertionHandler { let handlers: [AssertionHandler] public init(handlers: [AssertionHandler]) { self.handlers = handlers } public func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { for handler in handlers { handler.assert(assertion, message: message, location: location) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Adapters/AssertionRecorder.swift ================================================ import Foundation /// A data structure that stores information about an assertion when /// AssertionRecorder is set as the Nimble assertion handler. /// /// @see AssertionRecorder /// @see AssertionHandler public struct AssertionRecord: CustomStringConvertible { /// Whether the assertion succeeded or failed public let success: Bool /// The failure message the assertion would display on failure. public let message: FailureMessage /// The source location the expectation occurred on. public let location: SourceLocation public var description: String { return "AssertionRecord { success=\(success), message='\(message.stringValue)', location=\(location) }" } } /// An AssertionHandler that silently records assertions that Nimble makes. /// This is useful for testing failure messages for matchers. /// /// @see AssertionHandler public class AssertionRecorder : AssertionHandler { /// All the assertions that were captured by this recorder public var assertions = [AssertionRecord]() public init() {} public func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { assertions.append( AssertionRecord( success: assertion, message: message, location: location)) } } /// Allows you to temporarily replace the current Nimble assertion handler with /// the one provided for the scope of the closure. /// /// Once the closure finishes, then the original Nimble assertion handler is restored. /// /// @see AssertionHandler public func withAssertionHandler(tempAssertionHandler: AssertionHandler, closure: () throws -> Void) { let oldRecorder = NimbleAssertionHandler let capturer = NMBExceptionCapture(handler: nil, finally: ({ NimbleAssertionHandler = oldRecorder })) NimbleAssertionHandler = tempAssertionHandler capturer.tryBlock { try! closure() } } /// Captures expectations that occur in the given closure. Note that all /// expectations will still go through to the default Nimble handler. /// /// This can be useful if you want to gather information about expectations /// that occur within a closure. /// /// @param silently expectations are no longer send to the default Nimble /// assertion handler when this is true. Defaults to false. /// /// @see gatherFailingExpectations public func gatherExpectations(silently silently: Bool = false, closure: () -> Void) -> [AssertionRecord] { let previousRecorder = NimbleAssertionHandler let recorder = AssertionRecorder() let handlers: [AssertionHandler] if silently { handlers = [recorder] } else { handlers = [recorder, previousRecorder] } let dispatcher = AssertionDispatcher(handlers: handlers) withAssertionHandler(dispatcher, closure: closure) return recorder.assertions } /// Captures failed expectations that occur in the given closure. Note that all /// expectations will still go through to the default Nimble handler. /// /// This can be useful if you want to gather information about failed /// expectations that occur within a closure. /// /// @param silently expectations are no longer send to the default Nimble /// assertion handler when this is true. Defaults to false. /// /// @see gatherExpectations /// @see raiseException source for an example use case. public func gatherFailingExpectations(silently silently: Bool = false, closure: () -> Void) -> [AssertionRecord] { let assertions = gatherExpectations(silently: silently, closure: closure) return assertions.filter { assertion in !assertion.success } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Adapters/NimbleXCTestHandler.swift ================================================ import Foundation import XCTest /// Default handler for Nimble. This assertion handler passes failures along to /// XCTest. public class NimbleXCTestHandler : AssertionHandler { public func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { if !assertion { XCTFail("\(message.stringValue)\n", file: location.file, line: location.line) } } } /// Alternative handler for Nimble. This assertion handler passes failures along /// to XCTest by attempting to reduce the failure message size. public class NimbleShortXCTestHandler: AssertionHandler { public func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { if !assertion { let msg: String if let actual = message.actualValue { msg = "got: \(actual) \(message.postfixActual)" } else { msg = "expected \(message.to) \(message.postfixMessage)" } XCTFail("\(msg)\n", file: location.file, line: location.line) } } } /// Fallback handler in case XCTest is unavailable. This assertion handler will abort /// the program if it is invoked. class NimbleXCTestUnavailableHandler : AssertionHandler { func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { fatalError("XCTest is not available and no custom assertion handler was configured. Aborting.") } } func isXCTestAvailable() -> Bool { return NSClassFromString("XCTestCase") != nil } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/DSL+Wait.swift ================================================ import Foundation /// Only classes, protocols, methods, properties, and subscript declarations can be /// bridges to Objective-C via the @objc keyword. This class encapsulates callback-style /// asynchronous waiting logic so that it may be called from Objective-C and Swift. internal class NMBWait: NSObject { internal class func until(timeout timeout: NSTimeInterval, file: String = __FILE__, line: UInt = __LINE__, action: (() -> Void) -> Void) -> Void { var completed = false var token: dispatch_once_t = 0 let result = pollBlock(pollInterval: 0.01, timeoutInterval: timeout) { dispatch_once(&token) { dispatch_async(dispatch_get_main_queue()) { action() { completed = true } } } return completed } switch (result) { case .Failure: let pluralize = (timeout == 1 ? "" : "s") fail("Waited more than \(timeout) second\(pluralize)", file: file, line: line) case .Timeout: fail("Stall on main thread - too much enqueued on main run loop before waitUntil executes.", file: file, line: line) case let .ErrorThrown(error): // Technically, we can never reach this via a public API call fail("Unexpected error thrown: \(error)", file: file, line: line) case .Success: break } } @objc(untilFile:line:action:) internal class func until(file: String = __FILE__, line: UInt = __LINE__, action: (() -> Void) -> Void) -> Void { until(timeout: 1, file: file, line: line, action: action) } } /// Wait asynchronously until the done closure is called. /// /// This will advance the run loop. public func waitUntil(timeout timeout: NSTimeInterval = 1, file: String = __FILE__, line: UInt = __LINE__, action: (() -> Void) -> Void) -> Void { NMBWait.until(timeout: timeout, file: file, line: line, action: action) } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/DSL.swift ================================================ /// Make an expectation on a given actual value. The value given is lazily evaluated. public func expect(@autoclosure(escaping) expression: () throws -> T?, file: String = __FILE__, line: UInt = __LINE__) -> Expectation { return Expectation( expression: Expression( expression: expression, location: SourceLocation(file: file, line: line), isClosure: true)) } /// Make an expectation on a given actual value. The closure is lazily invoked. public func expect(file: String = __FILE__, line: UInt = __LINE__, expression: () throws -> T?) -> Expectation { return Expectation( expression: Expression( expression: expression, location: SourceLocation(file: file, line: line), isClosure: true)) } /// Always fails the test with a message and a specified location. public func fail(message: String, location: SourceLocation) { NimbleAssertionHandler.assert(false, message: FailureMessage(stringValue: message), location: location) } /// Always fails the test with a message. public func fail(message: String, file: String = __FILE__, line: UInt = __LINE__) { fail(message, location: SourceLocation(file: file, line: line)) } /// Always fails the test. public func fail(file: String = __FILE__, line: UInt = __LINE__) { fail("fail() always fails", file: file, line: line) } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Expectation.swift ================================================ import Foundation internal func expressionMatches(expression: Expression, matcher: U, to: String, description: String?) -> (Bool, FailureMessage) { let msg = FailureMessage() msg.userDescription = description msg.to = to do { let pass = try matcher.matches(expression, failureMessage: msg) if msg.actualValue == "" { msg.actualValue = "<\(stringify(try expression.evaluate()))>" } return (pass, msg) } catch let error { msg.actualValue = "an unexpected error thrown: <\(error)>" return (false, msg) } } internal func expressionDoesNotMatch(expression: Expression, matcher: U, toNot: String, description: String?) -> (Bool, FailureMessage) { let msg = FailureMessage() msg.userDescription = description msg.to = toNot do { let pass = try matcher.doesNotMatch(expression, failureMessage: msg) if msg.actualValue == "" { msg.actualValue = "<\(stringify(try expression.evaluate()))>" } return (pass, msg) } catch let error { msg.actualValue = "an unexpected error thrown: <\(error)>" return (false, msg) } } public struct Expectation { let expression: Expression public func verify(pass: Bool, _ message: FailureMessage) { NimbleAssertionHandler.assert(pass, message: message, location: expression.location) } /// Tests the actual value using a matcher to match. public func to(matcher: U, description: String? = nil) { let (pass, msg) = expressionMatches(expression, matcher: matcher, to: "to", description: description) verify(pass, msg) } /// Tests the actual value using a matcher to not match. public func toNot(matcher: U, description: String? = nil) { let (pass, msg) = expressionDoesNotMatch(expression, matcher: matcher, toNot: "to not", description: description) verify(pass, msg) } /// Tests the actual value using a matcher to not match. /// /// Alias to toNot(). public func notTo(matcher: U, description: String? = nil) { toNot(matcher, description: description) } // see: // - AsyncMatcherWrapper for extension // - NMBExpectation for Objective-C interface } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Expression.swift ================================================ import Foundation // Memoizes the given closure, only calling the passed // closure once; even if repeat calls to the returned closure internal func memoizedClosure(closure: () throws -> T) -> (Bool) throws -> T { var cache: T? return ({ withoutCaching in if (withoutCaching || cache == nil) { cache = try closure() } return cache! }) } /// Expression represents the closure of the value inside expect(...). /// Expressions are memoized by default. This makes them safe to call /// evaluate() multiple times without causing a re-evaluation of the underlying /// closure. /// /// @warning Since the closure can be any code, Objective-C code may choose /// to raise an exception. Currently, Expression does not memoize /// exception raising. /// /// This provides a common consumable API for matchers to utilize to allow /// Nimble to change internals to how the captured closure is managed. public struct Expression { internal let _expression: (Bool) throws -> T? internal let _withoutCaching: Bool public let location: SourceLocation public let isClosure: Bool /// Creates a new expression struct. Normally, expect(...) will manage this /// creation process. The expression is memoized. /// /// @param expression The closure that produces a given value. /// @param location The source location that this closure originates from. /// @param isClosure A bool indicating if the captured expression is a /// closure or internally produced closure. Some matchers /// may require closures. For example, toEventually() /// requires an explicit closure. This gives Nimble /// flexibility if @autoclosure behavior changes between /// Swift versions. Nimble internals always sets this true. public init(expression: () throws -> T?, location: SourceLocation, isClosure: Bool = true) { self._expression = memoizedClosure(expression) self.location = location self._withoutCaching = false self.isClosure = isClosure } /// Creates a new expression struct. Normally, expect(...) will manage this /// creation process. /// /// @param expression The closure that produces a given value. /// @param location The source location that this closure originates from. /// @param withoutCaching Indicates if the struct should memoize the given /// closure's result. Subsequent evaluate() calls will /// not call the given closure if this is true. /// @param isClosure A bool indicating if the captured expression is a /// closure or internally produced closure. Some matchers /// may require closures. For example, toEventually() /// requires an explicit closure. This gives Nimble /// flexibility if @autoclosure behavior changes between /// Swift versions. Nimble internals always sets this true. public init(memoizedExpression: (Bool) throws -> T?, location: SourceLocation, withoutCaching: Bool, isClosure: Bool = true) { self._expression = memoizedExpression self.location = location self._withoutCaching = withoutCaching self.isClosure = isClosure } /// Returns a new Expression from the given expression. Identical to a map() /// on this type. This should be used only to typecast the Expression's /// closure value. /// /// The returned expression will preserve location and isClosure. /// /// @param block The block that can cast the current Expression value to a /// new type. public func cast(block: (T?) throws -> U?) -> Expression { return Expression(expression: ({ try block(self.evaluate()) }), location: self.location, isClosure: self.isClosure) } public func evaluate() throws -> T? { return try self._expression(_withoutCaching) } public func withoutCaching() -> Expression { return Expression(memoizedExpression: self._expression, location: location, withoutCaching: true, isClosure: isClosure) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/FailureMessage.swift ================================================ import Foundation /// Encapsulates the failure message that matchers can report to the end user. /// /// This is shared state between Nimble and matchers that mutate this value. public class FailureMessage: NSObject { public var expected: String = "expected" public var actualValue: String? = "" // empty string -> use default; nil -> exclude public var to: String = "to" public var postfixMessage: String = "match" public var postfixActual: String = "" public var userDescription: String? = nil public var stringValue: String { get { if let value = _stringValueOverride { return value } else { return computeStringValue() } } set { _stringValueOverride = newValue } } internal var _stringValueOverride: String? public override init() { } public init(stringValue: String) { _stringValueOverride = stringValue } internal func stripNewlines(str: String) -> String { var lines: [String] = (str as NSString).componentsSeparatedByString("\n") as [String] let whitespace = NSCharacterSet.whitespaceAndNewlineCharacterSet() lines = lines.map { line in line.stringByTrimmingCharactersInSet(whitespace) } return lines.joinWithSeparator("") } internal func computeStringValue() -> String { var value = "\(expected) \(to) \(postfixMessage)" if let actualValue = actualValue { value = "\(expected) \(to) \(postfixMessage), got \(actualValue)\(postfixActual)" } value = stripNewlines(value) if let userDescription = userDescription { return "\(userDescription)\n\(value)" } return value } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSHumanReadableCopyright Copyright © 2014 Jeff Hui. All rights reserved. NSPrincipalClass ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/AllPass.swift ================================================ import Foundation public func allPass (passFunc: (T?) -> Bool) -> NonNilMatcherFunc { return allPass("pass a condition", passFunc) } public func allPass (passName: String, _ passFunc: (T?) -> Bool) -> NonNilMatcherFunc { return createAllPassMatcher() { expression, failureMessage in failureMessage.postfixMessage = passName return passFunc(try expression.evaluate()) } } public func allPass (matcher: V) -> NonNilMatcherFunc { return createAllPassMatcher() { try matcher.matches($0, failureMessage: $1) } } private func createAllPassMatcher (elementEvaluator:(Expression, FailureMessage) throws -> Bool) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.actualValue = nil if let actualValue = try actualExpression.evaluate() { for currentElement in actualValue { let exp = Expression( expression: {currentElement}, location: actualExpression.location) if try !elementEvaluator(exp, failureMessage) { failureMessage.postfixMessage = "all \(failureMessage.postfixMessage)," + " but failed first at element <\(stringify(currentElement))>" + " in <\(stringify(actualValue))>" return false } } failureMessage.postfixMessage = "all \(failureMessage.postfixMessage)" } else { failureMessage.postfixMessage = "all pass (use beNil() to match nils)" return false } return true } } extension NMBObjCMatcher { public class func allPassMatcher(matcher: NMBObjCMatcher) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let location = actualExpression.location let actualValue = try! actualExpression.evaluate() var nsObjects = [NSObject]() var collectionIsUsable = true if let value = actualValue as? NSFastEnumeration { let generator = NSFastGenerator(value) while let obj:AnyObject = generator.next() { if let nsObject = obj as? NSObject { nsObjects.append(nsObject) } else { collectionIsUsable = false break } } } else { collectionIsUsable = false } if !collectionIsUsable { failureMessage.postfixMessage = "allPass only works with NSFastEnumeration (NSArray, NSSet, ...) of NSObjects" failureMessage.expected = "" failureMessage.to = "" return false } let expr = Expression(expression: ({ nsObjects }), location: location) let elementEvaluator: (Expression, FailureMessage) -> Bool = { expression, failureMessage in return matcher.matches( {try! expression.evaluate()}, failureMessage: failureMessage, location: expr.location) } return try! createAllPassMatcher(elementEvaluator).matches( expr, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/BeAKindOf.swift ================================================ import Foundation // A Nimble matcher that catches attempts to use beAKindOf with non Objective-C types public func beAKindOf(expectedClass: Any) -> NonNilMatcherFunc { return NonNilMatcherFunc {actualExpression, failureMessage in failureMessage.stringValue = "beAKindOf only works on Objective-C types since" + " the Swift compiler will automatically type check Swift-only types." + " This expectation is redundant." return false } } /// A Nimble matcher that succeeds when the actual value is an instance of the given class. /// @see beAnInstanceOf if you want to match against the exact class public func beAKindOf(expectedClass: AnyClass) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in let instance = try actualExpression.evaluate() if let validInstance = instance { failureMessage.actualValue = "<\(NSStringFromClass(validInstance.dynamicType)) instance>" } else { failureMessage.actualValue = "" } failureMessage.postfixMessage = "be a kind of \(NSStringFromClass(expectedClass))" return instance != nil && instance!.isKindOfClass(expectedClass) } } extension NMBObjCMatcher { public class func beAKindOfMatcher(expected: AnyClass) -> NMBMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in return try! beAKindOf(expected).matches(actualExpression, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/BeAnInstanceOf.swift ================================================ import Foundation // A Nimble matcher that catches attempts to use beAnInstanceOf with non Objective-C types public func beAnInstanceOf(expectedClass: Any) -> NonNilMatcherFunc { return NonNilMatcherFunc {actualExpression, failureMessage in failureMessage.stringValue = "beAnInstanceOf only works on Objective-C types since" + " the Swift compiler will automatically type check Swift-only types." + " This expectation is redundant." return false } } /// A Nimble matcher that succeeds when the actual value is an instance of the given class. /// @see beAKindOf if you want to match against subclasses public func beAnInstanceOf(expectedClass: AnyClass) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in let instance = try actualExpression.evaluate() if let validInstance = instance { failureMessage.actualValue = "<\(NSStringFromClass(validInstance.dynamicType)) instance>" } else { failureMessage.actualValue = "" } failureMessage.postfixMessage = "be an instance of \(NSStringFromClass(expectedClass))" return instance != nil && instance!.isMemberOfClass(expectedClass) } } extension NMBObjCMatcher { public class func beAnInstanceOfMatcher(expected: AnyClass) -> NMBMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in return try! beAnInstanceOf(expected).matches(actualExpression, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/BeCloseTo.swift ================================================ import Foundation internal let DefaultDelta = 0.0001 internal func isCloseTo(actualValue: NMBDoubleConvertible?, expectedValue: NMBDoubleConvertible, delta: Double, failureMessage: FailureMessage) -> Bool { failureMessage.postfixMessage = "be close to <\(stringify(expectedValue))> (within \(stringify(delta)))" if actualValue != nil { failureMessage.actualValue = "<\(stringify(actualValue!))>" } else { failureMessage.actualValue = "" } return actualValue != nil && abs(actualValue!.doubleValue - expectedValue.doubleValue) < delta } /// A Nimble matcher that succeeds when a value is close to another. This is used for floating /// point values which can have imprecise results when doing arithmetic on them. /// /// @see equal public func beCloseTo(expectedValue: Double, within delta: Double = DefaultDelta) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in return isCloseTo(try actualExpression.evaluate(), expectedValue: expectedValue, delta: delta, failureMessage: failureMessage) } } /// A Nimble matcher that succeeds when a value is close to another. This is used for floating /// point values which can have imprecise results when doing arithmetic on them. /// /// @see equal public func beCloseTo(expectedValue: NMBDoubleConvertible, within delta: Double = DefaultDelta) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in return isCloseTo(try actualExpression.evaluate(), expectedValue: expectedValue, delta: delta, failureMessage: failureMessage) } } public class NMBObjCBeCloseToMatcher : NSObject, NMBMatcher { var _expected: NSNumber var _delta: CDouble init(expected: NSNumber, within: CDouble) { _expected = expected _delta = within } public func matches(actualExpression: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { let actualBlock: () -> NMBDoubleConvertible? = ({ return actualExpression() as? NMBDoubleConvertible }) let expr = Expression(expression: actualBlock, location: location) let matcher = beCloseTo(self._expected, within: self._delta) return try! matcher.matches(expr, failureMessage: failureMessage) } public func doesNotMatch(actualExpression: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { let actualBlock: () -> NMBDoubleConvertible? = ({ return actualExpression() as? NMBDoubleConvertible }) let expr = Expression(expression: actualBlock, location: location) let matcher = beCloseTo(self._expected, within: self._delta) return try! matcher.doesNotMatch(expr, failureMessage: failureMessage) } public var within: (CDouble) -> NMBObjCBeCloseToMatcher { return ({ delta in return NMBObjCBeCloseToMatcher(expected: self._expected, within: delta) }) } } extension NMBObjCMatcher { public class func beCloseToMatcher(expected: NSNumber, within: CDouble) -> NMBObjCBeCloseToMatcher { return NMBObjCBeCloseToMatcher(expected: expected, within: within) } } public func beCloseTo(expectedValues: [Double], within delta: Double = DefaultDelta) -> NonNilMatcherFunc <[Double]> { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be close to <\(stringify(expectedValues))> (each within \(stringify(delta)))" if let actual = try actualExpression.evaluate() { if actual.count != expectedValues.count { return false } else { for (index, actualItem) in actual.enumerate() { if fabs(actualItem - expectedValues[index]) > delta { return false } } return true } } return false } } // MARK: - Operators infix operator ≈ { associativity none precedence 130 } public func ≈(lhs: Expectation<[Double]>, rhs: [Double]) { lhs.to(beCloseTo(rhs)) } public func ≈(lhs: Expectation, rhs: Double) { lhs.to(beCloseTo(rhs)) } public func ≈(lhs: Expectation, rhs: (expected: Double, delta: Double)) { lhs.to(beCloseTo(rhs.expected, within: rhs.delta)) } public func ==(lhs: Expectation, rhs: (expected: Double, delta: Double)) { lhs.to(beCloseTo(rhs.expected, within: rhs.delta)) } // make this higher precedence than exponents so the Doubles either end aren't pulled in // unexpectantly infix operator ± { precedence 170 } public func ±(lhs: Double, rhs: Double) -> (expected: Double, delta: Double) { return (expected: lhs, delta: rhs) } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/BeEmpty.swift ================================================ import Foundation /// A Nimble matcher that succeeds when a value is "empty". For collections, this /// means the are no items in that collection. For strings, it is an empty string. public func beEmpty() -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be empty" let actualSeq = try actualExpression.evaluate() if actualSeq == nil { return true } var generator = actualSeq!.generate() return generator.next() == nil } } /// A Nimble matcher that succeeds when a value is "empty". For collections, this /// means the are no items in that collection. For strings, it is an empty string. public func beEmpty() -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be empty" let actualString = try actualExpression.evaluate() return actualString == nil || (actualString! as NSString).length == 0 } } /// A Nimble matcher that succeeds when a value is "empty". For collections, this /// means the are no items in that collection. For NSString instances, it is an empty string. public func beEmpty() -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be empty" let actualString = try actualExpression.evaluate() return actualString == nil || actualString!.length == 0 } } // Without specific overrides, beEmpty() is ambiguous for NSDictionary, NSArray, // etc, since they conform to SequenceType as well as NMBCollection. /// A Nimble matcher that succeeds when a value is "empty". For collections, this /// means the are no items in that collection. For strings, it is an empty string. public func beEmpty() -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be empty" let actualDictionary = try actualExpression.evaluate() return actualDictionary == nil || actualDictionary!.count == 0 } } /// A Nimble matcher that succeeds when a value is "empty". For collections, this /// means the are no items in that collection. For strings, it is an empty string. public func beEmpty() -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be empty" let actualArray = try actualExpression.evaluate() return actualArray == nil || actualArray!.count == 0 } } /// A Nimble matcher that succeeds when a value is "empty". For collections, this /// means the are no items in that collection. For strings, it is an empty string. public func beEmpty() -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be empty" let actual = try actualExpression.evaluate() return actual == nil || actual!.count == 0 } } extension NMBObjCMatcher { public class func beEmptyMatcher() -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let location = actualExpression.location let actualValue = try! actualExpression.evaluate() failureMessage.postfixMessage = "be empty" if let value = actualValue as? NMBCollection { let expr = Expression(expression: ({ value as NMBCollection }), location: location) return try! beEmpty().matches(expr, failureMessage: failureMessage) } else if let value = actualValue as? NSString { let expr = Expression(expression: ({ value as String }), location: location) return try! beEmpty().matches(expr, failureMessage: failureMessage) } else if let actualValue = actualValue { failureMessage.postfixMessage = "be empty (only works for NSArrays, NSSets, NSDictionaries, NSHashTables, and NSStrings)" failureMessage.actualValue = "\(NSStringFromClass(actualValue.dynamicType)) type" } return false } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/BeGreaterThan.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual value is greater than the expected value. public func beGreaterThan(expectedValue: T?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be greater than <\(stringify(expectedValue))>" return try actualExpression.evaluate() > expectedValue } } /// A Nimble matcher that succeeds when the actual value is greater than the expected value. public func beGreaterThan(expectedValue: NMBComparable?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be greater than <\(stringify(expectedValue))>" let actualValue = try actualExpression.evaluate() let matches = actualValue != nil && actualValue!.NMB_compare(expectedValue) == NSComparisonResult.OrderedDescending return matches } } public func >(lhs: Expectation, rhs: T) { lhs.to(beGreaterThan(rhs)) } public func >(lhs: Expectation, rhs: NMBComparable?) { lhs.to(beGreaterThan(rhs)) } extension NMBObjCMatcher { public class func beGreaterThanMatcher(expected: NMBComparable?) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let expr = actualExpression.cast { $0 as? NMBComparable } return try! beGreaterThan(expected).matches(expr, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/BeGreaterThanOrEqualTo.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual value is greater than /// or equal to the expected value. public func beGreaterThanOrEqualTo(expectedValue: T?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be greater than or equal to <\(stringify(expectedValue))>" let actualValue = try actualExpression.evaluate() return actualValue >= expectedValue } } /// A Nimble matcher that succeeds when the actual value is greater than /// or equal to the expected value. public func beGreaterThanOrEqualTo(expectedValue: T?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be greater than or equal to <\(stringify(expectedValue))>" let actualValue = try actualExpression.evaluate() let matches = actualValue != nil && actualValue!.NMB_compare(expectedValue) != NSComparisonResult.OrderedAscending return matches } } public func >=(lhs: Expectation, rhs: T) { lhs.to(beGreaterThanOrEqualTo(rhs)) } public func >=(lhs: Expectation, rhs: T) { lhs.to(beGreaterThanOrEqualTo(rhs)) } extension NMBObjCMatcher { public class func beGreaterThanOrEqualToMatcher(expected: NMBComparable?) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let expr = actualExpression.cast { $0 as? NMBComparable } return try! beGreaterThanOrEqualTo(expected).matches(expr, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/BeIdenticalTo.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual value is the same instance /// as the expected instance. public func beIdenticalTo(expected: T?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in let actual = try actualExpression.evaluate() failureMessage.actualValue = "\(identityAsString(actual))" failureMessage.postfixMessage = "be identical to \(identityAsString(expected))" return actual === expected && actual !== nil } } public func ===(lhs: Expectation, rhs: T?) { lhs.to(beIdenticalTo(rhs)) } public func !==(lhs: Expectation, rhs: T?) { lhs.toNot(beIdenticalTo(rhs)) } extension NMBObjCMatcher { public class func beIdenticalToMatcher(expected: NSObject?) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in return try! beIdenticalTo(expected).matches(actualExpression, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/BeLessThan.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual value is less than the expected value. public func beLessThan(expectedValue: T?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be less than <\(stringify(expectedValue))>" return try actualExpression.evaluate() < expectedValue } } /// A Nimble matcher that succeeds when the actual value is less than the expected value. public func beLessThan(expectedValue: NMBComparable?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be less than <\(stringify(expectedValue))>" let actualValue = try actualExpression.evaluate() let matches = actualValue != nil && actualValue!.NMB_compare(expectedValue) == NSComparisonResult.OrderedAscending return matches } } public func <(lhs: Expectation, rhs: T) { lhs.to(beLessThan(rhs)) } public func <(lhs: Expectation, rhs: NMBComparable?) { lhs.to(beLessThan(rhs)) } extension NMBObjCMatcher { public class func beLessThanMatcher(expected: NMBComparable?) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let expr = actualExpression.cast { $0 as! NMBComparable? } return try! beLessThan(expected).matches(expr, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/BeLessThanOrEqual.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual value is less than /// or equal to the expected value. public func beLessThanOrEqualTo(expectedValue: T?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be less than or equal to <\(stringify(expectedValue))>" return try actualExpression.evaluate() <= expectedValue } } /// A Nimble matcher that succeeds when the actual value is less than /// or equal to the expected value. public func beLessThanOrEqualTo(expectedValue: T?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be less than or equal to <\(stringify(expectedValue))>" let actualValue = try actualExpression.evaluate() return actualValue != nil && actualValue!.NMB_compare(expectedValue) != NSComparisonResult.OrderedDescending } } public func <=(lhs: Expectation, rhs: T) { lhs.to(beLessThanOrEqualTo(rhs)) } public func <=(lhs: Expectation, rhs: T) { lhs.to(beLessThanOrEqualTo(rhs)) } extension NMBObjCMatcher { public class func beLessThanOrEqualToMatcher(expected: NMBComparable?) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil:false) { actualExpression, failureMessage in let expr = actualExpression.cast { $0 as? NMBComparable } return try! beLessThanOrEqualTo(expected).matches(expr, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/BeLogical.swift ================================================ import Foundation internal func matcherWithFailureMessage(matcher: M, postprocessor: (FailureMessage) -> Void) -> FullMatcherFunc { return FullMatcherFunc { actualExpression, failureMessage, isNegation in let pass: Bool if isNegation { pass = try matcher.doesNotMatch(actualExpression, failureMessage: failureMessage) } else { pass = try matcher.matches(actualExpression, failureMessage: failureMessage) } postprocessor(failureMessage) return pass } } // MARK: beTrue() / beFalse() /// A Nimble matcher that succeeds when the actual value is exactly true. /// This matcher will not match against nils. public func beTrue() -> FullMatcherFunc { return matcherWithFailureMessage(equal(true)) { failureMessage in failureMessage.postfixMessage = "be true" } } /// A Nimble matcher that succeeds when the actual value is exactly false. /// This matcher will not match against nils. public func beFalse() -> FullMatcherFunc { return matcherWithFailureMessage(equal(false)) { failureMessage in failureMessage.postfixMessage = "be false" } } // MARK: beTruthy() / beFalsy() /// A Nimble matcher that succeeds when the actual value is not logically false. public func beTruthy() -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be truthy" let actualValue = try actualExpression.evaluate() if let actualValue = actualValue { if let actualValue = actualValue as? BooleanType { return actualValue.boolValue == true } } return actualValue != nil } } /// A Nimble matcher that succeeds when the actual value is logically false. /// This matcher will match against nils. public func beFalsy() -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be falsy" let actualValue = try actualExpression.evaluate() if let actualValue = actualValue { if let actualValue = actualValue as? BooleanType { return actualValue.boolValue != true } } return actualValue == nil } } extension NMBObjCMatcher { public class func beTruthyMatcher() -> NMBObjCMatcher { return NMBObjCMatcher { actualExpression, failureMessage in let expr = actualExpression.cast { ($0 as? NSNumber)?.boolValue ?? false as BooleanType? } return try! beTruthy().matches(expr, failureMessage: failureMessage) } } public class func beFalsyMatcher() -> NMBObjCMatcher { return NMBObjCMatcher { actualExpression, failureMessage in let expr = actualExpression.cast { ($0 as? NSNumber)?.boolValue ?? false as BooleanType? } return try! beFalsy().matches(expr, failureMessage: failureMessage) } } public class func beTrueMatcher() -> NMBObjCMatcher { return NMBObjCMatcher { actualExpression, failureMessage in let expr = actualExpression.cast { ($0 as? NSNumber)?.boolValue ?? false as Bool? } return try! beTrue().matches(expr, failureMessage: failureMessage) } } public class func beFalseMatcher() -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let expr = actualExpression.cast { ($0 as? NSNumber)?.boolValue ?? false as Bool? } return try! beFalse().matches(expr, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/BeNil.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual value is nil. public func beNil() -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be nil" let actualValue = try actualExpression.evaluate() return actualValue == nil } } extension NMBObjCMatcher { public class func beNilMatcher() -> NMBObjCMatcher { return NMBObjCMatcher { actualExpression, failureMessage in return try! beNil().matches(actualExpression, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/BeginWith.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual sequence's first element /// is equal to the expected value. public func beginWith(startingElement: T) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "begin with <\(startingElement)>" if let actualValue = try actualExpression.evaluate() { var actualGenerator = actualValue.generate() return actualGenerator.next() == startingElement } return false } } /// A Nimble matcher that succeeds when the actual collection's first element /// is equal to the expected object. public func beginWith(startingElement: AnyObject) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "begin with <\(startingElement)>" let collection = try actualExpression.evaluate() return collection != nil && collection!.indexOfObject(startingElement) == 0 } } /// A Nimble matcher that succeeds when the actual string contains expected substring /// where the expected substring's location is zero. public func beginWith(startingSubstring: String) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "begin with <\(startingSubstring)>" if let actual = try actualExpression.evaluate() { let range = actual.rangeOfString(startingSubstring) return range != nil && range!.startIndex == actual.startIndex } return false } } extension NMBObjCMatcher { public class func beginWithMatcher(expected: AnyObject) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let actual = try! actualExpression.evaluate() if let _ = actual as? String { let expr = actualExpression.cast { $0 as? String } return try! beginWith(expected as! String).matches(expr, failureMessage: failureMessage) } else { let expr = actualExpression.cast { $0 as? NMBOrderedCollection } return try! beginWith(expected).matches(expr, failureMessage: failureMessage) } } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/Contain.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual sequence contains the expected value. public func contain(items: T...) -> NonNilMatcherFunc { return contain(items) } private func contain(items: [T]) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "contain <\(arrayAsString(items))>" if let actual = try actualExpression.evaluate() { return all(items) { return actual.contains($0) } } return false } } /// A Nimble matcher that succeeds when the actual string contains the expected substring. public func contain(substrings: String...) -> NonNilMatcherFunc { return contain(substrings) } private func contain(substrings: [String]) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "contain <\(arrayAsString(substrings))>" if let actual = try actualExpression.evaluate() { return all(substrings) { let scanRange = Range(start: actual.startIndex, end: actual.endIndex) let range = actual.rangeOfString($0, options: [], range: scanRange, locale: nil) return range != nil && !range!.isEmpty } } return false } } /// A Nimble matcher that succeeds when the actual string contains the expected substring. public func contain(substrings: NSString...) -> NonNilMatcherFunc { return contain(substrings) } private func contain(substrings: [NSString]) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "contain <\(arrayAsString(substrings))>" if let actual = try actualExpression.evaluate() { return all(substrings) { actual.rangeOfString($0.description).length != 0 } } return false } } /// A Nimble matcher that succeeds when the actual collection contains the expected object. public func contain(items: AnyObject?...) -> NonNilMatcherFunc { return contain(items) } private func contain(items: [AnyObject?]) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "contain <\(arrayAsString(items))>" let actual = try actualExpression.evaluate() return all(items) { item in return actual != nil && actual!.containsObject(item) } } } extension NMBObjCMatcher { public class func containMatcher(expected: [NSObject]) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let location = actualExpression.location let actualValue = try! actualExpression.evaluate() if let value = actualValue as? NMBContainer { let expr = Expression(expression: ({ value as NMBContainer }), location: location) // A straightforward cast on the array causes this to crash, so we have to cast the individual items let expectedOptionals: [AnyObject?] = expected.map({ $0 as AnyObject? }) return try! contain(expectedOptionals).matches(expr, failureMessage: failureMessage) } else if let value = actualValue as? NSString { let expr = Expression(expression: ({ value as String }), location: location) return try! contain(expected as! [String]).matches(expr, failureMessage: failureMessage) } else if actualValue != nil { failureMessage.postfixMessage = "contain <\(arrayAsString(expected))> (only works for NSArrays, NSSets, NSHashTables, and NSStrings)" } else { failureMessage.postfixMessage = "contain <\(arrayAsString(expected))>" } return false } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/EndWith.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual sequence's last element /// is equal to the expected value. public func endWith(endingElement: T) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "end with <\(endingElement)>" if let actualValue = try actualExpression.evaluate() { var actualGenerator = actualValue.generate() var lastItem: T? var item: T? repeat { lastItem = item item = actualGenerator.next() } while(item != nil) return lastItem == endingElement } return false } } /// A Nimble matcher that succeeds when the actual collection's last element /// is equal to the expected object. public func endWith(endingElement: AnyObject) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "end with <\(endingElement)>" let collection = try actualExpression.evaluate() return collection != nil && collection!.indexOfObject(endingElement) == collection!.count - 1 } } /// A Nimble matcher that succeeds when the actual string contains the expected substring /// where the expected substring's location is the actual string's length minus the /// expected substring's length. public func endWith(endingSubstring: String) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "end with <\(endingSubstring)>" if let collection = try actualExpression.evaluate() { let range = collection.rangeOfString(endingSubstring) return range != nil && range!.endIndex == collection.endIndex } return false } } extension NMBObjCMatcher { public class func endWithMatcher(expected: AnyObject) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let actual = try! actualExpression.evaluate() if let _ = actual as? String { let expr = actualExpression.cast { $0 as? String } return try! endWith(expected as! String).matches(expr, failureMessage: failureMessage) } else { let expr = actualExpression.cast { $0 as? NMBOrderedCollection } return try! endWith(expected).matches(expr, failureMessage: failureMessage) } } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/Equal.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual value is equal to the expected value. /// Values can support equal by supporting the Equatable protocol. /// /// @see beCloseTo if you want to match imprecise types (eg - floats, doubles). public func equal(expectedValue: T?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "equal <\(stringify(expectedValue))>" let actualValue = try actualExpression.evaluate() let matches = actualValue == expectedValue && expectedValue != nil if expectedValue == nil || actualValue == nil { if expectedValue == nil { failureMessage.postfixActual = " (use beNil() to match nils)" } return false } return matches } } /// A Nimble matcher that succeeds when the actual value is equal to the expected value. /// Values can support equal by supporting the Equatable protocol. /// /// @see beCloseTo if you want to match imprecise types (eg - floats, doubles). public func equal(expectedValue: [T: C]?) -> NonNilMatcherFunc<[T: C]> { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "equal <\(stringify(expectedValue))>" let actualValue = try actualExpression.evaluate() if expectedValue == nil || actualValue == nil { if expectedValue == nil { failureMessage.postfixActual = " (use beNil() to match nils)" } return false } return expectedValue! == actualValue! } } /// A Nimble matcher that succeeds when the actual collection is equal to the expected collection. /// Items must implement the Equatable protocol. public func equal(expectedValue: [T]?) -> NonNilMatcherFunc<[T]> { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "equal <\(stringify(expectedValue))>" let actualValue = try actualExpression.evaluate() if expectedValue == nil || actualValue == nil { if expectedValue == nil { failureMessage.postfixActual = " (use beNil() to match nils)" } return false } return expectedValue! == actualValue! } } /// A Nimble matcher that succeeds when the actual set is equal to the expected set. public func equal(expectedValue: Set?) -> NonNilMatcherFunc> { return equal(expectedValue, stringify: stringify) } /// A Nimble matcher that succeeds when the actual set is equal to the expected set. public func equal(expectedValue: Set?) -> NonNilMatcherFunc> { return equal(expectedValue, stringify: { if let set = $0 { return stringify(Array(set).sort { $0 < $1 }) } else { return "nil" } }) } private func equal(expectedValue: Set?, stringify: Set? -> String) -> NonNilMatcherFunc> { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "equal <\(stringify(expectedValue))>" if let expectedValue = expectedValue { if let actualValue = try actualExpression.evaluate() { failureMessage.actualValue = "<\(stringify(actualValue))>" if expectedValue == actualValue { return true } let missing = expectedValue.subtract(actualValue) if missing.count > 0 { failureMessage.postfixActual += ", missing <\(stringify(missing))>" } let extra = actualValue.subtract(expectedValue) if extra.count > 0 { failureMessage.postfixActual += ", extra <\(stringify(extra))>" } } } else { failureMessage.postfixActual = " (use beNil() to match nils)" } return false } } public func ==(lhs: Expectation, rhs: T?) { lhs.to(equal(rhs)) } public func !=(lhs: Expectation, rhs: T?) { lhs.toNot(equal(rhs)) } public func ==(lhs: Expectation<[T]>, rhs: [T]?) { lhs.to(equal(rhs)) } public func !=(lhs: Expectation<[T]>, rhs: [T]?) { lhs.toNot(equal(rhs)) } public func ==(lhs: Expectation>, rhs: Set?) { lhs.to(equal(rhs)) } public func !=(lhs: Expectation>, rhs: Set?) { lhs.toNot(equal(rhs)) } public func ==(lhs: Expectation>, rhs: Set?) { lhs.to(equal(rhs)) } public func !=(lhs: Expectation>, rhs: Set?) { lhs.toNot(equal(rhs)) } public func ==(lhs: Expectation<[T: C]>, rhs: [T: C]?) { lhs.to(equal(rhs)) } public func !=(lhs: Expectation<[T: C]>, rhs: [T: C]?) { lhs.toNot(equal(rhs)) } extension NMBObjCMatcher { public class func equalMatcher(expected: NSObject) -> NMBMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in return try! equal(expected).matches(actualExpression, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/HaveCount.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual CollectionType's count equals /// the expected value public func haveCount(expectedValue: T.Index.Distance) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in if let actualValue = try actualExpression.evaluate() { failureMessage.postfixMessage = "have \(actualValue) with count \(expectedValue)" let result = expectedValue == actualValue.count failureMessage.actualValue = "\(actualValue.count)" return result } else { return false } } } /// A Nimble matcher that succeeds when the actual collection's count equals /// the expected value public func haveCount(expectedValue: Int) -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in if let actualValue = try actualExpression.evaluate() { failureMessage.postfixMessage = "have \(actualValue) with count \(expectedValue)" let result = expectedValue == actualValue.count failureMessage.actualValue = "\(actualValue.count)" return result } else { return false } } } extension NMBObjCMatcher { public class func haveCountMatcher(expected: NSNumber) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let location = actualExpression.location let actualValue = try! actualExpression.evaluate() if let value = actualValue as? NMBCollection { let expr = Expression(expression: ({ value as NMBCollection}), location: location) return try! haveCount(expected.integerValue).matches(expr, failureMessage: failureMessage) } else if let actualValue = actualValue { failureMessage.postfixMessage = "get type of NSArray, NSSet, NSDictionary, or NSHashTable" failureMessage.actualValue = "\(NSStringFromClass(actualValue.dynamicType))" } return false } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/Match.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual string satisfies the regular expression /// described by the expected string. public func match(expectedValue: String?) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "match <\(stringify(expectedValue))>" if let actual = try actualExpression.evaluate() { if let regexp = expectedValue { return actual.rangeOfString(regexp, options: .RegularExpressionSearch) != nil } } return false } } extension NMBObjCMatcher { public class func matchMatcher(expected: NSString) -> NMBMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let actual = actualExpression.cast { $0 as? String } return try! match(expected.description).matches(actual, failureMessage: failureMessage) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/MatcherProtocols.swift ================================================ import Foundation /// Implement this protocol to implement a custom matcher for Swift public protocol Matcher { typealias ValueType func matches(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool } /// Objective-C interface to the Swift variant of Matcher. @objc public protocol NMBMatcher { func matches(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool func doesNotMatch(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool } /// Protocol for types that support contain() matcher. @objc public protocol NMBContainer { func containsObject(object: AnyObject!) -> Bool } extension NSArray : NMBContainer {} extension NSSet : NMBContainer {} extension NSHashTable : NMBContainer {} /// Protocol for types that support only beEmpty(), haveCount() matchers @objc public protocol NMBCollection { var count: Int { get } } extension NSSet : NMBCollection {} extension NSDictionary : NMBCollection {} extension NSHashTable : NMBCollection {} extension NSMapTable : NMBCollection {} /// Protocol for types that support beginWith(), endWith(), beEmpty() matchers @objc public protocol NMBOrderedCollection : NMBCollection { func indexOfObject(object: AnyObject!) -> Int } extension NSArray : NMBOrderedCollection {} /// Protocol for types to support beCloseTo() matcher @objc public protocol NMBDoubleConvertible { var doubleValue: CDouble { get } } extension NSNumber : NMBDoubleConvertible { } private let dateFormatter: NSDateFormatter = { let formatter = NSDateFormatter() formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSSS" formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") return formatter }() extension NSDate: NMBDoubleConvertible { public var doubleValue: CDouble { get { return self.timeIntervalSinceReferenceDate } } } extension NMBDoubleConvertible { public var stringRepresentation: String { get { if let date = self as? NSDate { return dateFormatter.stringFromDate(date) } if let debugStringConvertible = self as? CustomDebugStringConvertible { return debugStringConvertible.debugDescription } if let stringConvertible = self as? CustomStringConvertible { return stringConvertible.description } return "" } } } /// Protocol for types to support beLessThan(), beLessThanOrEqualTo(), /// beGreaterThan(), beGreaterThanOrEqualTo(), and equal() matchers. /// /// Types that conform to Swift's Comparable protocol will work implicitly too @objc public protocol NMBComparable { func NMB_compare(otherObject: NMBComparable!) -> NSComparisonResult } extension NSNumber : NMBComparable { public func NMB_compare(otherObject: NMBComparable!) -> NSComparisonResult { return compare(otherObject as! NSNumber) } } extension NSString : NMBComparable { public func NMB_compare(otherObject: NMBComparable!) -> NSComparisonResult { return compare(otherObject as! String) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/RaisesException.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual expression raises an /// exception with the specified name, reason, and/or userInfo. /// /// Alternatively, you can pass a closure to do any arbitrary custom matching /// to the raised exception. The closure only gets called when an exception /// is raised. /// /// nil arguments indicates that the matcher should not attempt to match against /// that parameter. public func raiseException( named named: String? = nil, reason: String? = nil, userInfo: NSDictionary? = nil, closure: ((NSException) -> Void)? = nil) -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in var exception: NSException? let capture = NMBExceptionCapture(handler: ({ e in exception = e }), finally: nil) capture.tryBlock { try! actualExpression.evaluate() return } setFailureMessageForException(failureMessage, exception: exception, named: named, reason: reason, userInfo: userInfo, closure: closure) return exceptionMatchesNonNilFieldsOrClosure(exception, named: named, reason: reason, userInfo: userInfo, closure: closure) } } internal func setFailureMessageForException( failureMessage: FailureMessage, exception: NSException?, named: String?, reason: String?, userInfo: NSDictionary?, closure: ((NSException) -> Void)?) { failureMessage.postfixMessage = "raise exception" if let named = named { failureMessage.postfixMessage += " with name <\(named)>" } if let reason = reason { failureMessage.postfixMessage += " with reason <\(reason)>" } if let userInfo = userInfo { failureMessage.postfixMessage += " with userInfo <\(userInfo)>" } if let _ = closure { failureMessage.postfixMessage += " that satisfies block" } if named == nil && reason == nil && userInfo == nil && closure == nil { failureMessage.postfixMessage = "raise any exception" } if let exception = exception { failureMessage.actualValue = "\(NSStringFromClass(exception.dynamicType)) { name=\(exception.name), reason='\(stringify(exception.reason))', userInfo=\(stringify(exception.userInfo)) }" } else { failureMessage.actualValue = "no exception" } } internal func exceptionMatchesNonNilFieldsOrClosure( exception: NSException?, named: String?, reason: String?, userInfo: NSDictionary?, closure: ((NSException) -> Void)?) -> Bool { var matches = false if let exception = exception { matches = true if named != nil && exception.name != named { matches = false } if reason != nil && exception.reason != reason { matches = false } if userInfo != nil && exception.userInfo != userInfo { matches = false } if let closure = closure { let assertions = gatherFailingExpectations { closure(exception) } let messages = assertions.map { $0.message } if messages.count > 0 { matches = false } } } return matches } public class NMBObjCRaiseExceptionMatcher : NSObject, NMBMatcher { internal var _name: String? internal var _reason: String? internal var _userInfo: NSDictionary? internal var _block: ((NSException) -> Void)? internal init(name: String?, reason: String?, userInfo: NSDictionary?, block: ((NSException) -> Void)?) { _name = name _reason = reason _userInfo = userInfo _block = block } public func matches(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { let block: () -> Any? = ({ actualBlock(); return nil }) let expr = Expression(expression: block, location: location) return try! raiseException( named: _name, reason: _reason, userInfo: _userInfo, closure: _block ).matches(expr, failureMessage: failureMessage) } public func doesNotMatch(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { return !matches(actualBlock, failureMessage: failureMessage, location: location) } public var named: (name: String) -> NMBObjCRaiseExceptionMatcher { return ({ name in return NMBObjCRaiseExceptionMatcher( name: name, reason: self._reason, userInfo: self._userInfo, block: self._block ) }) } public var reason: (reason: String?) -> NMBObjCRaiseExceptionMatcher { return ({ reason in return NMBObjCRaiseExceptionMatcher( name: self._name, reason: reason, userInfo: self._userInfo, block: self._block ) }) } public var userInfo: (userInfo: NSDictionary?) -> NMBObjCRaiseExceptionMatcher { return ({ userInfo in return NMBObjCRaiseExceptionMatcher( name: self._name, reason: self._reason, userInfo: userInfo, block: self._block ) }) } public var satisfyingBlock: (block: ((NSException) -> Void)?) -> NMBObjCRaiseExceptionMatcher { return ({ block in return NMBObjCRaiseExceptionMatcher( name: self._name, reason: self._reason, userInfo: self._userInfo, block: block ) }) } } extension NMBObjCMatcher { public class func raiseExceptionMatcher() -> NMBObjCRaiseExceptionMatcher { return NMBObjCRaiseExceptionMatcher(name: nil, reason: nil, userInfo: nil, block: nil) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Matchers/ThrowError.swift ================================================ import Foundation /// A Nimble matcher that succeeds when the actual expression throws an /// error of the specified type or from the specified case. /// /// Errors are tried to be compared by their implementation of Equatable, /// otherwise they fallback to comparision by _domain and _code. /// /// Alternatively, you can pass a closure to do any arbitrary custom matching /// to the thrown error. The closure only gets called when an error was thrown. /// /// nil arguments indicates that the matcher should not attempt to match against /// that parameter. public func throwError( error: T? = nil, errorType: T.Type? = nil, closure: ((T) -> Void)? = nil) -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in var actualError: ErrorType? do { try actualExpression.evaluate() } catch let catchedError { actualError = catchedError } setFailureMessageForError(failureMessage, actualError: actualError, error: error, errorType: errorType, closure: closure) return errorMatchesNonNilFieldsOrClosure(actualError, error: error, errorType: errorType, closure: closure) } } internal func setFailureMessageForError( failureMessage: FailureMessage, actualError: ErrorType?, error: T?, errorType: T.Type? = nil, closure: ((T) -> Void)?) { failureMessage.postfixMessage = "throw error" if let error = error { if let error = error as? CustomDebugStringConvertible { failureMessage.postfixMessage += " <\(error.debugDescription)>" } else { failureMessage.postfixMessage += " <\(error)>" } } else if errorType != nil || closure != nil { failureMessage.postfixMessage += " from type <\(T.self)>" } if let _ = closure { failureMessage.postfixMessage += " that satisfies block" } if error == nil && errorType == nil && closure == nil { failureMessage.postfixMessage = "throw any error" } if let actualError = actualError { failureMessage.actualValue = "<\(actualError)>" } else { failureMessage.actualValue = "no error" } } internal func errorMatchesExpectedError( actualError: ErrorType, expectedError: T) -> Bool { return actualError._domain == expectedError._domain && actualError._code == expectedError._code } internal func errorMatchesExpectedError( actualError: ErrorType, expectedError: T) -> Bool { if let actualError = actualError as? T { return actualError == expectedError } return false } internal func errorMatchesNonNilFieldsOrClosure( actualError: ErrorType?, error: T?, errorType: T.Type?, closure: ((T) -> Void)?) -> Bool { var matches = false if let actualError = actualError { matches = true if let error = error { if !errorMatchesExpectedError(actualError, expectedError: error) { matches = false } } if let actualError = actualError as? T { if let closure = closure { let assertions = gatherFailingExpectations { closure(actualError as T) } let messages = assertions.map { $0.message } if messages.count > 0 { matches = false } } } else if errorType != nil && closure != nil { // The closure expects another ErrorType as argument, so this // is _supposed_ to fail, so that it becomes more obvious. let assertions = gatherExpectations { expect(actualError is T).to(equal(true)) } precondition(assertions.map { $0.message }.count > 0) matches = false } } return matches } /// A Nimble matcher that succeeds when the actual expression throws any /// error or when the passed closures' arbitrary custom matching succeeds. /// /// This duplication to it's generic adequate is required to allow to receive /// values of the existential type ErrorType in the closure. /// /// The closure only gets called when an error was thrown. public func throwError( closure closure: ((ErrorType) -> Void)? = nil) -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in var actualError: ErrorType? do { try actualExpression.evaluate() } catch let catchedError { actualError = catchedError } setFailureMessageForError(failureMessage, actualError: actualError, closure: closure) return errorMatchesNonNilFieldsOrClosure(actualError, closure: closure) } } internal func setFailureMessageForError( failureMessage: FailureMessage, actualError: ErrorType?, closure: ((ErrorType) -> Void)?) { failureMessage.postfixMessage = "throw error" if let _ = closure { failureMessage.postfixMessage += " that satisfies block" } else { failureMessage.postfixMessage = "throw any error" } if let actualError = actualError { failureMessage.actualValue = "<\(actualError)>" } else { failureMessage.actualValue = "no error" } } internal func errorMatchesNonNilFieldsOrClosure( actualError: ErrorType?, closure: ((ErrorType) -> Void)?) -> Bool { var matches = false if let actualError = actualError { matches = true if let closure = closure { let assertions = gatherFailingExpectations { closure(actualError) } let messages = assertions.map { $0.message } if messages.count > 0 { matches = false } } } return matches } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Nimble.h ================================================ #import #import "NMBExceptionCapture.h" #import "DSL.h" FOUNDATION_EXPORT double NimbleVersionNumber; FOUNDATION_EXPORT const unsigned char NimbleVersionString[]; ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/ObjCExpectation.swift ================================================ internal struct ObjCMatcherWrapper : Matcher { let matcher: NMBMatcher func matches(actualExpression: Expression, failureMessage: FailureMessage) -> Bool { return matcher.matches( ({ try! actualExpression.evaluate() }), failureMessage: failureMessage, location: actualExpression.location) } func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) -> Bool { return matcher.doesNotMatch( ({ try! actualExpression.evaluate() }), failureMessage: failureMessage, location: actualExpression.location) } } // Equivalent to Expectation, but for Nimble's Objective-C interface public class NMBExpectation : NSObject { internal let _actualBlock: () -> NSObject! internal var _negative: Bool internal let _file: String internal let _line: UInt internal var _timeout: NSTimeInterval = 1.0 public init(actualBlock: () -> NSObject!, negative: Bool, file: String, line: UInt) { self._actualBlock = actualBlock self._negative = negative self._file = file self._line = line } private var expectValue: Expectation { return expect(_file, line: _line){ self._actualBlock() as NSObject? } } public var withTimeout: (NSTimeInterval) -> NMBExpectation { return ({ timeout in self._timeout = timeout return self }) } public var to: (NMBMatcher) -> Void { return ({ matcher in self.expectValue.to(ObjCMatcherWrapper(matcher: matcher)) }) } public var toWithDescription: (NMBMatcher, String) -> Void { return ({ matcher, description in self.expectValue.to(ObjCMatcherWrapper(matcher: matcher), description: description) }) } public var toNot: (NMBMatcher) -> Void { return ({ matcher in self.expectValue.toNot( ObjCMatcherWrapper(matcher: matcher) ) }) } public var toNotWithDescription: (NMBMatcher, String) -> Void { return ({ matcher, description in self.expectValue.toNot( ObjCMatcherWrapper(matcher: matcher), description: description ) }) } public var notTo: (NMBMatcher) -> Void { return toNot } public var notToWithDescription: (NMBMatcher, String) -> Void { return toNotWithDescription } public var toEventually: (NMBMatcher) -> Void { return ({ matcher in self.expectValue.toEventually( ObjCMatcherWrapper(matcher: matcher), timeout: self._timeout, description: nil ) }) } public var toEventuallyWithDescription: (NMBMatcher, String) -> Void { return ({ matcher, description in self.expectValue.toEventually( ObjCMatcherWrapper(matcher: matcher), timeout: self._timeout, description: description ) }) } public var toEventuallyNot: (NMBMatcher) -> Void { return ({ matcher in self.expectValue.toEventuallyNot( ObjCMatcherWrapper(matcher: matcher), timeout: self._timeout, description: nil ) }) } public var toEventuallyNotWithDescription: (NMBMatcher, String) -> Void { return ({ matcher, description in self.expectValue.toEventuallyNot( ObjCMatcherWrapper(matcher: matcher), timeout: self._timeout, description: description ) }) } public var toNotEventually: (NMBMatcher) -> Void { return toEventuallyNot } public var toNotEventuallyWithDescription: (NMBMatcher, String) -> Void { return toEventuallyNotWithDescription } public class func failWithMessage(message: String, file: String, line: UInt) { fail(message, location: SourceLocation(file: file, line: line)) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Utils/Functional.swift ================================================ import Foundation internal func all(array: [T], fn: (T) -> Bool) -> Bool { for item in array { if !fn(item) { return false } } return true } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Utils/Poll.swift ================================================ import Foundation internal enum PollResult : BooleanType { case Success, Failure, Timeout case ErrorThrown(ErrorType) var boolValue : Bool { switch (self) { case .Success: return true default: return false } } } internal class RunPromise { var token: dispatch_once_t = 0 var didFinish = false var didFail = false init() {} func succeed() { dispatch_once(&self.token) { self.didFinish = false } } func fail(block: () -> Void) { dispatch_once(&self.token) { self.didFail = true block() } } } let killQueue = dispatch_queue_create("nimble.waitUntil.queue", DISPATCH_QUEUE_SERIAL) internal func stopRunLoop(runLoop: NSRunLoop, delay: NSTimeInterval) -> RunPromise { let promise = RunPromise() let killTimeOffset = Int64(CDouble(delay) * CDouble(NSEC_PER_SEC)) let killTime = dispatch_time(DISPATCH_TIME_NOW, killTimeOffset) dispatch_after(killTime, killQueue) { promise.fail { CFRunLoopStop(runLoop.getCFRunLoop()) } } return promise } internal func pollBlock(pollInterval pollInterval: NSTimeInterval, timeoutInterval: NSTimeInterval, expression: () throws -> Bool) -> PollResult { let runLoop = NSRunLoop.mainRunLoop() let promise = stopRunLoop(runLoop, delay: min(timeoutInterval, 0.2)) let startDate = NSDate() // trigger run loop to make sure enqueued tasks don't block our assertion polling // the stop run loop task above will abort us if necessary runLoop.runUntilDate(startDate) dispatch_sync(killQueue) { promise.succeed() } if promise.didFail { return .Timeout } var pass = false do { repeat { pass = try expression() if pass { break } let runDate = NSDate().dateByAddingTimeInterval(pollInterval) runLoop.runUntilDate(runDate) } while(NSDate().timeIntervalSinceDate(startDate) < timeoutInterval) } catch let error { return .ErrorThrown(error) } return pass ? .Success : .Failure } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Utils/SourceLocation.swift ================================================ import Foundation public class SourceLocation : NSObject { public let file: String public let line: UInt override init() { file = "Unknown File" line = 0 } init(file: String, line: UInt) { self.file = file self.line = line } override public var description: String { return "\(file):\(line)" } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Utils/Stringers.swift ================================================ import Foundation internal func identityAsString(value: AnyObject?) -> String { if value == nil { return "nil" } return NSString(format: "<%p>", unsafeBitCast(value!, Int.self)).description } internal func arrayAsString(items: [T], joiner: String = ", ") -> String { return items.reduce("") { accum, item in let prefix = (accum.isEmpty ? "" : joiner) return accum + prefix + "\(stringify(item))" } } @objc internal protocol NMBStringer { func NMB_stringify() -> String } internal func stringify(value: S) -> String { var generator = value.generate() var strings = [String]() var value: S.Generator.Element? repeat { value = generator.next() if value != nil { strings.append(stringify(value)) } } while value != nil let str = strings.joinWithSeparator(", ") return "[\(str)]" } extension NSArray : NMBStringer { func NMB_stringify() -> String { let str = self.componentsJoinedByString(", ") return "[\(str)]" } } internal func stringify(value: T) -> String { if let value = value as? Double { return NSString(format: "%.4f", (value)).description } return String(value) } internal func stringify(value: NMBDoubleConvertible) -> String { if let value = value as? Double { return NSString(format: "%.4f", (value)).description } return value.stringRepresentation } internal func stringify(value: T?) -> String { if let unboxed = value { return stringify(unboxed) } return "nil" } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Wrappers/AsyncMatcherWrapper.swift ================================================ import Foundation internal struct AsyncMatcherWrapper: Matcher { let fullMatcher: U let timeoutInterval: NSTimeInterval let pollInterval: NSTimeInterval init(fullMatcher: U, timeoutInterval: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01) { self.fullMatcher = fullMatcher self.timeoutInterval = timeoutInterval self.pollInterval = pollInterval } func matches(actualExpression: Expression, failureMessage: FailureMessage) -> Bool { let uncachedExpression = actualExpression.withoutCaching() let result = pollBlock(pollInterval: pollInterval, timeoutInterval: timeoutInterval) { try self.fullMatcher.matches(uncachedExpression, failureMessage: failureMessage) } switch (result) { case .Success: return true case .Failure: return false case let .ErrorThrown(error): failureMessage.actualValue = "an unexpected error thrown: <\(error)>" return false case .Timeout: failureMessage.postfixMessage += " (Stall on main thread)." return false } } func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) -> Bool { let uncachedExpression = actualExpression.withoutCaching() let result = pollBlock(pollInterval: pollInterval, timeoutInterval: timeoutInterval) { try self.fullMatcher.doesNotMatch(uncachedExpression, failureMessage: failureMessage) } switch (result) { case .Success: return true case .Failure: return false case let .ErrorThrown(error): failureMessage.actualValue = "an unexpected error thrown: <\(error)>" return false case .Timeout: failureMessage.postfixMessage += " (Stall on main thread)." return false } } } private let toEventuallyRequiresClosureError = FailureMessage(stringValue: "expect(...).toEventually(...) requires an explicit closure (eg - expect { ... }.toEventually(...) )\nSwift 1.2 @autoclosure behavior has changed in an incompatible way for Nimble to function") extension Expectation { /// Tests the actual value using a matcher to match by checking continuously /// at each pollInterval until the timeout is reached. public func toEventually(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01, description: String? = nil) { if expression.isClosure { let (pass, msg) = expressionMatches( expression, matcher: AsyncMatcherWrapper( fullMatcher: matcher, timeoutInterval: timeout, pollInterval: pollInterval), to: "to eventually", description: description ) verify(pass, msg) } else { verify(false, toEventuallyRequiresClosureError) } } /// Tests the actual value using a matcher to not match by checking /// continuously at each pollInterval until the timeout is reached. public func toEventuallyNot(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01, description: String? = nil) { if expression.isClosure { let (pass, msg) = expressionDoesNotMatch( expression, matcher: AsyncMatcherWrapper( fullMatcher: matcher, timeoutInterval: timeout, pollInterval: pollInterval), toNot: "to eventually not", description: description ) verify(pass, msg) } else { verify(false, toEventuallyRequiresClosureError) } } /// Tests the actual value using a matcher to not match by checking /// continuously at each pollInterval until the timeout is reached. /// /// Alias of toEventuallyNot() public func toNotEventually(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01, description: String? = nil) { return toEventuallyNot(matcher, timeout: timeout, pollInterval: pollInterval, description: description) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Wrappers/MatcherFunc.swift ================================================ /// A convenience API to build matchers that allow full control over /// to() and toNot() match cases. /// /// The final bool argument in the closure is if the match is for negation. /// /// You may use this when implementing your own custom matchers. /// /// Use the Matcher protocol instead of this type to accept custom matchers as /// input parameters. /// @see allPass for an example that uses accepts other matchers as input. public struct FullMatcherFunc: Matcher { public let matcher: (Expression, FailureMessage, Bool) throws -> Bool public init(_ matcher: (Expression, FailureMessage, Bool) throws -> Bool) { self.matcher = matcher } public func matches(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { return try matcher(actualExpression, failureMessage, false) } public func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { return try matcher(actualExpression, failureMessage, true) } } /// A convenience API to build matchers that don't need special negation /// behavior. The toNot() behavior is the negation of to(). /// /// @see NonNilMatcherFunc if you prefer to have this matcher fail when nil /// values are recieved in an expectation. /// /// You may use this when implementing your own custom matchers. /// /// Use the Matcher protocol instead of this type to accept custom matchers as /// input parameters. /// @see allPass for an example that uses accepts other matchers as input. public struct MatcherFunc: Matcher { public let matcher: (Expression, FailureMessage) throws -> Bool public init(_ matcher: (Expression, FailureMessage) throws -> Bool) { self.matcher = matcher } public func matches(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { return try matcher(actualExpression, failureMessage) } public func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { return try !matcher(actualExpression, failureMessage) } } /// A convenience API to build matchers that don't need special negation /// behavior. The toNot() behavior is the negation of to(). /// /// Unlike MatcherFunc, this will always fail if an expectation contains nil. /// This applies regardless of using to() or toNot(). /// /// You may use this when implementing your own custom matchers. /// /// Use the Matcher protocol instead of this type to accept custom matchers as /// input parameters. /// @see allPass for an example that uses accepts other matchers as input. public struct NonNilMatcherFunc: Matcher { public let matcher: (Expression, FailureMessage) throws -> Bool public init(_ matcher: (Expression, FailureMessage) throws -> Bool) { self.matcher = matcher } public func matches(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { let pass = try matcher(actualExpression, failureMessage) if try attachNilErrorIfNeeded(actualExpression, failureMessage: failureMessage) { return false } return pass } public func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { let pass = try !matcher(actualExpression, failureMessage) if try attachNilErrorIfNeeded(actualExpression, failureMessage: failureMessage) { return false } return pass } internal func attachNilErrorIfNeeded(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { if try actualExpression.evaluate() == nil { failureMessage.postfixActual = " (use beNil() to match nils)" return true } return false } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/Wrappers/ObjCMatcher.swift ================================================ import Foundation public typealias MatcherBlock = (actualExpression: Expression, failureMessage: FailureMessage) -> Bool public typealias FullMatcherBlock = (actualExpression: Expression, failureMessage: FailureMessage, shouldNotMatch: Bool) -> Bool public class NMBObjCMatcher : NSObject, NMBMatcher { let _match: MatcherBlock let _doesNotMatch: MatcherBlock let canMatchNil: Bool public init(canMatchNil: Bool, matcher: MatcherBlock, notMatcher: MatcherBlock) { self.canMatchNil = canMatchNil self._match = matcher self._doesNotMatch = notMatcher } public convenience init(matcher: MatcherBlock) { self.init(canMatchNil: true, matcher: matcher) } public convenience init(canMatchNil: Bool, matcher: MatcherBlock) { self.init(canMatchNil: canMatchNil, matcher: matcher, notMatcher: ({ actualExpression, failureMessage in return !matcher(actualExpression: actualExpression, failureMessage: failureMessage) })) } public convenience init(matcher: FullMatcherBlock) { self.init(canMatchNil: true, matcher: matcher) } public convenience init(canMatchNil: Bool, matcher: FullMatcherBlock) { self.init(canMatchNil: canMatchNil, matcher: ({ actualExpression, failureMessage in return matcher(actualExpression: actualExpression, failureMessage: failureMessage, shouldNotMatch: false) }), notMatcher: ({ actualExpression, failureMessage in return matcher(actualExpression: actualExpression, failureMessage: failureMessage, shouldNotMatch: true) })) } private func canMatch(actualExpression: Expression, failureMessage: FailureMessage) -> Bool { do { if !canMatchNil { if try actualExpression.evaluate() == nil { failureMessage.postfixActual = " (use beNil() to match nils)" return false } } } catch let error { failureMessage.actualValue = "an unexpected error thrown: \(error)" return false } return true } public func matches(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { let expr = Expression(expression: actualBlock, location: location) let result = _match( actualExpression: expr, failureMessage: failureMessage) if self.canMatch(Expression(expression: actualBlock, location: location), failureMessage: failureMessage) { return result } else { return false } } public func doesNotMatch(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { let expr = Expression(expression: actualBlock, location: location) let result = _doesNotMatch( actualExpression: expr, failureMessage: failureMessage) if self.canMatch(Expression(expression: actualBlock, location: location), failureMessage: failureMessage) { return result } else { return false } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/objc/DSL.h ================================================ #import @class NMBExpectation; @class NMBObjCBeCloseToMatcher; @class NMBObjCRaiseExceptionMatcher; @protocol NMBMatcher; #define NIMBLE_EXPORT FOUNDATION_EXPORT #ifdef NIMBLE_DISABLE_SHORT_SYNTAX #define NIMBLE_SHORT(PROTO, ORIGINAL) #else #define NIMBLE_SHORT(PROTO, ORIGINAL) FOUNDATION_STATIC_INLINE PROTO { return (ORIGINAL); } #endif NIMBLE_EXPORT NMBExpectation *NMB_expect(id(^actualBlock)(), NSString *file, NSUInteger line); NIMBLE_EXPORT NMBExpectation *NMB_expectAction(void(^actualBlock)(), NSString *file, NSUInteger line); NIMBLE_EXPORT id NMB_equal(id expectedValue); NIMBLE_SHORT(id equal(id expectedValue), NMB_equal(expectedValue)); NIMBLE_EXPORT id NMB_haveCount(id expectedValue); NIMBLE_SHORT(id haveCount(id expectedValue), NMB_haveCount(expectedValue)); NIMBLE_EXPORT NMBObjCBeCloseToMatcher *NMB_beCloseTo(NSNumber *expectedValue); NIMBLE_SHORT(NMBObjCBeCloseToMatcher *beCloseTo(id expectedValue), NMB_beCloseTo(expectedValue)); NIMBLE_EXPORT id NMB_beAnInstanceOf(Class expectedClass); NIMBLE_SHORT(id beAnInstanceOf(Class expectedClass), NMB_beAnInstanceOf(expectedClass)); NIMBLE_EXPORT id NMB_beAKindOf(Class expectedClass); NIMBLE_SHORT(id beAKindOf(Class expectedClass), NMB_beAKindOf(expectedClass)); NIMBLE_EXPORT id NMB_beginWith(id itemElementOrSubstring); NIMBLE_SHORT(id beginWith(id itemElementOrSubstring), NMB_beginWith(itemElementOrSubstring)); NIMBLE_EXPORT id NMB_beGreaterThan(NSNumber *expectedValue); NIMBLE_SHORT(id beGreaterThan(NSNumber *expectedValue), NMB_beGreaterThan(expectedValue)); NIMBLE_EXPORT id NMB_beGreaterThanOrEqualTo(NSNumber *expectedValue); NIMBLE_SHORT(id beGreaterThanOrEqualTo(NSNumber *expectedValue), NMB_beGreaterThanOrEqualTo(expectedValue)); NIMBLE_EXPORT id NMB_beIdenticalTo(id expectedInstance); NIMBLE_SHORT(id beIdenticalTo(id expectedInstance), NMB_beIdenticalTo(expectedInstance)); NIMBLE_EXPORT id NMB_beLessThan(NSNumber *expectedValue); NIMBLE_SHORT(id beLessThan(NSNumber *expectedValue), NMB_beLessThan(expectedValue)); NIMBLE_EXPORT id NMB_beLessThanOrEqualTo(NSNumber *expectedValue); NIMBLE_SHORT(id beLessThanOrEqualTo(NSNumber *expectedValue), NMB_beLessThanOrEqualTo(expectedValue)); NIMBLE_EXPORT id NMB_beTruthy(void); NIMBLE_SHORT(id beTruthy(void), NMB_beTruthy()); NIMBLE_EXPORT id NMB_beFalsy(void); NIMBLE_SHORT(id beFalsy(void), NMB_beFalsy()); NIMBLE_EXPORT id NMB_beTrue(void); NIMBLE_SHORT(id beTrue(void), NMB_beTrue()); NIMBLE_EXPORT id NMB_beFalse(void); NIMBLE_SHORT(id beFalse(void), NMB_beFalse()); NIMBLE_EXPORT id NMB_beNil(void); NIMBLE_SHORT(id beNil(void), NMB_beNil()); NIMBLE_EXPORT id NMB_beEmpty(void); NIMBLE_SHORT(id beEmpty(void), NMB_beEmpty()); NIMBLE_EXPORT id NMB_containWithNilTermination(id itemOrSubstring, ...) NS_REQUIRES_NIL_TERMINATION; #define NMB_contain(...) NMB_containWithNilTermination(__VA_ARGS__, nil) #ifndef NIMBLE_DISABLE_SHORT_SYNTAX #define contain(...) NMB_contain(__VA_ARGS__) #endif NIMBLE_EXPORT id NMB_endWith(id itemElementOrSubstring); NIMBLE_SHORT(id endWith(id itemElementOrSubstring), NMB_endWith(itemElementOrSubstring)); NIMBLE_EXPORT NMBObjCRaiseExceptionMatcher *NMB_raiseException(void); NIMBLE_SHORT(NMBObjCRaiseExceptionMatcher *raiseException(void), NMB_raiseException()); NIMBLE_EXPORT id NMB_match(id expectedValue); NIMBLE_SHORT(id match(id expectedValue), NMB_match(expectedValue)); NIMBLE_EXPORT id NMB_allPass(id matcher); NIMBLE_SHORT(id allPass(id matcher), NMB_allPass(matcher)); // In order to preserve breakpoint behavior despite using macros to fill in __FILE__ and __LINE__, // define a builder that populates __FILE__ and __LINE__, and returns a block that takes timeout // and action arguments. See https://github.com/Quick/Quick/pull/185 for details. typedef void (^NMBWaitUntilTimeoutBlock)(NSTimeInterval timeout, void (^action)(void (^)(void))); typedef void (^NMBWaitUntilBlock)(void (^action)(void (^)(void))); NIMBLE_EXPORT void NMB_failWithMessage(NSString *msg, NSString *file, NSUInteger line); NIMBLE_EXPORT NMBWaitUntilTimeoutBlock NMB_waitUntilTimeoutBuilder(NSString *file, NSUInteger line); NIMBLE_EXPORT NMBWaitUntilBlock NMB_waitUntilBuilder(NSString *file, NSUInteger line); NIMBLE_EXPORT void NMB_failWithMessage(NSString *msg, NSString *file, NSUInteger line); #define NMB_waitUntilTimeout NMB_waitUntilTimeoutBuilder(@(__FILE__), __LINE__) #define NMB_waitUntil NMB_waitUntilBuilder(@(__FILE__), __LINE__) #ifndef NIMBLE_DISABLE_SHORT_SYNTAX #define expect(...) NMB_expect(^id{ return (__VA_ARGS__); }, @(__FILE__), __LINE__) #define expectAction(BLOCK) NMB_expectAction((BLOCK), @(__FILE__), __LINE__) #define failWithMessage(msg) NMB_failWithMessage(msg, @(__FILE__), __LINE__) #define fail() failWithMessage(@"fail() always fails") #define waitUntilTimeout NMB_waitUntilTimeout #define waitUntil NMB_waitUntil #endif ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/objc/DSL.m ================================================ #import #import SWIFT_CLASS("_TtC6Nimble7NMBWait") @interface NMBWait : NSObject + (void)untilTimeout:(NSTimeInterval)timeout file:(NSString *)file line:(NSUInteger)line action:(void(^)())action; + (void)untilFile:(NSString *)file line:(NSUInteger)line action:(void(^)())action; @end NIMBLE_EXPORT NMBExpectation *NMB_expect(id(^actualBlock)(), NSString *file, NSUInteger line) { return [[NMBExpectation alloc] initWithActualBlock:actualBlock negative:NO file:file line:line]; } NIMBLE_EXPORT NMBExpectation *NMB_expectAction(void(^actualBlock)(), NSString *file, NSUInteger line) { return NMB_expect(^id{ actualBlock(); return nil; }, file, line); } NIMBLE_EXPORT void NMB_failWithMessage(NSString *msg, NSString *file, NSUInteger line) { return [NMBExpectation failWithMessage:msg file:file line:line]; } NIMBLE_EXPORT id NMB_beAnInstanceOf(Class expectedClass) { return [NMBObjCMatcher beAnInstanceOfMatcher:expectedClass]; } NIMBLE_EXPORT id NMB_beAKindOf(Class expectedClass) { return [NMBObjCMatcher beAKindOfMatcher:expectedClass]; } NIMBLE_EXPORT NMBObjCBeCloseToMatcher *NMB_beCloseTo(NSNumber *expectedValue) { return [NMBObjCMatcher beCloseToMatcher:expectedValue within:0.001]; } NIMBLE_EXPORT id NMB_beginWith(id itemElementOrSubstring) { return [NMBObjCMatcher beginWithMatcher:itemElementOrSubstring]; } NIMBLE_EXPORT id NMB_beGreaterThan(NSNumber *expectedValue) { return [NMBObjCMatcher beGreaterThanMatcher:expectedValue]; } NIMBLE_EXPORT id NMB_beGreaterThanOrEqualTo(NSNumber *expectedValue) { return [NMBObjCMatcher beGreaterThanOrEqualToMatcher:expectedValue]; } NIMBLE_EXPORT id NMB_beIdenticalTo(id expectedInstance) { return [NMBObjCMatcher beIdenticalToMatcher:expectedInstance]; } NIMBLE_EXPORT id NMB_beLessThan(NSNumber *expectedValue) { return [NMBObjCMatcher beLessThanMatcher:expectedValue]; } NIMBLE_EXPORT id NMB_beLessThanOrEqualTo(NSNumber *expectedValue) { return [NMBObjCMatcher beLessThanOrEqualToMatcher:expectedValue]; } NIMBLE_EXPORT id NMB_beTruthy() { return [NMBObjCMatcher beTruthyMatcher]; } NIMBLE_EXPORT id NMB_beFalsy() { return [NMBObjCMatcher beFalsyMatcher]; } NIMBLE_EXPORT id NMB_beTrue() { return [NMBObjCMatcher beTrueMatcher]; } NIMBLE_EXPORT id NMB_beFalse() { return [NMBObjCMatcher beFalseMatcher]; } NIMBLE_EXPORT id NMB_beNil() { return [NMBObjCMatcher beNilMatcher]; } NIMBLE_EXPORT id NMB_beEmpty() { return [NMBObjCMatcher beEmptyMatcher]; } NIMBLE_EXPORT id NMB_containWithNilTermination(id itemOrSubstring, ...) { NSMutableArray *itemOrSubstringArray = [NSMutableArray array]; if (itemOrSubstring) { [itemOrSubstringArray addObject:itemOrSubstring]; va_list args; va_start(args, itemOrSubstring); id next; while ((next = va_arg(args, id))) { [itemOrSubstringArray addObject:next]; } va_end(args); } return [NMBObjCMatcher containMatcher:itemOrSubstringArray]; } NIMBLE_EXPORT id NMB_endWith(id itemElementOrSubstring) { return [NMBObjCMatcher endWithMatcher:itemElementOrSubstring]; } NIMBLE_EXPORT id NMB_equal(id expectedValue) { return [NMBObjCMatcher equalMatcher:expectedValue]; } NIMBLE_EXPORT id NMB_haveCount(id expectedValue) { return [NMBObjCMatcher haveCountMatcher:expectedValue]; } NIMBLE_EXPORT id NMB_match(id expectedValue) { return [NMBObjCMatcher matchMatcher:expectedValue]; } NIMBLE_EXPORT id NMB_allPass(id expectedValue) { return [NMBObjCMatcher allPassMatcher:expectedValue]; } NIMBLE_EXPORT NMBObjCRaiseExceptionMatcher *NMB_raiseException() { return [NMBObjCMatcher raiseExceptionMatcher]; } NIMBLE_EXPORT NMBWaitUntilTimeoutBlock NMB_waitUntilTimeoutBuilder(NSString *file, NSUInteger line) { return ^(NSTimeInterval timeout, void (^action)(void (^)(void))) { [NMBWait untilTimeout:timeout file:file line:line action:action]; }; } NIMBLE_EXPORT NMBWaitUntilBlock NMB_waitUntilBuilder(NSString *file, NSUInteger line) { return ^(void (^action)(void (^)(void))) { [NMBWait untilFile:file line:line action:action]; }; } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/objc/NMBExceptionCapture.h ================================================ #import @interface NMBExceptionCapture : NSObject - (id)initWithHandler:(void(^)(NSException *))handler finally:(void(^)())finally; - (void)tryBlock:(void(^)())unsafeBlock; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble/objc/NMBExceptionCapture.m ================================================ #import "NMBExceptionCapture.h" @interface NMBExceptionCapture () @property (nonatomic, copy) void(^handler)(NSException *exception); @property (nonatomic, copy) void(^finally)(); @end @implementation NMBExceptionCapture - (id)initWithHandler:(void(^)(NSException *))handler finally:(void(^)())finally { self = [super init]; if (self) { self.handler = handler; self.finally = finally; } return self; } - (void)tryBlock:(void(^)())unsafeBlock { @try { unsafeBlock(); } @catch (NSException *exception) { if (self.handler) { self.handler(exception); } } @finally { if (self.finally) { self.finally(); } } } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble.podspec ================================================ Pod::Spec.new do |s| s.name = "Nimble" s.version = "3.0.0" s.summary = "A Matcher Framework for Swift and Objective-C" s.description = <<-DESC Use Nimble to express the expected outcomes of Swift or Objective-C expressions. Inspired by Cedar. DESC s.homepage = "https://github.com/Quick/Nimble" s.license = { :type => "Apache 2.0", :file => "LICENSE.md" } s.author = "Quick Contributors" s.ios.deployment_target = "7.0" s.osx.deployment_target = "10.9" s.tvos.deployment_target = "9.0" s.source = { :git => "https://github.com/Quick/Nimble.git", :tag => "v#{s.version}" } s.source_files = "Nimble", "Nimble/**/*.{swift,h,m}" s.weak_framework = "XCTest" s.requires_arc = true s.pod_target_xcconfig = { 'ENABLE_BITCODE' => 'NO', 'OTHER_LDFLAGS' => '-weak-lswiftXCTest', 'FRAMEWORK_SEARCH_PATHS' => '$(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks"' } end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 1F0648CC19639F5A001F9C46 /* ObjectWithLazyProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0648CB19639F5A001F9C46 /* ObjectWithLazyProperty.swift */; }; 1F0648CD19639F5A001F9C46 /* ObjectWithLazyProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0648CB19639F5A001F9C46 /* ObjectWithLazyProperty.swift */; }; 1F0648D41963AAB2001F9C46 /* SynchronousTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0648D31963AAB2001F9C46 /* SynchronousTests.swift */; }; 1F0648D51963AAB2001F9C46 /* SynchronousTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0648D31963AAB2001F9C46 /* SynchronousTests.swift */; }; 1F0FEA9A1AF32DA4001E554E /* ObjCExpectation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0FEA991AF32DA4001E554E /* ObjCExpectation.swift */; }; 1F0FEA9B1AF32DA4001E554E /* ObjCExpectation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0FEA991AF32DA4001E554E /* ObjCExpectation.swift */; }; 1F14FB64194180C5009F2A08 /* utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F14FB63194180C5009F2A08 /* utils.swift */; }; 1F1A742F1940169200FFFC47 /* Nimble.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F1A742E1940169200FFFC47 /* Nimble.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F1A74351940169200FFFC47 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F1A74291940169200FFFC47 /* Nimble.framework */; }; 1F1B5AD41963E13900CA8BF9 /* BeAKindOfTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F1B5AD31963E13900CA8BF9 /* BeAKindOfTest.swift */; }; 1F1B5AD51963E13900CA8BF9 /* BeAKindOfTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F1B5AD31963E13900CA8BF9 /* BeAKindOfTest.swift */; }; 1F299EAB19627B2D002641AF /* BeEmptyTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F299EAA19627B2D002641AF /* BeEmptyTest.swift */; }; 1F299EAC19627B2D002641AF /* BeEmptyTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F299EAA19627B2D002641AF /* BeEmptyTest.swift */; }; 1F43728A1A1B343800EB80F8 /* Functional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD251968AB07008ED995 /* Functional.swift */; }; 1F43728B1A1B343900EB80F8 /* Functional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD251968AB07008ED995 /* Functional.swift */; }; 1F43728C1A1B343C00EB80F8 /* SourceLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD271968AB07008ED995 /* SourceLocation.swift */; }; 1F43728D1A1B343D00EB80F8 /* SourceLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD271968AB07008ED995 /* SourceLocation.swift */; }; 1F43728E1A1B343F00EB80F8 /* Stringers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD281968AB07008ED995 /* Stringers.swift */; }; 1F43728F1A1B344000EB80F8 /* Stringers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD281968AB07008ED995 /* Stringers.swift */; }; 1F4A56661A3B305F009E1637 /* ObjCAsyncTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56651A3B305F009E1637 /* ObjCAsyncTest.m */; }; 1F4A56671A3B305F009E1637 /* ObjCAsyncTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56651A3B305F009E1637 /* ObjCAsyncTest.m */; }; 1F4A566A1A3B3108009E1637 /* ObjCBeAnInstanceOfTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56691A3B3108009E1637 /* ObjCBeAnInstanceOfTest.m */; }; 1F4A566B1A3B3108009E1637 /* ObjCBeAnInstanceOfTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56691A3B3108009E1637 /* ObjCBeAnInstanceOfTest.m */; }; 1F4A566D1A3B3159009E1637 /* ObjCBeKindOfTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A566C1A3B3159009E1637 /* ObjCBeKindOfTest.m */; }; 1F4A566E1A3B3159009E1637 /* ObjCBeKindOfTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A566C1A3B3159009E1637 /* ObjCBeKindOfTest.m */; }; 1F4A56701A3B319F009E1637 /* ObjCBeCloseToTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A566F1A3B319F009E1637 /* ObjCBeCloseToTest.m */; }; 1F4A56711A3B319F009E1637 /* ObjCBeCloseToTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A566F1A3B319F009E1637 /* ObjCBeCloseToTest.m */; }; 1F4A56731A3B3210009E1637 /* ObjCBeginWithTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56721A3B3210009E1637 /* ObjCBeginWithTest.m */; }; 1F4A56741A3B3210009E1637 /* ObjCBeginWithTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56721A3B3210009E1637 /* ObjCBeginWithTest.m */; }; 1F4A56761A3B3253009E1637 /* ObjCBeGreaterThanTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56751A3B3253009E1637 /* ObjCBeGreaterThanTest.m */; }; 1F4A56771A3B3253009E1637 /* ObjCBeGreaterThanTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56751A3B3253009E1637 /* ObjCBeGreaterThanTest.m */; }; 1F4A56791A3B32E3009E1637 /* ObjCBeGreaterThanOrEqualToTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56781A3B32E3009E1637 /* ObjCBeGreaterThanOrEqualToTest.m */; }; 1F4A567A1A3B32E3009E1637 /* ObjCBeGreaterThanOrEqualToTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56781A3B32E3009E1637 /* ObjCBeGreaterThanOrEqualToTest.m */; }; 1F4A567C1A3B3311009E1637 /* ObjCBeIdenticalToTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A567B1A3B3311009E1637 /* ObjCBeIdenticalToTest.m */; }; 1F4A567D1A3B3311009E1637 /* ObjCBeIdenticalToTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A567B1A3B3311009E1637 /* ObjCBeIdenticalToTest.m */; }; 1F4A567F1A3B333F009E1637 /* ObjCBeLessThanTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A567E1A3B333F009E1637 /* ObjCBeLessThanTest.m */; }; 1F4A56801A3B333F009E1637 /* ObjCBeLessThanTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A567E1A3B333F009E1637 /* ObjCBeLessThanTest.m */; }; 1F4A56821A3B336F009E1637 /* ObjCBeLessThanOrEqualToTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56811A3B336F009E1637 /* ObjCBeLessThanOrEqualToTest.m */; }; 1F4A56831A3B336F009E1637 /* ObjCBeLessThanOrEqualToTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56811A3B336F009E1637 /* ObjCBeLessThanOrEqualToTest.m */; }; 1F4A56851A3B33A0009E1637 /* ObjCBeTruthyTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56841A3B33A0009E1637 /* ObjCBeTruthyTest.m */; }; 1F4A56861A3B33A0009E1637 /* ObjCBeTruthyTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56841A3B33A0009E1637 /* ObjCBeTruthyTest.m */; }; 1F4A56881A3B33CB009E1637 /* ObjCBeFalsyTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56871A3B33CB009E1637 /* ObjCBeFalsyTest.m */; }; 1F4A56891A3B33CB009E1637 /* ObjCBeFalsyTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56871A3B33CB009E1637 /* ObjCBeFalsyTest.m */; }; 1F4A568B1A3B3407009E1637 /* ObjCBeTrueTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A568A1A3B3407009E1637 /* ObjCBeTrueTest.m */; }; 1F4A568C1A3B3407009E1637 /* ObjCBeTrueTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A568A1A3B3407009E1637 /* ObjCBeTrueTest.m */; }; 1F4A568E1A3B342B009E1637 /* ObjCBeFalseTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A568D1A3B342B009E1637 /* ObjCBeFalseTest.m */; }; 1F4A568F1A3B342B009E1637 /* ObjCBeFalseTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A568D1A3B342B009E1637 /* ObjCBeFalseTest.m */; }; 1F4A56911A3B344A009E1637 /* ObjCBeNilTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56901A3B344A009E1637 /* ObjCBeNilTest.m */; }; 1F4A56921A3B344A009E1637 /* ObjCBeNilTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56901A3B344A009E1637 /* ObjCBeNilTest.m */; }; 1F4A56941A3B346F009E1637 /* ObjCContainTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56931A3B346F009E1637 /* ObjCContainTest.m */; }; 1F4A56951A3B346F009E1637 /* ObjCContainTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56931A3B346F009E1637 /* ObjCContainTest.m */; }; 1F4A56971A3B34AA009E1637 /* ObjCEndWithTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56961A3B34AA009E1637 /* ObjCEndWithTest.m */; }; 1F4A56981A3B34AA009E1637 /* ObjCEndWithTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56961A3B34AA009E1637 /* ObjCEndWithTest.m */; }; 1F4A569A1A3B3539009E1637 /* ObjCEqualTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56991A3B3539009E1637 /* ObjCEqualTest.m */; }; 1F4A569B1A3B3539009E1637 /* ObjCEqualTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A56991A3B3539009E1637 /* ObjCEqualTest.m */; }; 1F4A569D1A3B3565009E1637 /* ObjCMatchTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A569C1A3B3565009E1637 /* ObjCMatchTest.m */; }; 1F4A569E1A3B3565009E1637 /* ObjCMatchTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A569C1A3B3565009E1637 /* ObjCMatchTest.m */; }; 1F4A56A01A3B359E009E1637 /* ObjCRaiseExceptionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A569F1A3B359E009E1637 /* ObjCRaiseExceptionTest.m */; }; 1F4A56A11A3B359E009E1637 /* ObjCRaiseExceptionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F4A569F1A3B359E009E1637 /* ObjCRaiseExceptionTest.m */; }; 1F5DF15F1BDCA0CE00C3A531 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F5DF1551BDCA0CE00C3A531 /* Nimble.framework */; }; 1F5DF16C1BDCA0F500C3A531 /* AssertionRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD051968AB07008ED995 /* AssertionRecorder.swift */; }; 1F5DF16D1BDCA0F500C3A531 /* AdapterProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD061968AB07008ED995 /* AdapterProtocols.swift */; }; 1F5DF16E1BDCA0F500C3A531 /* NimbleXCTestHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD071968AB07008ED995 /* NimbleXCTestHandler.swift */; }; 1F5DF16F1BDCA0F500C3A531 /* AssertionDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FDBD8661AF8A4FF0089F27B /* AssertionDispatcher.swift */; }; 1F5DF1701BDCA0F500C3A531 /* DSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD081968AB07008ED995 /* DSL.swift */; }; 1F5DF1711BDCA0F500C3A531 /* DSL+Wait.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9E8C811A414BB9002633C2 /* DSL+Wait.swift */; }; 1F5DF1721BDCA0F500C3A531 /* Expectation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD091968AB07008ED995 /* Expectation.swift */; }; 1F5DF1731BDCA0F500C3A531 /* ObjCExpectation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0FEA991AF32DA4001E554E /* ObjCExpectation.swift */; }; 1F5DF1741BDCA0F500C3A531 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0A1968AB07008ED995 /* Expression.swift */; }; 1F5DF1751BDCA0F500C3A531 /* FailureMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0B1968AB07008ED995 /* FailureMessage.swift */; }; 1F5DF1761BDCA0F500C3A531 /* AllPass.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB1BC781A92235600F743C3 /* AllPass.swift */; }; 1F5DF1771BDCA0F500C3A531 /* BeAKindOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0E1968AB07008ED995 /* BeAKindOf.swift */; }; 1F5DF1781BDCA0F500C3A531 /* BeAnInstanceOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0D1968AB07008ED995 /* BeAnInstanceOf.swift */; }; 1F5DF1791BDCA0F500C3A531 /* BeCloseTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0F1968AB07008ED995 /* BeCloseTo.swift */; }; 1F5DF17A1BDCA0F500C3A531 /* BeEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD101968AB07008ED995 /* BeEmpty.swift */; }; 1F5DF17B1BDCA0F500C3A531 /* BeginWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD111968AB07008ED995 /* BeginWith.swift */; }; 1F5DF17C1BDCA0F500C3A531 /* BeGreaterThan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD121968AB07008ED995 /* BeGreaterThan.swift */; }; 1F5DF17D1BDCA0F500C3A531 /* BeGreaterThanOrEqualTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD131968AB07008ED995 /* BeGreaterThanOrEqualTo.swift */; }; 1F5DF17E1BDCA0F500C3A531 /* BeIdenticalTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD141968AB07008ED995 /* BeIdenticalTo.swift */; }; 1F5DF17F1BDCA0F500C3A531 /* BeLessThan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD151968AB07008ED995 /* BeLessThan.swift */; }; 1F5DF1801BDCA0F500C3A531 /* BeLessThanOrEqual.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD161968AB07008ED995 /* BeLessThanOrEqual.swift */; }; 1F5DF1811BDCA0F500C3A531 /* BeLogical.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD171968AB07008ED995 /* BeLogical.swift */; }; 1F5DF1821BDCA0F500C3A531 /* BeNil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD181968AB07008ED995 /* BeNil.swift */; }; 1F5DF1831BDCA0F500C3A531 /* Contain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1A1968AB07008ED995 /* Contain.swift */; }; 1F5DF1841BDCA0F500C3A531 /* EndWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1B1968AB07008ED995 /* EndWith.swift */; }; 1F5DF1851BDCA0F500C3A531 /* Equal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1C1968AB07008ED995 /* Equal.swift */; }; 1F5DF1861BDCA0F500C3A531 /* HaveCount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472FD1341B9E085700C7B8DA /* HaveCount.swift */; }; 1F5DF1871BDCA0F500C3A531 /* Match.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB4D5EC19FE43C200E9D9FE /* Match.swift */; }; 1F5DF1881BDCA0F500C3A531 /* MatcherProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1D1968AB07008ED995 /* MatcherProtocols.swift */; }; 1F5DF1891BDCA0F500C3A531 /* RaisesException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1E1968AB07008ED995 /* RaisesException.swift */; }; 1F5DF18A1BDCA0F500C3A531 /* ThrowError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29EA59651B551EE6002D767E /* ThrowError.swift */; }; 1F5DF18B1BDCA0F500C3A531 /* Functional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD251968AB07008ED995 /* Functional.swift */; }; 1F5DF18C1BDCA0F500C3A531 /* Poll.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD261968AB07008ED995 /* Poll.swift */; }; 1F5DF18D1BDCA0F500C3A531 /* SourceLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD271968AB07008ED995 /* SourceLocation.swift */; }; 1F5DF18E1BDCA0F500C3A531 /* Stringers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD281968AB07008ED995 /* Stringers.swift */; }; 1F5DF18F1BDCA0F500C3A531 /* AsyncMatcherWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2A1968AB07008ED995 /* AsyncMatcherWrapper.swift */; }; 1F5DF1901BDCA0F500C3A531 /* MatcherFunc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2C1968AB07008ED995 /* MatcherFunc.swift */; }; 1F5DF1911BDCA0F500C3A531 /* ObjCMatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2D1968AB07008ED995 /* ObjCMatcher.swift */; }; 1F5DF1921BDCA10200C3A531 /* AsynchronousTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EE5195C121200ED456B /* AsynchronousTest.swift */; }; 1F5DF1931BDCA10200C3A531 /* SynchronousTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0648D31963AAB2001F9C46 /* SynchronousTests.swift */; }; 1F5DF1941BDCA10200C3A531 /* UserDescriptionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 965B0D0B1B62C06D0005AE66 /* UserDescriptionTest.swift */; }; 1F5DF1951BDCA10200C3A531 /* utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F14FB63194180C5009F2A08 /* utils.swift */; }; 1F5DF1961BDCA10200C3A531 /* ObjectWithLazyProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F0648CB19639F5A001F9C46 /* ObjectWithLazyProperty.swift */; }; 1F5DF1971BDCA10200C3A531 /* AllPassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD72EC631A93874A002F7651 /* AllPassTest.swift */; }; 1F5DF1981BDCA10200C3A531 /* BeAKindOfTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F1B5AD31963E13900CA8BF9 /* BeAKindOfTest.swift */; }; 1F5DF1991BDCA10200C3A531 /* BeAnInstanceOfTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EE8195C124400ED456B /* BeAnInstanceOfTest.swift */; }; 1F5DF19A1BDCA10200C3A531 /* BeCloseToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EF5195C147800ED456B /* BeCloseToTest.swift */; }; 1F5DF19B1BDCA10200C3A531 /* BeEmptyTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F299EAA19627B2D002641AF /* BeEmptyTest.swift */; }; 1F5DF19C1BDCA10200C3A531 /* BeginWithTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EFB195C186800ED456B /* BeginWithTest.swift */; }; 1F5DF19D1BDCA10200C3A531 /* BeGreaterThanOrEqualToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F10195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift */; }; 1F5DF19E1BDCA10200C3A531 /* BeGreaterThanTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F07195C18CF00ED456B /* BeGreaterThanTest.swift */; }; 1F5DF19F1BDCA10200C3A531 /* BeIdenticalToObjectTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD9A9A8D19CF413800706F49 /* BeIdenticalToObjectTest.swift */; }; 1F5DF1A01BDCA10200C3A531 /* BeIdenticalToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FB90097195EC4B8001D7FAE /* BeIdenticalToTest.swift */; }; 1F5DF1A11BDCA10200C3A531 /* BeLessThanOrEqualToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F0D195C18F500ED456B /* BeLessThanOrEqualToTest.swift */; }; 1F5DF1A21BDCA10200C3A531 /* BeLessThanTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F0A195C18E100ED456B /* BeLessThanTest.swift */; }; 1F5DF1A31BDCA10200C3A531 /* BeLogicalTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EEE195C136500ED456B /* BeLogicalTest.swift */; }; 1F5DF1A41BDCA10200C3A531 /* BeNilTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EF8195C175000ED456B /* BeNilTest.swift */; }; 1F5DF1A51BDCA10200C3A531 /* ContainTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F01195C189500ED456B /* ContainTest.swift */; }; 1F5DF1A61BDCA10200C3A531 /* EndWithTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EFE195C187600ED456B /* EndWithTest.swift */; }; 1F5DF1A71BDCA10200C3A531 /* EqualTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F04195C18B700ED456B /* EqualTest.swift */; }; 1F5DF1A81BDCA10200C3A531 /* HaveCountTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472FD1361B9E094B00C7B8DA /* HaveCountTest.swift */; }; 1F5DF1A91BDCA10200C3A531 /* MatchTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB4D5EF19FE442800E9D9FE /* MatchTest.swift */; }; 1F5DF1AA1BDCA10200C3A531 /* RaisesExceptionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EEB195C12C800ED456B /* RaisesExceptionTest.swift */; }; 1F5DF1AB1BDCA10200C3A531 /* ThrowErrorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29EA59621B551ED2002D767E /* ThrowErrorTest.swift */; }; 1F5DF1AC1BDCA16E00C3A531 /* DSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD211968AB07008ED995 /* DSL.m */; }; 1F5DF1AD1BDCA16E00C3A531 /* NMBExceptionCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD231968AB07008ED995 /* NMBExceptionCapture.m */; }; 1F5DF1AE1BDCA17600C3A531 /* Nimble.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F1A742E1940169200FFFC47 /* Nimble.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F5DF1AF1BDCA17600C3A531 /* DSL.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FD8CD201968AB07008ED995 /* DSL.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F5DF1B01BDCA17600C3A531 /* NMBExceptionCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FD8CD221968AB07008ED995 /* NMBExceptionCapture.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F8A37B01B7C5042001C8357 /* ObjCSyncTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F8A37AF1B7C5042001C8357 /* ObjCSyncTest.m */; }; 1F8A37B11B7C5042001C8357 /* ObjCSyncTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F8A37AF1B7C5042001C8357 /* ObjCSyncTest.m */; }; 1F925EB8195C0D6300ED456B /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F925EAD195C0D6300ED456B /* Nimble.framework */; }; 1F925EC7195C0DD100ED456B /* Nimble.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F1A742E1940169200FFFC47 /* Nimble.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F925EE2195C0DFD00ED456B /* utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F14FB63194180C5009F2A08 /* utils.swift */; }; 1F925EE6195C121200ED456B /* AsynchronousTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EE5195C121200ED456B /* AsynchronousTest.swift */; }; 1F925EE7195C121200ED456B /* AsynchronousTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EE5195C121200ED456B /* AsynchronousTest.swift */; }; 1F925EE9195C124400ED456B /* BeAnInstanceOfTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EE8195C124400ED456B /* BeAnInstanceOfTest.swift */; }; 1F925EEA195C124400ED456B /* BeAnInstanceOfTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EE8195C124400ED456B /* BeAnInstanceOfTest.swift */; }; 1F925EEC195C12C800ED456B /* RaisesExceptionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EEB195C12C800ED456B /* RaisesExceptionTest.swift */; }; 1F925EED195C12C800ED456B /* RaisesExceptionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EEB195C12C800ED456B /* RaisesExceptionTest.swift */; }; 1F925EEF195C136500ED456B /* BeLogicalTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EEE195C136500ED456B /* BeLogicalTest.swift */; }; 1F925EF0195C136500ED456B /* BeLogicalTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EEE195C136500ED456B /* BeLogicalTest.swift */; }; 1F925EF6195C147800ED456B /* BeCloseToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EF5195C147800ED456B /* BeCloseToTest.swift */; }; 1F925EF7195C147800ED456B /* BeCloseToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EF5195C147800ED456B /* BeCloseToTest.swift */; }; 1F925EF9195C175000ED456B /* BeNilTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EF8195C175000ED456B /* BeNilTest.swift */; }; 1F925EFA195C175000ED456B /* BeNilTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EF8195C175000ED456B /* BeNilTest.swift */; }; 1F925EFC195C186800ED456B /* BeginWithTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EFB195C186800ED456B /* BeginWithTest.swift */; }; 1F925EFD195C186800ED456B /* BeginWithTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EFB195C186800ED456B /* BeginWithTest.swift */; }; 1F925EFF195C187600ED456B /* EndWithTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EFE195C187600ED456B /* EndWithTest.swift */; }; 1F925F00195C187600ED456B /* EndWithTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925EFE195C187600ED456B /* EndWithTest.swift */; }; 1F925F02195C189500ED456B /* ContainTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F01195C189500ED456B /* ContainTest.swift */; }; 1F925F03195C189500ED456B /* ContainTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F01195C189500ED456B /* ContainTest.swift */; }; 1F925F05195C18B700ED456B /* EqualTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F04195C18B700ED456B /* EqualTest.swift */; }; 1F925F06195C18B700ED456B /* EqualTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F04195C18B700ED456B /* EqualTest.swift */; }; 1F925F08195C18CF00ED456B /* BeGreaterThanTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F07195C18CF00ED456B /* BeGreaterThanTest.swift */; }; 1F925F09195C18CF00ED456B /* BeGreaterThanTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F07195C18CF00ED456B /* BeGreaterThanTest.swift */; }; 1F925F0B195C18E100ED456B /* BeLessThanTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F0A195C18E100ED456B /* BeLessThanTest.swift */; }; 1F925F0C195C18E100ED456B /* BeLessThanTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F0A195C18E100ED456B /* BeLessThanTest.swift */; }; 1F925F0E195C18F500ED456B /* BeLessThanOrEqualToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F0D195C18F500ED456B /* BeLessThanOrEqualToTest.swift */; }; 1F925F0F195C18F500ED456B /* BeLessThanOrEqualToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F0D195C18F500ED456B /* BeLessThanOrEqualToTest.swift */; }; 1F925F11195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F10195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift */; }; 1F925F12195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F925F10195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift */; }; 1F9DB8FB1A74E793002E96AD /* ObjCBeEmptyTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F9DB8FA1A74E793002E96AD /* ObjCBeEmptyTest.m */; }; 1F9DB8FC1A74E793002E96AD /* ObjCBeEmptyTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F9DB8FA1A74E793002E96AD /* ObjCBeEmptyTest.m */; }; 1FB90098195EC4B8001D7FAE /* BeIdenticalToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FB90097195EC4B8001D7FAE /* BeIdenticalToTest.swift */; }; 1FB90099195EC4B8001D7FAE /* BeIdenticalToTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FB90097195EC4B8001D7FAE /* BeIdenticalToTest.swift */; }; 1FD8CD2E1968AB07008ED995 /* AssertionRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD051968AB07008ED995 /* AssertionRecorder.swift */; }; 1FD8CD2F1968AB07008ED995 /* AssertionRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD051968AB07008ED995 /* AssertionRecorder.swift */; }; 1FD8CD301968AB07008ED995 /* AdapterProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD061968AB07008ED995 /* AdapterProtocols.swift */; }; 1FD8CD311968AB07008ED995 /* AdapterProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD061968AB07008ED995 /* AdapterProtocols.swift */; }; 1FD8CD321968AB07008ED995 /* NimbleXCTestHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD071968AB07008ED995 /* NimbleXCTestHandler.swift */; }; 1FD8CD331968AB07008ED995 /* NimbleXCTestHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD071968AB07008ED995 /* NimbleXCTestHandler.swift */; }; 1FD8CD341968AB07008ED995 /* DSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD081968AB07008ED995 /* DSL.swift */; }; 1FD8CD351968AB07008ED995 /* DSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD081968AB07008ED995 /* DSL.swift */; }; 1FD8CD361968AB07008ED995 /* Expectation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD091968AB07008ED995 /* Expectation.swift */; }; 1FD8CD371968AB07008ED995 /* Expectation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD091968AB07008ED995 /* Expectation.swift */; }; 1FD8CD381968AB07008ED995 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0A1968AB07008ED995 /* Expression.swift */; }; 1FD8CD391968AB07008ED995 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0A1968AB07008ED995 /* Expression.swift */; }; 1FD8CD3A1968AB07008ED995 /* FailureMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0B1968AB07008ED995 /* FailureMessage.swift */; }; 1FD8CD3B1968AB07008ED995 /* FailureMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0B1968AB07008ED995 /* FailureMessage.swift */; }; 1FD8CD3C1968AB07008ED995 /* BeAnInstanceOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0D1968AB07008ED995 /* BeAnInstanceOf.swift */; }; 1FD8CD3D1968AB07008ED995 /* BeAnInstanceOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0D1968AB07008ED995 /* BeAnInstanceOf.swift */; }; 1FD8CD3E1968AB07008ED995 /* BeAKindOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0E1968AB07008ED995 /* BeAKindOf.swift */; }; 1FD8CD3F1968AB07008ED995 /* BeAKindOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0E1968AB07008ED995 /* BeAKindOf.swift */; }; 1FD8CD401968AB07008ED995 /* BeCloseTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0F1968AB07008ED995 /* BeCloseTo.swift */; }; 1FD8CD411968AB07008ED995 /* BeCloseTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD0F1968AB07008ED995 /* BeCloseTo.swift */; }; 1FD8CD421968AB07008ED995 /* BeEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD101968AB07008ED995 /* BeEmpty.swift */; }; 1FD8CD431968AB07008ED995 /* BeEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD101968AB07008ED995 /* BeEmpty.swift */; }; 1FD8CD441968AB07008ED995 /* BeginWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD111968AB07008ED995 /* BeginWith.swift */; }; 1FD8CD451968AB07008ED995 /* BeginWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD111968AB07008ED995 /* BeginWith.swift */; }; 1FD8CD461968AB07008ED995 /* BeGreaterThan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD121968AB07008ED995 /* BeGreaterThan.swift */; }; 1FD8CD471968AB07008ED995 /* BeGreaterThan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD121968AB07008ED995 /* BeGreaterThan.swift */; }; 1FD8CD481968AB07008ED995 /* BeGreaterThanOrEqualTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD131968AB07008ED995 /* BeGreaterThanOrEqualTo.swift */; }; 1FD8CD491968AB07008ED995 /* BeGreaterThanOrEqualTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD131968AB07008ED995 /* BeGreaterThanOrEqualTo.swift */; }; 1FD8CD4A1968AB07008ED995 /* BeIdenticalTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD141968AB07008ED995 /* BeIdenticalTo.swift */; }; 1FD8CD4B1968AB07008ED995 /* BeIdenticalTo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD141968AB07008ED995 /* BeIdenticalTo.swift */; }; 1FD8CD4C1968AB07008ED995 /* BeLessThan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD151968AB07008ED995 /* BeLessThan.swift */; }; 1FD8CD4D1968AB07008ED995 /* BeLessThan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD151968AB07008ED995 /* BeLessThan.swift */; }; 1FD8CD4E1968AB07008ED995 /* BeLessThanOrEqual.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD161968AB07008ED995 /* BeLessThanOrEqual.swift */; }; 1FD8CD4F1968AB07008ED995 /* BeLessThanOrEqual.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD161968AB07008ED995 /* BeLessThanOrEqual.swift */; }; 1FD8CD501968AB07008ED995 /* BeLogical.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD171968AB07008ED995 /* BeLogical.swift */; }; 1FD8CD511968AB07008ED995 /* BeLogical.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD171968AB07008ED995 /* BeLogical.swift */; }; 1FD8CD521968AB07008ED995 /* BeNil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD181968AB07008ED995 /* BeNil.swift */; }; 1FD8CD531968AB07008ED995 /* BeNil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD181968AB07008ED995 /* BeNil.swift */; }; 1FD8CD561968AB07008ED995 /* Contain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1A1968AB07008ED995 /* Contain.swift */; }; 1FD8CD571968AB07008ED995 /* Contain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1A1968AB07008ED995 /* Contain.swift */; }; 1FD8CD581968AB07008ED995 /* EndWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1B1968AB07008ED995 /* EndWith.swift */; }; 1FD8CD591968AB07008ED995 /* EndWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1B1968AB07008ED995 /* EndWith.swift */; }; 1FD8CD5A1968AB07008ED995 /* Equal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1C1968AB07008ED995 /* Equal.swift */; }; 1FD8CD5B1968AB07008ED995 /* Equal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1C1968AB07008ED995 /* Equal.swift */; }; 1FD8CD5C1968AB07008ED995 /* MatcherProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1D1968AB07008ED995 /* MatcherProtocols.swift */; }; 1FD8CD5D1968AB07008ED995 /* MatcherProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1D1968AB07008ED995 /* MatcherProtocols.swift */; }; 1FD8CD5E1968AB07008ED995 /* RaisesException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1E1968AB07008ED995 /* RaisesException.swift */; }; 1FD8CD5F1968AB07008ED995 /* RaisesException.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD1E1968AB07008ED995 /* RaisesException.swift */; }; 1FD8CD601968AB07008ED995 /* DSL.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FD8CD201968AB07008ED995 /* DSL.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1FD8CD611968AB07008ED995 /* DSL.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FD8CD201968AB07008ED995 /* DSL.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1FD8CD621968AB07008ED995 /* DSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD211968AB07008ED995 /* DSL.m */; }; 1FD8CD631968AB07008ED995 /* DSL.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD211968AB07008ED995 /* DSL.m */; }; 1FD8CD641968AB07008ED995 /* NMBExceptionCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FD8CD221968AB07008ED995 /* NMBExceptionCapture.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1FD8CD651968AB07008ED995 /* NMBExceptionCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FD8CD221968AB07008ED995 /* NMBExceptionCapture.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1FD8CD661968AB07008ED995 /* NMBExceptionCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD231968AB07008ED995 /* NMBExceptionCapture.m */; }; 1FD8CD671968AB07008ED995 /* NMBExceptionCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD231968AB07008ED995 /* NMBExceptionCapture.m */; }; 1FD8CD6A1968AB07008ED995 /* Poll.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD261968AB07008ED995 /* Poll.swift */; }; 1FD8CD6B1968AB07008ED995 /* Poll.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD261968AB07008ED995 /* Poll.swift */; }; 1FD8CD701968AB07008ED995 /* AsyncMatcherWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2A1968AB07008ED995 /* AsyncMatcherWrapper.swift */; }; 1FD8CD711968AB07008ED995 /* AsyncMatcherWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2A1968AB07008ED995 /* AsyncMatcherWrapper.swift */; }; 1FD8CD741968AB07008ED995 /* MatcherFunc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2C1968AB07008ED995 /* MatcherFunc.swift */; }; 1FD8CD751968AB07008ED995 /* MatcherFunc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2C1968AB07008ED995 /* MatcherFunc.swift */; }; 1FD8CD761968AB07008ED995 /* ObjCMatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2D1968AB07008ED995 /* ObjCMatcher.swift */; }; 1FD8CD771968AB07008ED995 /* ObjCMatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FD8CD2D1968AB07008ED995 /* ObjCMatcher.swift */; }; 1FDBD8671AF8A4FF0089F27B /* AssertionDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FDBD8661AF8A4FF0089F27B /* AssertionDispatcher.swift */; }; 1FDBD8681AF8A4FF0089F27B /* AssertionDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FDBD8661AF8A4FF0089F27B /* AssertionDispatcher.swift */; }; 29EA59631B551ED2002D767E /* ThrowErrorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29EA59621B551ED2002D767E /* ThrowErrorTest.swift */; }; 29EA59641B551ED2002D767E /* ThrowErrorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29EA59621B551ED2002D767E /* ThrowErrorTest.swift */; }; 29EA59661B551EE6002D767E /* ThrowError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29EA59651B551EE6002D767E /* ThrowError.swift */; }; 29EA59671B551EE6002D767E /* ThrowError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29EA59651B551EE6002D767E /* ThrowError.swift */; }; 472FD1351B9E085700C7B8DA /* HaveCount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472FD1341B9E085700C7B8DA /* HaveCount.swift */; }; 472FD1391B9E0A9700C7B8DA /* HaveCount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472FD1341B9E085700C7B8DA /* HaveCount.swift */; }; 472FD13A1B9E0A9F00C7B8DA /* HaveCountTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472FD1361B9E094B00C7B8DA /* HaveCountTest.swift */; }; 472FD13B1B9E0CFE00C7B8DA /* HaveCountTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472FD1361B9E094B00C7B8DA /* HaveCountTest.swift */; }; 4793854D1BA0BB2500296F85 /* ObjCHaveCount.m in Sources */ = {isa = PBXBuildFile; fileRef = 4793854C1BA0BB2500296F85 /* ObjCHaveCount.m */; }; 4793854E1BA0BB2500296F85 /* ObjCHaveCount.m in Sources */ = {isa = PBXBuildFile; fileRef = 4793854C1BA0BB2500296F85 /* ObjCHaveCount.m */; }; 965B0D091B62B8ED0005AE66 /* ObjCUserDescriptionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 965B0D081B62B8ED0005AE66 /* ObjCUserDescriptionTest.m */; }; 965B0D0A1B62B8ED0005AE66 /* ObjCUserDescriptionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 965B0D081B62B8ED0005AE66 /* ObjCUserDescriptionTest.m */; }; 965B0D0C1B62C06D0005AE66 /* UserDescriptionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 965B0D0B1B62C06D0005AE66 /* UserDescriptionTest.swift */; }; 965B0D0D1B62C06D0005AE66 /* UserDescriptionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 965B0D0B1B62C06D0005AE66 /* UserDescriptionTest.swift */; }; DA9E8C821A414BB9002633C2 /* DSL+Wait.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9E8C811A414BB9002633C2 /* DSL+Wait.swift */; }; DA9E8C831A414BB9002633C2 /* DSL+Wait.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9E8C811A414BB9002633C2 /* DSL+Wait.swift */; }; DD72EC641A93874A002F7651 /* AllPassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD72EC631A93874A002F7651 /* AllPassTest.swift */; }; DD72EC651A93874A002F7651 /* AllPassTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD72EC631A93874A002F7651 /* AllPassTest.swift */; }; DD9A9A8F19CF439B00706F49 /* BeIdenticalToObjectTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD9A9A8D19CF413800706F49 /* BeIdenticalToObjectTest.swift */; }; DD9A9A9019CF43AD00706F49 /* BeIdenticalToObjectTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD9A9A8D19CF413800706F49 /* BeIdenticalToObjectTest.swift */; }; DDB1BC791A92235600F743C3 /* AllPass.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB1BC781A92235600F743C3 /* AllPass.swift */; }; DDB1BC7A1A92235600F743C3 /* AllPass.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB1BC781A92235600F743C3 /* AllPass.swift */; }; DDB4D5ED19FE43C200E9D9FE /* Match.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB4D5EC19FE43C200E9D9FE /* Match.swift */; }; DDB4D5EE19FE43C200E9D9FE /* Match.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB4D5EC19FE43C200E9D9FE /* Match.swift */; }; DDB4D5F019FE442800E9D9FE /* MatchTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB4D5EF19FE442800E9D9FE /* MatchTest.swift */; }; DDB4D5F119FE442800E9D9FE /* MatchTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB4D5EF19FE442800E9D9FE /* MatchTest.swift */; }; DDEFAEB41A93CBE6005CA37A /* ObjCAllPassTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DDEFAEB31A93CBE6005CA37A /* ObjCAllPassTest.m */; }; DDEFAEB51A93CBE6005CA37A /* ObjCAllPassTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DDEFAEB31A93CBE6005CA37A /* ObjCAllPassTest.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 1F1A74361940169200FFFC47 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F1A74281940169200FFFC47; remoteInfo = "Nimble-iOS"; }; 1F5DF1601BDCA0CE00C3A531 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F5DF1541BDCA0CE00C3A531; remoteInfo = "Nimble-tvOS"; }; 1F6BB82A1968BFF9009F1DBB /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F1A74281940169200FFFC47; remoteInfo = "Nimble-iOS"; }; 1F925EA4195C0C8500ED456B /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F1A74281940169200FFFC47; remoteInfo = Nimble; }; 1F925EA6195C0C8500ED456B /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F1A74281940169200FFFC47; remoteInfo = Nimble; }; 1F925EB9195C0D6300ED456B /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F925EAC195C0D6300ED456B; remoteInfo = "Nimble-OSX"; }; 1F9B7BFD1968AD760094EB8F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F925EAC195C0D6300ED456B; remoteInfo = "Nimble-OSX"; }; 1F9B7BFF1968AD760094EB8F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F925EAC195C0D6300ED456B; remoteInfo = "Nimble-OSX"; }; 1F9B7C011968AD820094EB8F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1F1A74201940169200FFFC47 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F925EAC195C0D6300ED456B; remoteInfo = "Nimble-OSX"; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 1F0648CB19639F5A001F9C46 /* ObjectWithLazyProperty.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectWithLazyProperty.swift; sourceTree = ""; }; 1F0648D31963AAB2001F9C46 /* SynchronousTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronousTests.swift; sourceTree = ""; }; 1F0FEA991AF32DA4001E554E /* ObjCExpectation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjCExpectation.swift; sourceTree = ""; }; 1F14FB63194180C5009F2A08 /* utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = utils.swift; sourceTree = ""; }; 1F1A74291940169200FFFC47 /* Nimble.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Nimble.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1F1A742D1940169200FFFC47 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 1F1A742E1940169200FFFC47 /* Nimble.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Nimble.h; sourceTree = ""; }; 1F1A74341940169200FFFC47 /* NimbleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NimbleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 1F1A743A1940169200FFFC47 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 1F1B5AD31963E13900CA8BF9 /* BeAKindOfTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeAKindOfTest.swift; sourceTree = ""; }; 1F2752D119445B8400052A26 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; lineEnding = 0; path = README.md; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.markdown; }; 1F299EAA19627B2D002641AF /* BeEmptyTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeEmptyTest.swift; sourceTree = ""; }; 1F4A56651A3B305F009E1637 /* ObjCAsyncTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCAsyncTest.m; sourceTree = ""; }; 1F4A56681A3B3074009E1637 /* NimbleSpecHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NimbleSpecHelper.h; sourceTree = ""; }; 1F4A56691A3B3108009E1637 /* ObjCBeAnInstanceOfTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeAnInstanceOfTest.m; sourceTree = ""; }; 1F4A566C1A3B3159009E1637 /* ObjCBeKindOfTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeKindOfTest.m; sourceTree = ""; }; 1F4A566F1A3B319F009E1637 /* ObjCBeCloseToTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeCloseToTest.m; sourceTree = ""; }; 1F4A56721A3B3210009E1637 /* ObjCBeginWithTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeginWithTest.m; sourceTree = ""; }; 1F4A56751A3B3253009E1637 /* ObjCBeGreaterThanTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeGreaterThanTest.m; sourceTree = ""; }; 1F4A56781A3B32E3009E1637 /* ObjCBeGreaterThanOrEqualToTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeGreaterThanOrEqualToTest.m; sourceTree = ""; }; 1F4A567B1A3B3311009E1637 /* ObjCBeIdenticalToTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeIdenticalToTest.m; sourceTree = ""; }; 1F4A567E1A3B333F009E1637 /* ObjCBeLessThanTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeLessThanTest.m; sourceTree = ""; }; 1F4A56811A3B336F009E1637 /* ObjCBeLessThanOrEqualToTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeLessThanOrEqualToTest.m; sourceTree = ""; }; 1F4A56841A3B33A0009E1637 /* ObjCBeTruthyTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeTruthyTest.m; sourceTree = ""; }; 1F4A56871A3B33CB009E1637 /* ObjCBeFalsyTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeFalsyTest.m; sourceTree = ""; }; 1F4A568A1A3B3407009E1637 /* ObjCBeTrueTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeTrueTest.m; sourceTree = ""; }; 1F4A568D1A3B342B009E1637 /* ObjCBeFalseTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeFalseTest.m; sourceTree = ""; }; 1F4A56901A3B344A009E1637 /* ObjCBeNilTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeNilTest.m; sourceTree = ""; }; 1F4A56931A3B346F009E1637 /* ObjCContainTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCContainTest.m; sourceTree = ""; }; 1F4A56961A3B34AA009E1637 /* ObjCEndWithTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCEndWithTest.m; sourceTree = ""; }; 1F4A56991A3B3539009E1637 /* ObjCEqualTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCEqualTest.m; sourceTree = ""; }; 1F4A569C1A3B3565009E1637 /* ObjCMatchTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCMatchTest.m; sourceTree = ""; }; 1F4A569F1A3B359E009E1637 /* ObjCRaiseExceptionTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCRaiseExceptionTest.m; sourceTree = ""; }; 1F5DF1551BDCA0CE00C3A531 /* Nimble.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Nimble.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1F5DF15E1BDCA0CE00C3A531 /* NimbleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NimbleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 1F8A37AF1B7C5042001C8357 /* ObjCSyncTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCSyncTest.m; sourceTree = ""; }; 1F925EAD195C0D6300ED456B /* Nimble.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Nimble.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1F925EB7195C0D6300ED456B /* NimbleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NimbleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 1F925EE5195C121200ED456B /* AsynchronousTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsynchronousTest.swift; sourceTree = ""; }; 1F925EE8195C124400ED456B /* BeAnInstanceOfTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeAnInstanceOfTest.swift; sourceTree = ""; }; 1F925EEB195C12C800ED456B /* RaisesExceptionTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RaisesExceptionTest.swift; sourceTree = ""; }; 1F925EEE195C136500ED456B /* BeLogicalTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeLogicalTest.swift; sourceTree = ""; }; 1F925EF5195C147800ED456B /* BeCloseToTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeCloseToTest.swift; sourceTree = ""; }; 1F925EF8195C175000ED456B /* BeNilTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeNilTest.swift; sourceTree = ""; }; 1F925EFB195C186800ED456B /* BeginWithTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeginWithTest.swift; sourceTree = ""; }; 1F925EFE195C187600ED456B /* EndWithTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EndWithTest.swift; sourceTree = ""; }; 1F925F01195C189500ED456B /* ContainTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContainTest.swift; sourceTree = ""; }; 1F925F04195C18B700ED456B /* EqualTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EqualTest.swift; sourceTree = ""; }; 1F925F07195C18CF00ED456B /* BeGreaterThanTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeGreaterThanTest.swift; sourceTree = ""; }; 1F925F0A195C18E100ED456B /* BeLessThanTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeLessThanTest.swift; sourceTree = ""; }; 1F925F0D195C18F500ED456B /* BeLessThanOrEqualToTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeLessThanOrEqualToTest.swift; sourceTree = ""; }; 1F925F10195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeGreaterThanOrEqualToTest.swift; sourceTree = ""; }; 1F9DB8FA1A74E793002E96AD /* ObjCBeEmptyTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCBeEmptyTest.m; sourceTree = ""; }; 1FB90097195EC4B8001D7FAE /* BeIdenticalToTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeIdenticalToTest.swift; sourceTree = ""; }; 1FD8CD051968AB07008ED995 /* AssertionRecorder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssertionRecorder.swift; sourceTree = ""; }; 1FD8CD061968AB07008ED995 /* AdapterProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdapterProtocols.swift; sourceTree = ""; }; 1FD8CD071968AB07008ED995 /* NimbleXCTestHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NimbleXCTestHandler.swift; sourceTree = ""; }; 1FD8CD081968AB07008ED995 /* DSL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DSL.swift; sourceTree = ""; }; 1FD8CD091968AB07008ED995 /* Expectation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Expectation.swift; sourceTree = ""; }; 1FD8CD0A1968AB07008ED995 /* Expression.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Expression.swift; sourceTree = ""; }; 1FD8CD0B1968AB07008ED995 /* FailureMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FailureMessage.swift; sourceTree = ""; }; 1FD8CD0D1968AB07008ED995 /* BeAnInstanceOf.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeAnInstanceOf.swift; sourceTree = ""; }; 1FD8CD0E1968AB07008ED995 /* BeAKindOf.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeAKindOf.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD0F1968AB07008ED995 /* BeCloseTo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeCloseTo.swift; sourceTree = ""; }; 1FD8CD101968AB07008ED995 /* BeEmpty.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeEmpty.swift; sourceTree = ""; }; 1FD8CD111968AB07008ED995 /* BeginWith.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeginWith.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD121968AB07008ED995 /* BeGreaterThan.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeGreaterThan.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD131968AB07008ED995 /* BeGreaterThanOrEqualTo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeGreaterThanOrEqualTo.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD141968AB07008ED995 /* BeIdenticalTo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeIdenticalTo.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD151968AB07008ED995 /* BeLessThan.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeLessThan.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD161968AB07008ED995 /* BeLessThanOrEqual.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeLessThanOrEqual.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD171968AB07008ED995 /* BeLogical.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeLogical.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD181968AB07008ED995 /* BeNil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BeNil.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD1A1968AB07008ED995 /* Contain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Contain.swift; sourceTree = ""; }; 1FD8CD1B1968AB07008ED995 /* EndWith.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EndWith.swift; sourceTree = ""; }; 1FD8CD1C1968AB07008ED995 /* Equal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Equal.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD1D1968AB07008ED995 /* MatcherProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MatcherProtocols.swift; sourceTree = ""; }; 1FD8CD1E1968AB07008ED995 /* RaisesException.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = RaisesException.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 1FD8CD201968AB07008ED995 /* DSL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DSL.h; sourceTree = ""; }; 1FD8CD211968AB07008ED995 /* DSL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DSL.m; sourceTree = ""; }; 1FD8CD221968AB07008ED995 /* NMBExceptionCapture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NMBExceptionCapture.h; sourceTree = ""; }; 1FD8CD231968AB07008ED995 /* NMBExceptionCapture.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NMBExceptionCapture.m; sourceTree = ""; }; 1FD8CD251968AB07008ED995 /* Functional.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Functional.swift; sourceTree = ""; }; 1FD8CD261968AB07008ED995 /* Poll.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Poll.swift; sourceTree = ""; }; 1FD8CD271968AB07008ED995 /* SourceLocation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SourceLocation.swift; sourceTree = ""; }; 1FD8CD281968AB07008ED995 /* Stringers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Stringers.swift; sourceTree = ""; }; 1FD8CD2A1968AB07008ED995 /* AsyncMatcherWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsyncMatcherWrapper.swift; sourceTree = ""; }; 1FD8CD2C1968AB07008ED995 /* MatcherFunc.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MatcherFunc.swift; sourceTree = ""; }; 1FD8CD2D1968AB07008ED995 /* ObjCMatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjCMatcher.swift; sourceTree = ""; }; 1FDBD8661AF8A4FF0089F27B /* AssertionDispatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssertionDispatcher.swift; sourceTree = ""; }; 1FFD729B1963FCAB00CD29A2 /* NimbleTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NimbleTests-Bridging-Header.h"; sourceTree = ""; }; 1FFD729C1963FCAB00CD29A2 /* Nimble-OSXTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Nimble-OSXTests-Bridging-Header.h"; sourceTree = ""; }; 29EA59621B551ED2002D767E /* ThrowErrorTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThrowErrorTest.swift; sourceTree = ""; }; 29EA59651B551EE6002D767E /* ThrowError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThrowError.swift; sourceTree = ""; }; 472FD1341B9E085700C7B8DA /* HaveCount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HaveCount.swift; sourceTree = ""; }; 472FD1361B9E094B00C7B8DA /* HaveCountTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HaveCountTest.swift; sourceTree = ""; }; 4793854C1BA0BB2500296F85 /* ObjCHaveCount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCHaveCount.m; sourceTree = ""; }; 965B0D081B62B8ED0005AE66 /* ObjCUserDescriptionTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCUserDescriptionTest.m; sourceTree = ""; }; 965B0D0B1B62C06D0005AE66 /* UserDescriptionTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDescriptionTest.swift; sourceTree = ""; }; DA9E8C811A414BB9002633C2 /* DSL+Wait.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DSL+Wait.swift"; sourceTree = ""; }; DD72EC631A93874A002F7651 /* AllPassTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AllPassTest.swift; sourceTree = ""; }; DD9A9A8D19CF413800706F49 /* BeIdenticalToObjectTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeIdenticalToObjectTest.swift; sourceTree = ""; }; DDB1BC781A92235600F743C3 /* AllPass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AllPass.swift; sourceTree = ""; }; DDB4D5EC19FE43C200E9D9FE /* Match.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Match.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; DDB4D5EF19FE442800E9D9FE /* MatchTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MatchTest.swift; sourceTree = ""; }; DDEFAEB31A93CBE6005CA37A /* ObjCAllPassTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjCAllPassTest.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 1F1A74251940169200FFFC47 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F1A74311940169200FFFC47 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 1F1A74351940169200FFFC47 /* Nimble.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F5DF1511BDCA0CE00C3A531 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F5DF15B1BDCA0CE00C3A531 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 1F5DF15F1BDCA0CE00C3A531 /* Nimble.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F925EA9195C0D6300ED456B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F925EB4195C0D6300ED456B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 1F925EB8195C0D6300ED456B /* Nimble.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 1F14FB61194180A7009F2A08 /* Helpers */ = { isa = PBXGroup; children = ( 1F14FB63194180C5009F2A08 /* utils.swift */, 1F0648CB19639F5A001F9C46 /* ObjectWithLazyProperty.swift */, ); path = Helpers; sourceTree = ""; }; 1F1A741F1940169200FFFC47 = { isa = PBXGroup; children = ( 1F2752D119445B8400052A26 /* README.md */, 1F1A742B1940169200FFFC47 /* Nimble */, 1F1A74381940169200FFFC47 /* NimbleTests */, 1F1A742A1940169200FFFC47 /* Products */, ); sourceTree = ""; }; 1F1A742A1940169200FFFC47 /* Products */ = { isa = PBXGroup; children = ( 1F1A74291940169200FFFC47 /* Nimble.framework */, 1F1A74341940169200FFFC47 /* NimbleTests.xctest */, 1F925EAD195C0D6300ED456B /* Nimble.framework */, 1F925EB7195C0D6300ED456B /* NimbleTests.xctest */, 1F5DF1551BDCA0CE00C3A531 /* Nimble.framework */, 1F5DF15E1BDCA0CE00C3A531 /* NimbleTests.xctest */, ); name = Products; sourceTree = ""; }; 1F1A742B1940169200FFFC47 /* Nimble */ = { isa = PBXGroup; children = ( 1FD8CD041968AB07008ED995 /* Adapters */, 1FD8CD081968AB07008ED995 /* DSL.swift */, DA9E8C811A414BB9002633C2 /* DSL+Wait.swift */, 1FD8CD091968AB07008ED995 /* Expectation.swift */, 1F0FEA991AF32DA4001E554E /* ObjCExpectation.swift */, 1FD8CD0A1968AB07008ED995 /* Expression.swift */, 1FD8CD0B1968AB07008ED995 /* FailureMessage.swift */, 1FD8CD0C1968AB07008ED995 /* Matchers */, 1F1A742E1940169200FFFC47 /* Nimble.h */, 1FD8CD1F1968AB07008ED995 /* objc */, 1F1A742C1940169200FFFC47 /* Supporting Files */, 1FD8CD241968AB07008ED995 /* Utils */, 1FD8CD291968AB07008ED995 /* Wrappers */, ); path = Nimble; sourceTree = ""; }; 1F1A742C1940169200FFFC47 /* Supporting Files */ = { isa = PBXGroup; children = ( 1F1A742D1940169200FFFC47 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; 1F1A74381940169200FFFC47 /* NimbleTests */ = { isa = PBXGroup; children = ( 1F925EE5195C121200ED456B /* AsynchronousTest.swift */, 1F0648D31963AAB2001F9C46 /* SynchronousTests.swift */, 965B0D0B1B62C06D0005AE66 /* UserDescriptionTest.swift */, 1FFD729A1963FC8200CD29A2 /* objc */, 1F14FB61194180A7009F2A08 /* Helpers */, 1F925EE3195C11B000ED456B /* Matchers */, 1F1A74391940169200FFFC47 /* Supporting Files */, ); path = NimbleTests; sourceTree = ""; }; 1F1A74391940169200FFFC47 /* Supporting Files */ = { isa = PBXGroup; children = ( 1F1A743A1940169200FFFC47 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; 1F925EE3195C11B000ED456B /* Matchers */ = { isa = PBXGroup; children = ( DD72EC631A93874A002F7651 /* AllPassTest.swift */, 1F1B5AD31963E13900CA8BF9 /* BeAKindOfTest.swift */, 1F925EE8195C124400ED456B /* BeAnInstanceOfTest.swift */, 1F925EF5195C147800ED456B /* BeCloseToTest.swift */, 1F299EAA19627B2D002641AF /* BeEmptyTest.swift */, 1F925EFB195C186800ED456B /* BeginWithTest.swift */, 1F925F10195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift */, 1F925F07195C18CF00ED456B /* BeGreaterThanTest.swift */, DD9A9A8D19CF413800706F49 /* BeIdenticalToObjectTest.swift */, 1FB90097195EC4B8001D7FAE /* BeIdenticalToTest.swift */, 1F925F0D195C18F500ED456B /* BeLessThanOrEqualToTest.swift */, 1F925F0A195C18E100ED456B /* BeLessThanTest.swift */, 1F925EEE195C136500ED456B /* BeLogicalTest.swift */, 1F925EF8195C175000ED456B /* BeNilTest.swift */, 1F925F01195C189500ED456B /* ContainTest.swift */, 1F925EFE195C187600ED456B /* EndWithTest.swift */, 1F925F04195C18B700ED456B /* EqualTest.swift */, 472FD1361B9E094B00C7B8DA /* HaveCountTest.swift */, DDB4D5EF19FE442800E9D9FE /* MatchTest.swift */, 1F925EEB195C12C800ED456B /* RaisesExceptionTest.swift */, 29EA59621B551ED2002D767E /* ThrowErrorTest.swift */, ); path = Matchers; sourceTree = ""; }; 1FD8CD041968AB07008ED995 /* Adapters */ = { isa = PBXGroup; children = ( 1FD8CD051968AB07008ED995 /* AssertionRecorder.swift */, 1FD8CD061968AB07008ED995 /* AdapterProtocols.swift */, 1FD8CD071968AB07008ED995 /* NimbleXCTestHandler.swift */, 1FDBD8661AF8A4FF0089F27B /* AssertionDispatcher.swift */, ); path = Adapters; sourceTree = ""; }; 1FD8CD0C1968AB07008ED995 /* Matchers */ = { isa = PBXGroup; children = ( DDB1BC781A92235600F743C3 /* AllPass.swift */, 1FD8CD0E1968AB07008ED995 /* BeAKindOf.swift */, 1FD8CD0D1968AB07008ED995 /* BeAnInstanceOf.swift */, 1FD8CD0F1968AB07008ED995 /* BeCloseTo.swift */, 1FD8CD101968AB07008ED995 /* BeEmpty.swift */, 1FD8CD111968AB07008ED995 /* BeginWith.swift */, 1FD8CD121968AB07008ED995 /* BeGreaterThan.swift */, 1FD8CD131968AB07008ED995 /* BeGreaterThanOrEqualTo.swift */, 1FD8CD141968AB07008ED995 /* BeIdenticalTo.swift */, 1FD8CD151968AB07008ED995 /* BeLessThan.swift */, 1FD8CD161968AB07008ED995 /* BeLessThanOrEqual.swift */, 1FD8CD171968AB07008ED995 /* BeLogical.swift */, 1FD8CD181968AB07008ED995 /* BeNil.swift */, 1FD8CD1A1968AB07008ED995 /* Contain.swift */, 1FD8CD1B1968AB07008ED995 /* EndWith.swift */, 1FD8CD1C1968AB07008ED995 /* Equal.swift */, 472FD1341B9E085700C7B8DA /* HaveCount.swift */, DDB4D5EC19FE43C200E9D9FE /* Match.swift */, 1FD8CD1D1968AB07008ED995 /* MatcherProtocols.swift */, 1FD8CD1E1968AB07008ED995 /* RaisesException.swift */, 29EA59651B551EE6002D767E /* ThrowError.swift */, ); path = Matchers; sourceTree = ""; }; 1FD8CD1F1968AB07008ED995 /* objc */ = { isa = PBXGroup; children = ( 1FD8CD201968AB07008ED995 /* DSL.h */, 1FD8CD211968AB07008ED995 /* DSL.m */, 1FD8CD221968AB07008ED995 /* NMBExceptionCapture.h */, 1FD8CD231968AB07008ED995 /* NMBExceptionCapture.m */, ); path = objc; sourceTree = ""; }; 1FD8CD241968AB07008ED995 /* Utils */ = { isa = PBXGroup; children = ( 1FD8CD251968AB07008ED995 /* Functional.swift */, 1FD8CD261968AB07008ED995 /* Poll.swift */, 1FD8CD271968AB07008ED995 /* SourceLocation.swift */, 1FD8CD281968AB07008ED995 /* Stringers.swift */, ); path = Utils; sourceTree = ""; }; 1FD8CD291968AB07008ED995 /* Wrappers */ = { isa = PBXGroup; children = ( 1FD8CD2A1968AB07008ED995 /* AsyncMatcherWrapper.swift */, 1FD8CD2C1968AB07008ED995 /* MatcherFunc.swift */, 1FD8CD2D1968AB07008ED995 /* ObjCMatcher.swift */, ); path = Wrappers; sourceTree = ""; }; 1FFD729A1963FC8200CD29A2 /* objc */ = { isa = PBXGroup; children = ( 1FFD729C1963FCAB00CD29A2 /* Nimble-OSXTests-Bridging-Header.h */, 1F4A56681A3B3074009E1637 /* NimbleSpecHelper.h */, 1FFD729B1963FCAB00CD29A2 /* NimbleTests-Bridging-Header.h */, 1F4A56651A3B305F009E1637 /* ObjCAsyncTest.m */, 1F8A37AF1B7C5042001C8357 /* ObjCSyncTest.m */, 1F4A56691A3B3108009E1637 /* ObjCBeAnInstanceOfTest.m */, 1F4A566F1A3B319F009E1637 /* ObjCBeCloseToTest.m */, 1F9DB8FA1A74E793002E96AD /* ObjCBeEmptyTest.m */, 1F4A568D1A3B342B009E1637 /* ObjCBeFalseTest.m */, 1F4A56871A3B33CB009E1637 /* ObjCBeFalsyTest.m */, 1F4A56721A3B3210009E1637 /* ObjCBeginWithTest.m */, 1F4A56781A3B32E3009E1637 /* ObjCBeGreaterThanOrEqualToTest.m */, 1F4A56751A3B3253009E1637 /* ObjCBeGreaterThanTest.m */, 1F4A567B1A3B3311009E1637 /* ObjCBeIdenticalToTest.m */, 1F4A566C1A3B3159009E1637 /* ObjCBeKindOfTest.m */, 1F4A56811A3B336F009E1637 /* ObjCBeLessThanOrEqualToTest.m */, 1F4A567E1A3B333F009E1637 /* ObjCBeLessThanTest.m */, 1F4A56901A3B344A009E1637 /* ObjCBeNilTest.m */, 1F4A568A1A3B3407009E1637 /* ObjCBeTrueTest.m */, 1F4A56841A3B33A0009E1637 /* ObjCBeTruthyTest.m */, 1F4A56931A3B346F009E1637 /* ObjCContainTest.m */, 1F4A56961A3B34AA009E1637 /* ObjCEndWithTest.m */, 1F4A56991A3B3539009E1637 /* ObjCEqualTest.m */, 4793854C1BA0BB2500296F85 /* ObjCHaveCount.m */, 1F4A569C1A3B3565009E1637 /* ObjCMatchTest.m */, 1F4A569F1A3B359E009E1637 /* ObjCRaiseExceptionTest.m */, 965B0D081B62B8ED0005AE66 /* ObjCUserDescriptionTest.m */, DDEFAEB31A93CBE6005CA37A /* ObjCAllPassTest.m */, ); path = objc; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 1F1A74261940169200FFFC47 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 1FD8CD601968AB07008ED995 /* DSL.h in Headers */, 1FD8CD641968AB07008ED995 /* NMBExceptionCapture.h in Headers */, 1F1A742F1940169200FFFC47 /* Nimble.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F5DF1521BDCA0CE00C3A531 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 1F5DF1AF1BDCA17600C3A531 /* DSL.h in Headers */, 1F5DF1B01BDCA17600C3A531 /* NMBExceptionCapture.h in Headers */, 1F5DF1AE1BDCA17600C3A531 /* Nimble.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F925EAA195C0D6300ED456B /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 1FD8CD611968AB07008ED995 /* DSL.h in Headers */, 1FD8CD651968AB07008ED995 /* NMBExceptionCapture.h in Headers */, 1F925EC7195C0DD100ED456B /* Nimble.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 1F1A74281940169200FFFC47 /* Nimble-iOS */ = { isa = PBXNativeTarget; buildConfigurationList = 1F1A743F1940169200FFFC47 /* Build configuration list for PBXNativeTarget "Nimble-iOS" */; buildPhases = ( 1F1A74241940169200FFFC47 /* Sources */, 1F1A74251940169200FFFC47 /* Frameworks */, 1F1A74261940169200FFFC47 /* Headers */, 1F1A74271940169200FFFC47 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Nimble-iOS"; productName = "Nimble-iOS"; productReference = 1F1A74291940169200FFFC47 /* Nimble.framework */; productType = "com.apple.product-type.framework"; }; 1F1A74331940169200FFFC47 /* Nimble-iOSTests */ = { isa = PBXNativeTarget; buildConfigurationList = 1F1A74421940169200FFFC47 /* Build configuration list for PBXNativeTarget "Nimble-iOSTests" */; buildPhases = ( 1F1A74301940169200FFFC47 /* Sources */, 1F1A74311940169200FFFC47 /* Frameworks */, 1F1A74321940169200FFFC47 /* Resources */, ); buildRules = ( ); dependencies = ( 1F1A74371940169200FFFC47 /* PBXTargetDependency */, 1F925EA5195C0C8500ED456B /* PBXTargetDependency */, 1F925EA7195C0C8500ED456B /* PBXTargetDependency */, 1F6BB82B1968BFF9009F1DBB /* PBXTargetDependency */, ); name = "Nimble-iOSTests"; productName = "Nimble-iOSTests"; productReference = 1F1A74341940169200FFFC47 /* NimbleTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 1F5DF1541BDCA0CE00C3A531 /* Nimble-tvOS */ = { isa = PBXNativeTarget; buildConfigurationList = 1F5DF16A1BDCA0CE00C3A531 /* Build configuration list for PBXNativeTarget "Nimble-tvOS" */; buildPhases = ( 1F5DF1501BDCA0CE00C3A531 /* Sources */, 1F5DF1511BDCA0CE00C3A531 /* Frameworks */, 1F5DF1521BDCA0CE00C3A531 /* Headers */, 1F5DF1531BDCA0CE00C3A531 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Nimble-tvOS"; productName = "Nimble-tvOS"; productReference = 1F5DF1551BDCA0CE00C3A531 /* Nimble.framework */; productType = "com.apple.product-type.framework"; }; 1F5DF15D1BDCA0CE00C3A531 /* Nimble-tvOSTests */ = { isa = PBXNativeTarget; buildConfigurationList = 1F5DF16B1BDCA0CE00C3A531 /* Build configuration list for PBXNativeTarget "Nimble-tvOSTests" */; buildPhases = ( 1F5DF15A1BDCA0CE00C3A531 /* Sources */, 1F5DF15B1BDCA0CE00C3A531 /* Frameworks */, 1F5DF15C1BDCA0CE00C3A531 /* Resources */, ); buildRules = ( ); dependencies = ( 1F5DF1611BDCA0CE00C3A531 /* PBXTargetDependency */, ); name = "Nimble-tvOSTests"; productName = "Nimble-tvOSTests"; productReference = 1F5DF15E1BDCA0CE00C3A531 /* NimbleTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 1F925EAC195C0D6300ED456B /* Nimble-OSX */ = { isa = PBXNativeTarget; buildConfigurationList = 1F925EC0195C0D6300ED456B /* Build configuration list for PBXNativeTarget "Nimble-OSX" */; buildPhases = ( 1F925EA8195C0D6300ED456B /* Sources */, 1F925EA9195C0D6300ED456B /* Frameworks */, 1F925EAA195C0D6300ED456B /* Headers */, 1F925EAB195C0D6300ED456B /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Nimble-OSX"; productName = "Nimble-OSX"; productReference = 1F925EAD195C0D6300ED456B /* Nimble.framework */; productType = "com.apple.product-type.framework"; }; 1F925EB6195C0D6300ED456B /* Nimble-OSXTests */ = { isa = PBXNativeTarget; buildConfigurationList = 1F925EC3195C0D6300ED456B /* Build configuration list for PBXNativeTarget "Nimble-OSXTests" */; buildPhases = ( 1F925EB3195C0D6300ED456B /* Sources */, 1F925EB4195C0D6300ED456B /* Frameworks */, 1F925EB5195C0D6300ED456B /* Resources */, ); buildRules = ( ); dependencies = ( 1F925EBA195C0D6300ED456B /* PBXTargetDependency */, 1F9B7BFE1968AD760094EB8F /* PBXTargetDependency */, 1F9B7C001968AD760094EB8F /* PBXTargetDependency */, 1F9B7C021968AD820094EB8F /* PBXTargetDependency */, ); name = "Nimble-OSXTests"; productName = "Nimble-OSXTests"; productReference = 1F925EB7195C0D6300ED456B /* NimbleTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 1F1A74201940169200FFFC47 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0710; LastUpgradeCheck = 0710; ORGANIZATIONNAME = "Jeff Hui"; TargetAttributes = { 1F1A74281940169200FFFC47 = { CreatedOnToolsVersion = 6.0; }; 1F1A74331940169200FFFC47 = { CreatedOnToolsVersion = 6.0; TestTargetID = 1F1A74281940169200FFFC47; }; 1F5DF1541BDCA0CE00C3A531 = { CreatedOnToolsVersion = 7.1; }; 1F5DF15D1BDCA0CE00C3A531 = { CreatedOnToolsVersion = 7.1; }; 1F925EAC195C0D6300ED456B = { CreatedOnToolsVersion = 6.0; }; 1F925EB6195C0D6300ED456B = { CreatedOnToolsVersion = 6.0; TestTargetID = 1F925EAC195C0D6300ED456B; }; }; }; buildConfigurationList = 1F1A74231940169200FFFC47 /* Build configuration list for PBXProject "Nimble" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = 1F1A741F1940169200FFFC47; productRefGroup = 1F1A742A1940169200FFFC47 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 1F1A74281940169200FFFC47 /* Nimble-iOS */, 1F1A74331940169200FFFC47 /* Nimble-iOSTests */, 1F925EAC195C0D6300ED456B /* Nimble-OSX */, 1F925EB6195C0D6300ED456B /* Nimble-OSXTests */, 1F5DF1541BDCA0CE00C3A531 /* Nimble-tvOS */, 1F5DF15D1BDCA0CE00C3A531 /* Nimble-tvOSTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 1F1A74271940169200FFFC47 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F1A74321940169200FFFC47 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F5DF1531BDCA0CE00C3A531 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F5DF15C1BDCA0CE00C3A531 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F925EAB195C0D6300ED456B /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F925EB5195C0D6300ED456B /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 1F1A74241940169200FFFC47 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 1FD8CD401968AB07008ED995 /* BeCloseTo.swift in Sources */, 1FD8CD741968AB07008ED995 /* MatcherFunc.swift in Sources */, 1FD8CD361968AB07008ED995 /* Expectation.swift in Sources */, 1FD8CD321968AB07008ED995 /* NimbleXCTestHandler.swift in Sources */, 1F43728F1A1B344000EB80F8 /* Stringers.swift in Sources */, 1F43728D1A1B343D00EB80F8 /* SourceLocation.swift in Sources */, 1FD8CD4E1968AB07008ED995 /* BeLessThanOrEqual.swift in Sources */, 1FDBD8671AF8A4FF0089F27B /* AssertionDispatcher.swift in Sources */, 1F43728A1A1B343800EB80F8 /* Functional.swift in Sources */, 1FD8CD3C1968AB07008ED995 /* BeAnInstanceOf.swift in Sources */, 1FD8CD501968AB07008ED995 /* BeLogical.swift in Sources */, 1F0FEA9A1AF32DA4001E554E /* ObjCExpectation.swift in Sources */, 1FD8CD661968AB07008ED995 /* NMBExceptionCapture.m in Sources */, DA9E8C821A414BB9002633C2 /* DSL+Wait.swift in Sources */, DDB1BC791A92235600F743C3 /* AllPass.swift in Sources */, 1FD8CD3E1968AB07008ED995 /* BeAKindOf.swift in Sources */, DDB4D5ED19FE43C200E9D9FE /* Match.swift in Sources */, 1FD8CD2E1968AB07008ED995 /* AssertionRecorder.swift in Sources */, 29EA59661B551EE6002D767E /* ThrowError.swift in Sources */, 1FD8CD5A1968AB07008ED995 /* Equal.swift in Sources */, 1FD8CD4C1968AB07008ED995 /* BeLessThan.swift in Sources */, 1FD8CD461968AB07008ED995 /* BeGreaterThan.swift in Sources */, 1FD8CD301968AB07008ED995 /* AdapterProtocols.swift in Sources */, 1FD8CD5E1968AB07008ED995 /* RaisesException.swift in Sources */, 1FD8CD561968AB07008ED995 /* Contain.swift in Sources */, 1FD8CD481968AB07008ED995 /* BeGreaterThanOrEqualTo.swift in Sources */, 1FD8CD701968AB07008ED995 /* AsyncMatcherWrapper.swift in Sources */, 1FD8CD441968AB07008ED995 /* BeginWith.swift in Sources */, 1FD8CD4A1968AB07008ED995 /* BeIdenticalTo.swift in Sources */, 1FD8CD621968AB07008ED995 /* DSL.m in Sources */, 1FD8CD421968AB07008ED995 /* BeEmpty.swift in Sources */, 1FD8CD521968AB07008ED995 /* BeNil.swift in Sources */, 1FD8CD6A1968AB07008ED995 /* Poll.swift in Sources */, 1FD8CD581968AB07008ED995 /* EndWith.swift in Sources */, 1FD8CD5C1968AB07008ED995 /* MatcherProtocols.swift in Sources */, 1FD8CD761968AB07008ED995 /* ObjCMatcher.swift in Sources */, 1FD8CD341968AB07008ED995 /* DSL.swift in Sources */, 1FD8CD381968AB07008ED995 /* Expression.swift in Sources */, 1FD8CD3A1968AB07008ED995 /* FailureMessage.swift in Sources */, 472FD1351B9E085700C7B8DA /* HaveCount.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F1A74301940169200FFFC47 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 1F4A569A1A3B3539009E1637 /* ObjCEqualTest.m in Sources */, 1F925EEC195C12C800ED456B /* RaisesExceptionTest.swift in Sources */, 1F925EFF195C187600ED456B /* EndWithTest.swift in Sources */, 1F1B5AD41963E13900CA8BF9 /* BeAKindOfTest.swift in Sources */, 1F925F0E195C18F500ED456B /* BeLessThanOrEqualToTest.swift in Sources */, 1F4A56661A3B305F009E1637 /* ObjCAsyncTest.m in Sources */, 1F925EFC195C186800ED456B /* BeginWithTest.swift in Sources */, 1F14FB64194180C5009F2A08 /* utils.swift in Sources */, DDB4D5F019FE442800E9D9FE /* MatchTest.swift in Sources */, 1F4A56731A3B3210009E1637 /* ObjCBeginWithTest.m in Sources */, 1F4A56821A3B336F009E1637 /* ObjCBeLessThanOrEqualToTest.m in Sources */, 1F925F02195C189500ED456B /* ContainTest.swift in Sources */, 1F4A56881A3B33CB009E1637 /* ObjCBeFalsyTest.m in Sources */, 1F4A568E1A3B342B009E1637 /* ObjCBeFalseTest.m in Sources */, 1F925F11195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift in Sources */, 1F925EEF195C136500ED456B /* BeLogicalTest.swift in Sources */, 1F4A56A01A3B359E009E1637 /* ObjCRaiseExceptionTest.m in Sources */, 1F925F0B195C18E100ED456B /* BeLessThanTest.swift in Sources */, 1F9DB8FB1A74E793002E96AD /* ObjCBeEmptyTest.m in Sources */, 1FB90098195EC4B8001D7FAE /* BeIdenticalToTest.swift in Sources */, 1F4A56761A3B3253009E1637 /* ObjCBeGreaterThanTest.m in Sources */, 1F925EF9195C175000ED456B /* BeNilTest.swift in Sources */, 1F4A56701A3B319F009E1637 /* ObjCBeCloseToTest.m in Sources */, 1F4A56971A3B34AA009E1637 /* ObjCEndWithTest.m in Sources */, 1F4A567C1A3B3311009E1637 /* ObjCBeIdenticalToTest.m in Sources */, 965B0D0C1B62C06D0005AE66 /* UserDescriptionTest.swift in Sources */, 965B0D091B62B8ED0005AE66 /* ObjCUserDescriptionTest.m in Sources */, 1F4A56911A3B344A009E1637 /* ObjCBeNilTest.m in Sources */, 1F8A37B01B7C5042001C8357 /* ObjCSyncTest.m in Sources */, 1F4A56941A3B346F009E1637 /* ObjCContainTest.m in Sources */, 1F299EAB19627B2D002641AF /* BeEmptyTest.swift in Sources */, 1F925EF6195C147800ED456B /* BeCloseToTest.swift in Sources */, 1F4A56791A3B32E3009E1637 /* ObjCBeGreaterThanOrEqualToTest.m in Sources */, 1F4A568B1A3B3407009E1637 /* ObjCBeTrueTest.m in Sources */, DDEFAEB41A93CBE6005CA37A /* ObjCAllPassTest.m in Sources */, 1F4A567F1A3B333F009E1637 /* ObjCBeLessThanTest.m in Sources */, 1F925EE6195C121200ED456B /* AsynchronousTest.swift in Sources */, 1F0648CC19639F5A001F9C46 /* ObjectWithLazyProperty.swift in Sources */, 1F4A56851A3B33A0009E1637 /* ObjCBeTruthyTest.m in Sources */, DD9A9A8F19CF439B00706F49 /* BeIdenticalToObjectTest.swift in Sources */, 1F0648D41963AAB2001F9C46 /* SynchronousTests.swift in Sources */, 4793854D1BA0BB2500296F85 /* ObjCHaveCount.m in Sources */, 1F925F08195C18CF00ED456B /* BeGreaterThanTest.swift in Sources */, 1F925F05195C18B700ED456B /* EqualTest.swift in Sources */, 1F4A566D1A3B3159009E1637 /* ObjCBeKindOfTest.m in Sources */, DD72EC641A93874A002F7651 /* AllPassTest.swift in Sources */, 1F4A569D1A3B3565009E1637 /* ObjCMatchTest.m in Sources */, 1F925EE9195C124400ED456B /* BeAnInstanceOfTest.swift in Sources */, 29EA59631B551ED2002D767E /* ThrowErrorTest.swift in Sources */, 1F4A566A1A3B3108009E1637 /* ObjCBeAnInstanceOfTest.m in Sources */, 472FD13B1B9E0CFE00C7B8DA /* HaveCountTest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F5DF1501BDCA0CE00C3A531 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 1F5DF1791BDCA0F500C3A531 /* BeCloseTo.swift in Sources */, 1F5DF16C1BDCA0F500C3A531 /* AssertionRecorder.swift in Sources */, 1F5DF1881BDCA0F500C3A531 /* MatcherProtocols.swift in Sources */, 1F5DF16E1BDCA0F500C3A531 /* NimbleXCTestHandler.swift in Sources */, 1F5DF1751BDCA0F500C3A531 /* FailureMessage.swift in Sources */, 1F5DF1801BDCA0F500C3A531 /* BeLessThanOrEqual.swift in Sources */, 1F5DF18A1BDCA0F500C3A531 /* ThrowError.swift in Sources */, 1F5DF1891BDCA0F500C3A531 /* RaisesException.swift in Sources */, 1F5DF1761BDCA0F500C3A531 /* AllPass.swift in Sources */, 1F5DF1861BDCA0F500C3A531 /* HaveCount.swift in Sources */, 1F5DF1811BDCA0F500C3A531 /* BeLogical.swift in Sources */, 1F5DF1741BDCA0F500C3A531 /* Expression.swift in Sources */, 1F5DF1911BDCA0F500C3A531 /* ObjCMatcher.swift in Sources */, 1F5DF1781BDCA0F500C3A531 /* BeAnInstanceOf.swift in Sources */, 1F5DF1771BDCA0F500C3A531 /* BeAKindOf.swift in Sources */, 1F5DF17F1BDCA0F500C3A531 /* BeLessThan.swift in Sources */, 1F5DF17C1BDCA0F500C3A531 /* BeGreaterThan.swift in Sources */, 1F5DF1831BDCA0F500C3A531 /* Contain.swift in Sources */, 1F5DF1731BDCA0F500C3A531 /* ObjCExpectation.swift in Sources */, 1F5DF1851BDCA0F500C3A531 /* Equal.swift in Sources */, 1F5DF18F1BDCA0F500C3A531 /* AsyncMatcherWrapper.swift in Sources */, 1F5DF1711BDCA0F500C3A531 /* DSL+Wait.swift in Sources */, 1F5DF17D1BDCA0F500C3A531 /* BeGreaterThanOrEqualTo.swift in Sources */, 1F5DF18E1BDCA0F500C3A531 /* Stringers.swift in Sources */, 1F5DF1AD1BDCA16E00C3A531 /* NMBExceptionCapture.m in Sources */, 1F5DF16D1BDCA0F500C3A531 /* AdapterProtocols.swift in Sources */, 1F5DF17B1BDCA0F500C3A531 /* BeginWith.swift in Sources */, 1F5DF17E1BDCA0F500C3A531 /* BeIdenticalTo.swift in Sources */, 1F5DF17A1BDCA0F500C3A531 /* BeEmpty.swift in Sources */, 1F5DF18C1BDCA0F500C3A531 /* Poll.swift in Sources */, 1F5DF1821BDCA0F500C3A531 /* BeNil.swift in Sources */, 1F5DF1AC1BDCA16E00C3A531 /* DSL.m in Sources */, 1F5DF16F1BDCA0F500C3A531 /* AssertionDispatcher.swift in Sources */, 1F5DF1841BDCA0F500C3A531 /* EndWith.swift in Sources */, 1F5DF18D1BDCA0F500C3A531 /* SourceLocation.swift in Sources */, 1F5DF1701BDCA0F500C3A531 /* DSL.swift in Sources */, 1F5DF1721BDCA0F500C3A531 /* Expectation.swift in Sources */, 1F5DF18B1BDCA0F500C3A531 /* Functional.swift in Sources */, 1F5DF1871BDCA0F500C3A531 /* Match.swift in Sources */, 1F5DF1901BDCA0F500C3A531 /* MatcherFunc.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F5DF15A1BDCA0CE00C3A531 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 1F5DF1A31BDCA10200C3A531 /* BeLogicalTest.swift in Sources */, 1F5DF1951BDCA10200C3A531 /* utils.swift in Sources */, 1F5DF1981BDCA10200C3A531 /* BeAKindOfTest.swift in Sources */, 1F5DF19B1BDCA10200C3A531 /* BeEmptyTest.swift in Sources */, 1F5DF1A11BDCA10200C3A531 /* BeLessThanOrEqualToTest.swift in Sources */, 1F5DF1961BDCA10200C3A531 /* ObjectWithLazyProperty.swift in Sources */, 1F5DF1AB1BDCA10200C3A531 /* ThrowErrorTest.swift in Sources */, 1F5DF1A51BDCA10200C3A531 /* ContainTest.swift in Sources */, 1F5DF19E1BDCA10200C3A531 /* BeGreaterThanTest.swift in Sources */, 1F5DF1A21BDCA10200C3A531 /* BeLessThanTest.swift in Sources */, 1F5DF1921BDCA10200C3A531 /* AsynchronousTest.swift in Sources */, 1F5DF1A91BDCA10200C3A531 /* MatchTest.swift in Sources */, 1F5DF1A81BDCA10200C3A531 /* HaveCountTest.swift in Sources */, 1F5DF1971BDCA10200C3A531 /* AllPassTest.swift in Sources */, 1F5DF19C1BDCA10200C3A531 /* BeginWithTest.swift in Sources */, 1F5DF1A01BDCA10200C3A531 /* BeIdenticalToTest.swift in Sources */, 1F5DF19A1BDCA10200C3A531 /* BeCloseToTest.swift in Sources */, 1F5DF1A61BDCA10200C3A531 /* EndWithTest.swift in Sources */, 1F5DF1A71BDCA10200C3A531 /* EqualTest.swift in Sources */, 1F5DF1931BDCA10200C3A531 /* SynchronousTests.swift in Sources */, 1F5DF19D1BDCA10200C3A531 /* BeGreaterThanOrEqualToTest.swift in Sources */, 1F5DF1A41BDCA10200C3A531 /* BeNilTest.swift in Sources */, 1F5DF1AA1BDCA10200C3A531 /* RaisesExceptionTest.swift in Sources */, 1F5DF1941BDCA10200C3A531 /* UserDescriptionTest.swift in Sources */, 1F5DF19F1BDCA10200C3A531 /* BeIdenticalToObjectTest.swift in Sources */, 1F5DF1991BDCA10200C3A531 /* BeAnInstanceOfTest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F925EA8195C0D6300ED456B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 1FD8CD411968AB07008ED995 /* BeCloseTo.swift in Sources */, 1FD8CD751968AB07008ED995 /* MatcherFunc.swift in Sources */, 1FD8CD371968AB07008ED995 /* Expectation.swift in Sources */, 1FD8CD331968AB07008ED995 /* NimbleXCTestHandler.swift in Sources */, 1F43728E1A1B343F00EB80F8 /* Stringers.swift in Sources */, 1F43728C1A1B343C00EB80F8 /* SourceLocation.swift in Sources */, 1FD8CD4F1968AB07008ED995 /* BeLessThanOrEqual.swift in Sources */, 1FDBD8681AF8A4FF0089F27B /* AssertionDispatcher.swift in Sources */, 1F43728B1A1B343900EB80F8 /* Functional.swift in Sources */, 1FD8CD3D1968AB07008ED995 /* BeAnInstanceOf.swift in Sources */, 1FD8CD511968AB07008ED995 /* BeLogical.swift in Sources */, 1F0FEA9B1AF32DA4001E554E /* ObjCExpectation.swift in Sources */, 1FD8CD671968AB07008ED995 /* NMBExceptionCapture.m in Sources */, DA9E8C831A414BB9002633C2 /* DSL+Wait.swift in Sources */, DDB1BC7A1A92235600F743C3 /* AllPass.swift in Sources */, 1FD8CD3F1968AB07008ED995 /* BeAKindOf.swift in Sources */, 1FD8CD2F1968AB07008ED995 /* AssertionRecorder.swift in Sources */, DDB4D5EE19FE43C200E9D9FE /* Match.swift in Sources */, 29EA59671B551EE6002D767E /* ThrowError.swift in Sources */, 1FD8CD5B1968AB07008ED995 /* Equal.swift in Sources */, 1FD8CD4D1968AB07008ED995 /* BeLessThan.swift in Sources */, 1FD8CD471968AB07008ED995 /* BeGreaterThan.swift in Sources */, 1FD8CD311968AB07008ED995 /* AdapterProtocols.swift in Sources */, 1FD8CD5F1968AB07008ED995 /* RaisesException.swift in Sources */, 1FD8CD571968AB07008ED995 /* Contain.swift in Sources */, 1FD8CD491968AB07008ED995 /* BeGreaterThanOrEqualTo.swift in Sources */, 1FD8CD711968AB07008ED995 /* AsyncMatcherWrapper.swift in Sources */, 1FD8CD451968AB07008ED995 /* BeginWith.swift in Sources */, 1FD8CD4B1968AB07008ED995 /* BeIdenticalTo.swift in Sources */, 1FD8CD631968AB07008ED995 /* DSL.m in Sources */, 1FD8CD431968AB07008ED995 /* BeEmpty.swift in Sources */, 1FD8CD531968AB07008ED995 /* BeNil.swift in Sources */, 1FD8CD6B1968AB07008ED995 /* Poll.swift in Sources */, 1FD8CD591968AB07008ED995 /* EndWith.swift in Sources */, 1FD8CD5D1968AB07008ED995 /* MatcherProtocols.swift in Sources */, 1FD8CD771968AB07008ED995 /* ObjCMatcher.swift in Sources */, 1FD8CD351968AB07008ED995 /* DSL.swift in Sources */, 1FD8CD391968AB07008ED995 /* Expression.swift in Sources */, 1FD8CD3B1968AB07008ED995 /* FailureMessage.swift in Sources */, 472FD1391B9E0A9700C7B8DA /* HaveCount.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F925EB3195C0D6300ED456B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 1F4A569B1A3B3539009E1637 /* ObjCEqualTest.m in Sources */, 1F925EED195C12C800ED456B /* RaisesExceptionTest.swift in Sources */, 1F925F00195C187600ED456B /* EndWithTest.swift in Sources */, 1F1B5AD51963E13900CA8BF9 /* BeAKindOfTest.swift in Sources */, 1F925F0F195C18F500ED456B /* BeLessThanOrEqualToTest.swift in Sources */, 1F4A56671A3B305F009E1637 /* ObjCAsyncTest.m in Sources */, 1F925EFD195C186800ED456B /* BeginWithTest.swift in Sources */, 1F925EE2195C0DFD00ED456B /* utils.swift in Sources */, DDB4D5F119FE442800E9D9FE /* MatchTest.swift in Sources */, 1F4A56741A3B3210009E1637 /* ObjCBeginWithTest.m in Sources */, 1F4A56831A3B336F009E1637 /* ObjCBeLessThanOrEqualToTest.m in Sources */, 1F925F03195C189500ED456B /* ContainTest.swift in Sources */, 1F4A56891A3B33CB009E1637 /* ObjCBeFalsyTest.m in Sources */, 1F4A568F1A3B342B009E1637 /* ObjCBeFalseTest.m in Sources */, 1F925F12195C190B00ED456B /* BeGreaterThanOrEqualToTest.swift in Sources */, 1F925EF0195C136500ED456B /* BeLogicalTest.swift in Sources */, 1F4A56A11A3B359E009E1637 /* ObjCRaiseExceptionTest.m in Sources */, 1F925F0C195C18E100ED456B /* BeLessThanTest.swift in Sources */, 1F9DB8FC1A74E793002E96AD /* ObjCBeEmptyTest.m in Sources */, 1FB90099195EC4B8001D7FAE /* BeIdenticalToTest.swift in Sources */, 1F4A56771A3B3253009E1637 /* ObjCBeGreaterThanTest.m in Sources */, 1F925EFA195C175000ED456B /* BeNilTest.swift in Sources */, 1F4A56711A3B319F009E1637 /* ObjCBeCloseToTest.m in Sources */, 1F4A56981A3B34AA009E1637 /* ObjCEndWithTest.m in Sources */, 1F4A567D1A3B3311009E1637 /* ObjCBeIdenticalToTest.m in Sources */, 965B0D0D1B62C06D0005AE66 /* UserDescriptionTest.swift in Sources */, 965B0D0A1B62B8ED0005AE66 /* ObjCUserDescriptionTest.m in Sources */, 1F4A56921A3B344A009E1637 /* ObjCBeNilTest.m in Sources */, 1F8A37B11B7C5042001C8357 /* ObjCSyncTest.m in Sources */, 1F4A56951A3B346F009E1637 /* ObjCContainTest.m in Sources */, 1F299EAC19627B2D002641AF /* BeEmptyTest.swift in Sources */, 1F925EF7195C147800ED456B /* BeCloseToTest.swift in Sources */, 1F4A567A1A3B32E3009E1637 /* ObjCBeGreaterThanOrEqualToTest.m in Sources */, 1F4A568C1A3B3407009E1637 /* ObjCBeTrueTest.m in Sources */, DDEFAEB51A93CBE6005CA37A /* ObjCAllPassTest.m in Sources */, 1F4A56801A3B333F009E1637 /* ObjCBeLessThanTest.m in Sources */, 1F925EE7195C121200ED456B /* AsynchronousTest.swift in Sources */, 1F0648CD19639F5A001F9C46 /* ObjectWithLazyProperty.swift in Sources */, 1F4A56861A3B33A0009E1637 /* ObjCBeTruthyTest.m in Sources */, DD9A9A9019CF43AD00706F49 /* BeIdenticalToObjectTest.swift in Sources */, 1F0648D51963AAB2001F9C46 /* SynchronousTests.swift in Sources */, 4793854E1BA0BB2500296F85 /* ObjCHaveCount.m in Sources */, 1F925F09195C18CF00ED456B /* BeGreaterThanTest.swift in Sources */, 1F925F06195C18B700ED456B /* EqualTest.swift in Sources */, 1F4A566E1A3B3159009E1637 /* ObjCBeKindOfTest.m in Sources */, DD72EC651A93874A002F7651 /* AllPassTest.swift in Sources */, 1F4A569E1A3B3565009E1637 /* ObjCMatchTest.m in Sources */, 1F925EEA195C124400ED456B /* BeAnInstanceOfTest.swift in Sources */, 29EA59641B551ED2002D767E /* ThrowErrorTest.swift in Sources */, 1F4A566B1A3B3108009E1637 /* ObjCBeAnInstanceOfTest.m in Sources */, 472FD13A1B9E0A9F00C7B8DA /* HaveCountTest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 1F1A74371940169200FFFC47 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F1A74281940169200FFFC47 /* Nimble-iOS */; targetProxy = 1F1A74361940169200FFFC47 /* PBXContainerItemProxy */; }; 1F5DF1611BDCA0CE00C3A531 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F5DF1541BDCA0CE00C3A531 /* Nimble-tvOS */; targetProxy = 1F5DF1601BDCA0CE00C3A531 /* PBXContainerItemProxy */; }; 1F6BB82B1968BFF9009F1DBB /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F1A74281940169200FFFC47 /* Nimble-iOS */; targetProxy = 1F6BB82A1968BFF9009F1DBB /* PBXContainerItemProxy */; }; 1F925EA5195C0C8500ED456B /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F1A74281940169200FFFC47 /* Nimble-iOS */; targetProxy = 1F925EA4195C0C8500ED456B /* PBXContainerItemProxy */; }; 1F925EA7195C0C8500ED456B /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F1A74281940169200FFFC47 /* Nimble-iOS */; targetProxy = 1F925EA6195C0C8500ED456B /* PBXContainerItemProxy */; }; 1F925EBA195C0D6300ED456B /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F925EAC195C0D6300ED456B /* Nimble-OSX */; targetProxy = 1F925EB9195C0D6300ED456B /* PBXContainerItemProxy */; }; 1F9B7BFE1968AD760094EB8F /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F925EAC195C0D6300ED456B /* Nimble-OSX */; targetProxy = 1F9B7BFD1968AD760094EB8F /* PBXContainerItemProxy */; }; 1F9B7C001968AD760094EB8F /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F925EAC195C0D6300ED456B /* Nimble-OSX */; targetProxy = 1F9B7BFF1968AD760094EB8F /* PBXContainerItemProxy */; }; 1F9B7C021968AD820094EB8F /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F925EAC195C0D6300ED456B /* Nimble-OSX */; targetProxy = 1F9B7C011968AD820094EB8F /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 1F1A743D1940169200FFFC47 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_MODULES_AUTOLINK = NO; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; 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; IPHONEOS_DEPLOYMENT_TARGET = 7.0; METAL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TARGETED_DEVICE_FAMILY = "1,2,3"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; 1F1A743E1940169200FFFC47 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_MODULES_AUTOLINK = NO; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; CURRENT_PROJECT_VERSION = 1; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; 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; IPHONEOS_DEPLOYMENT_TARGET = 7.0; METAL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2,3"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Release; }; 1F1A74401940169200FFFC47 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(DEVELOPER_FRAMEWORKS_DIR)", ); GCC_TREAT_WARNINGS_AS_ERRORS = YES; INFOPLIST_FILE = Nimble/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; ONLY_ACTIVE_ARCH = NO; OTHER_LDFLAGS = ( "-weak_framework", XCTest, "-weak-lswiftXCTest", ); PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_MODULE_NAME = Nimble; PRODUCT_NAME = Nimble; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 1F1A74411940169200FFFC47 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(DEVELOPER_FRAMEWORKS_DIR)", ); GCC_TREAT_WARNINGS_AS_ERRORS = YES; INFOPLIST_FILE = Nimble/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_LDFLAGS = ( "-weak_framework", XCTest, "-weak-lswiftXCTest", ); PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_MODULE_NAME = Nimble; PRODUCT_NAME = Nimble; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SWIFT_OBJC_BRIDGING_HEADER = ""; }; name = Release; }; 1F1A74431940169200FFFC47 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = NimbleTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; METAL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = NimbleTests; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OBJC_BRIDGING_HEADER = "NimbleTests/objc/NimbleTests-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 1F1A74441940169200FFFC47 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", ); INFOPLIST_FILE = NimbleTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; METAL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = NimbleTests; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OBJC_BRIDGING_HEADER = "NimbleTests/objc/NimbleTests-Bridging-Header.h"; }; name = Release; }; 1F5DF1661BDCA0CE00C3A531 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(DEVELOPER_FRAMEWORKS_DIR)", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = Nimble/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; OTHER_LDFLAGS = ( "-weak_framework", XCTest, "-weak-lswiftXCTest", ); PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_MODULE_NAME = Nimble; PRODUCT_NAME = Nimble; SDKROOT = appletvos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; }; 1F5DF1671BDCA0CE00C3A531 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(DEVELOPER_FRAMEWORKS_DIR)", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = Nimble/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = ( "-weak_framework", XCTest, "-weak-lswiftXCTest", ); PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_MODULE_NAME = Nimble; PRODUCT_NAME = Nimble; SDKROOT = appletvos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Release; }; 1F5DF1681BDCA0CE00C3A531 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { DEBUG_INFORMATION_FORMAT = dwarf; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = NimbleTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = NimbleTests; SDKROOT = appletvos; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; }; 1F5DF1691BDCA0CE00C3A531 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = NimbleTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = NimbleTests; SDKROOT = appletvos; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Release; }; 1F925EC1195C0D6300ED456B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(DEVELOPER_FRAMEWORKS_DIR)", ); FRAMEWORK_VERSION = A; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_TREAT_WARNINGS_AS_ERRORS = YES; INFOPLIST_FILE = Nimble/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.9; METAL_ENABLE_DEBUG_INFO = YES; OTHER_LDFLAGS = ( "-weak_framework", XCTest, "-weak-lswiftXCTest", ); PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_MODULE_NAME = Nimble; PRODUCT_NAME = Nimble; SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OBJC_BRIDGING_HEADER = ""; VALID_ARCHS = x86_64; }; name = Debug; }; 1F925EC2195C0D6300ED456B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(DEVELOPER_FRAMEWORKS_DIR)", ); FRAMEWORK_VERSION = A; GCC_TREAT_WARNINGS_AS_ERRORS = YES; INFOPLIST_FILE = Nimble/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.9; METAL_ENABLE_DEBUG_INFO = NO; OTHER_LDFLAGS = ( "-weak_framework", XCTest, "-weak-lswiftXCTest", ); PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_MODULE_NAME = Nimble; PRODUCT_NAME = Nimble; SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_OBJC_BRIDGING_HEADER = ""; VALID_ARCHS = x86_64; }; name = Release; }; 1F925EC4195C0D6300ED456B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = NimbleTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.9; METAL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = NimbleTests; SDKROOT = macosx; SWIFT_OBJC_BRIDGING_HEADER = "NimbleTests/objc/Nimble-OSXTests-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 1F925EC5195C0D6300ED456B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); INFOPLIST_FILE = NimbleTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.9; METAL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "net.jeffhui.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = NimbleTests; SDKROOT = macosx; SWIFT_OBJC_BRIDGING_HEADER = "NimbleTests/objc/Nimble-OSXTests-Bridging-Header.h"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 1F1A74231940169200FFFC47 /* Build configuration list for PBXProject "Nimble" */ = { isa = XCConfigurationList; buildConfigurations = ( 1F1A743D1940169200FFFC47 /* Debug */, 1F1A743E1940169200FFFC47 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 1F1A743F1940169200FFFC47 /* Build configuration list for PBXNativeTarget "Nimble-iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 1F1A74401940169200FFFC47 /* Debug */, 1F1A74411940169200FFFC47 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 1F1A74421940169200FFFC47 /* Build configuration list for PBXNativeTarget "Nimble-iOSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 1F1A74431940169200FFFC47 /* Debug */, 1F1A74441940169200FFFC47 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 1F5DF16A1BDCA0CE00C3A531 /* Build configuration list for PBXNativeTarget "Nimble-tvOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 1F5DF1661BDCA0CE00C3A531 /* Debug */, 1F5DF1671BDCA0CE00C3A531 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 1F5DF16B1BDCA0CE00C3A531 /* Build configuration list for PBXNativeTarget "Nimble-tvOSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 1F5DF1681BDCA0CE00C3A531 /* Debug */, 1F5DF1691BDCA0CE00C3A531 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 1F925EC0195C0D6300ED456B /* Build configuration list for PBXNativeTarget "Nimble-OSX" */ = { isa = XCConfigurationList; buildConfigurations = ( 1F925EC1195C0D6300ED456B /* Debug */, 1F925EC2195C0D6300ED456B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 1F925EC3195C0D6300ED456B /* Build configuration list for PBXNativeTarget "Nimble-OSXTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 1F925EC4195C0D6300ED456B /* Debug */, 1F925EC5195C0D6300ED456B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 1F1A74201940169200FFFC47 /* Project object */; } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble.xcodeproj/xcshareddata/xcschemes/Nimble-OSX.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble.xcodeproj/xcshareddata/xcschemes/Nimble-iOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/Nimble.xcodeproj/xcshareddata/xcschemes/Nimble-tvOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/AsynchronousTest.swift ================================================ import XCTest import Nimble import Swift class AsyncTest: XCTestCase { let errorToThrow = NSError(domain: NSInternalInconsistencyException, code: 42, userInfo: nil) private func doThrowError() throws -> Int { throw errorToThrow } func testAsyncTestingViaEventuallyPositiveMatches() { var value = 0 deferToMainQueue { value = 1 } expect { value }.toEventually(equal(1)) deferToMainQueue { value = 0 } expect { value }.toEventuallyNot(equal(1)) } func testAsyncTestingViaEventuallyNegativeMatches() { let value = 0 failsWithErrorMessage("expected to eventually not equal <0>, got <0>") { expect { value }.toEventuallyNot(equal(0)) } failsWithErrorMessage("expected to eventually equal <1>, got <0>") { expect { value }.toEventually(equal(1)) } failsWithErrorMessage("expected to eventually equal <1>, got an unexpected error thrown: <\(errorToThrow)>") { expect { try self.doThrowError() }.toEventually(equal(1)) } failsWithErrorMessage("expected to eventually not equal <0>, got an unexpected error thrown: <\(errorToThrow)>") { expect { try self.doThrowError() }.toEventuallyNot(equal(0)) } } func testAsyncTestingViaWaitUntilPositiveMatches() { waitUntil { done in done() } waitUntil { done in deferToMainQueue { done() } } } func testAsyncTestingViaWaitUntilNegativeMatches() { failsWithErrorMessage("Waited more than 1.0 second") { waitUntil(timeout: 1) { done in return } } failsWithErrorMessage("Waited more than 0.01 seconds") { waitUntil(timeout: 0.01) { done in NSThread.sleepForTimeInterval(0.1) done() } } failsWithErrorMessage("expected to equal <2>, got <1>") { waitUntil { done in NSThread.sleepForTimeInterval(0.1) expect(1).to(equal(2)) done() } } // "clear" runloop to ensure this test doesn't poison other tests NSRunLoop.mainRunLoop().runUntilDate(NSDate().dateByAddingTimeInterval(0.2)) } func testWaitUntilDetectsStalledMainThreadActivity() { dispatch_async(dispatch_get_main_queue()) { NSThread.sleepForTimeInterval(2.0) } failsWithErrorMessage("Stall on main thread - too much enqueued on main run loop before waitUntil executes.") { waitUntil { done in done() } } // "clear" runloop to ensure this test doesn't poison other tests NSRunLoop.mainRunLoop().runUntilDate(NSDate().dateByAddingTimeInterval(2.0)) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Helpers/ObjectWithLazyProperty.swift ================================================ import Foundation class ObjectWithLazyProperty { init() {} lazy var value: String = "hello" lazy var anotherValue: String = { return "world" }() } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Helpers/utils.swift ================================================ import Foundation import Nimble import XCTest func failsWithErrorMessage(messages: [String], file: String = __FILE__, line: UInt = __LINE__, preferOriginalSourceLocation: Bool = false, closure: () throws -> Void) { var filePath = file var lineNumber = line let recorder = AssertionRecorder() withAssertionHandler(recorder, closure: closure) for msg in messages { var lastFailure: AssertionRecord? var foundFailureMessage = false for assertion in recorder.assertions { lastFailure = assertion if assertion.message.stringValue == msg { foundFailureMessage = true break } } if foundFailureMessage { continue } if preferOriginalSourceLocation { if let failure = lastFailure { filePath = failure.location.file lineNumber = failure.location.line } } if let lastFailure = lastFailure { let msg = "Got failure message: \"\(lastFailure.message.stringValue)\", but expected \"\(msg)\"" XCTFail(msg, file: filePath, line: lineNumber) } else { XCTFail("expected failure message, but got none", file: filePath, line: lineNumber) } } } func failsWithErrorMessage(message: String, file: String = __FILE__, line: UInt = __LINE__, preferOriginalSourceLocation: Bool = false, closure: () -> Void) { return failsWithErrorMessage( [message], file: file, line: line, preferOriginalSourceLocation: preferOriginalSourceLocation, closure: closure ) } func failsWithErrorMessageForNil(message: String, file: String = __FILE__, line: UInt = __LINE__, preferOriginalSourceLocation: Bool = false, closure: () -> Void) { failsWithErrorMessage("\(message) (use beNil() to match nils)", file: file, line: line, preferOriginalSourceLocation: preferOriginalSourceLocation, closure: closure) } func deferToMainQueue(action: () -> Void) { dispatch_async(dispatch_get_main_queue()) { NSThread.sleepForTimeInterval(0.01) action() } } public class NimbleHelper : NSObject { class func expectFailureMessage(message: NSString, block: () -> Void, file: String, line: UInt) { failsWithErrorMessage(message as String, file: file, line: line, preferOriginalSourceLocation: true, closure: block) } class func expectFailureMessages(messages: [NSString], block: () -> Void, file: String, line: UInt) { failsWithErrorMessage(messages as! [String], file: file, line: line, preferOriginalSourceLocation: true, closure: block) } class func expectFailureMessageForNil(message: NSString, block: () -> Void, file: String, line: UInt) { failsWithErrorMessageForNil(message as String, file: file, line: line, preferOriginalSourceLocation: true, closure: block) } } extension NSDate { convenience init(dateTimeString:String) { let dateFormatter = NSDateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss" dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") let date = dateFormatter.dateFromString(dateTimeString)! self.init(timeInterval:0, sinceDate:date) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/AllPassTest.swift ================================================ import XCTest import Nimble class AllPassTest: XCTestCase { func testAllPassArray() { expect([1,2,3,4]).to(allPass({$0 < 5})) expect([1,2,3,4]).toNot(allPass({$0 > 5})) failsWithErrorMessage( "expected to all pass a condition, but failed first at element <3> in <[1, 2, 3, 4]>") { expect([1,2,3,4]).to(allPass({$0 < 3})) } failsWithErrorMessage("expected to not all pass a condition") { expect([1,2,3,4]).toNot(allPass({$0 < 5})) } failsWithErrorMessage( "expected to all be something, but failed first at element <3> in <[1, 2, 3, 4]>") { expect([1,2,3,4]).to(allPass("be something", {$0 < 3})) } failsWithErrorMessage("expected to not all be something") { expect([1,2,3,4]).toNot(allPass("be something", {$0 < 5})) } } func testAllPassMatcher() { expect([1,2,3,4]).to(allPass(beLessThan(5))) expect([1,2,3,4]).toNot(allPass(beGreaterThan(5))) failsWithErrorMessage( "expected to all be less than <3>, but failed first at element <3> in <[1, 2, 3, 4]>") { expect([1,2,3,4]).to(allPass(beLessThan(3))) } failsWithErrorMessage("expected to not all be less than <5>") { expect([1,2,3,4]).toNot(allPass(beLessThan(5))) } } func testAllPassCollectionsWithOptionalsDontWork() { failsWithErrorMessage("expected to all be nil, but failed first at element in <[nil, nil, nil]>") { expect([nil, nil, nil] as [Int?]).to(allPass(beNil())) } failsWithErrorMessage("expected to all pass a condition, but failed first at element in <[nil, nil, nil]>") { expect([nil, nil, nil] as [Int?]).to(allPass({$0 == nil})) } } func testAllPassCollectionsWithOptionalsUnwrappingOneOptionalLayer() { expect([nil, nil, nil] as [Int?]).to(allPass({$0! == nil})) expect([nil, 1, nil] as [Int?]).toNot(allPass({$0! == nil})) expect([1, 1, 1] as [Int?]).to(allPass({$0! == 1})) expect([1, 1, nil] as [Int?]).toNot(allPass({$0! == 1})) expect([1, 2, 3] as [Int?]).to(allPass({$0! < 4})) expect([1, 2, 3] as [Int?]).toNot(allPass({$0! < 3})) expect([1, 2, nil] as [Int?]).to(allPass({$0! < 3})) } func testAllPassSet() { expect(Set([1,2,3,4])).to(allPass({$0 < 5})) expect(Set([1,2,3,4])).toNot(allPass({$0 > 5})) failsWithErrorMessage("expected to not all pass a condition") { expect(Set([1,2,3,4])).toNot(allPass({$0 < 5})) } failsWithErrorMessage("expected to not all be something") { expect(Set([1,2,3,4])).toNot(allPass("be something", {$0 < 5})) } } func testAllPassWithNilAsExpectedValue() { failsWithErrorMessageForNil("expected to all pass") { expect(nil as [Int]?).to(allPass(beLessThan(5))) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/BeAKindOfTest.swift ================================================ import XCTest import Nimble class TestNull : NSNull {} class BeAKindOfTest: XCTestCase { func testPositiveMatch() { expect(TestNull()).to(beAKindOf(NSNull)) expect(NSObject()).to(beAKindOf(NSObject)) expect(NSNumber(integer:1)).toNot(beAKindOf(NSDate)) } func testFailureMessages() { failsWithErrorMessageForNil("expected to not be a kind of NSNull, got ") { expect(nil as NSNull?).toNot(beAKindOf(NSNull)) } failsWithErrorMessageForNil("expected to be a kind of NSString, got ") { expect(nil as NSString?).to(beAKindOf(NSString)) } failsWithErrorMessage("expected to be a kind of NSString, got <__NSCFNumber instance>") { expect(NSNumber(integer:1)).to(beAKindOf(NSString)) } failsWithErrorMessage("expected to not be a kind of NSNumber, got <__NSCFNumber instance>") { expect(NSNumber(integer:1)).toNot(beAKindOf(NSNumber)) } } func testSwiftTypesFailureMessages() { enum TestEnum { case One, Two } failsWithErrorMessage("beAKindOf only works on Objective-C types since the Swift compiler" + " will automatically type check Swift-only types. This expectation is redundant.") { expect(1).to(beAKindOf(Int)) } failsWithErrorMessage("beAKindOf only works on Objective-C types since the Swift compiler" + " will automatically type check Swift-only types. This expectation is redundant.") { expect("test").to(beAKindOf(String)) } failsWithErrorMessage("beAKindOf only works on Objective-C types since the Swift compiler" + " will automatically type check Swift-only types. This expectation is redundant.") { expect(TestEnum.One).to(beAKindOf(TestEnum)) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/BeAnInstanceOfTest.swift ================================================ import XCTest import Nimble class BeAnInstanceOfTest: XCTestCase { func testPositiveMatch() { expect(NSNull()).to(beAnInstanceOf(NSNull)) expect(NSNumber(integer:1)).toNot(beAnInstanceOf(NSDate)) } func testFailureMessages() { failsWithErrorMessageForNil("expected to not be an instance of NSNull, got ") { expect(nil as NSNull?).toNot(beAnInstanceOf(NSNull)) } failsWithErrorMessageForNil("expected to be an instance of NSString, got ") { expect(nil as NSString?).to(beAnInstanceOf(NSString)) } failsWithErrorMessage("expected to be an instance of NSString, got <__NSCFNumber instance>") { expect(NSNumber(integer:1)).to(beAnInstanceOf(NSString)) } failsWithErrorMessage("expected to not be an instance of NSNumber, got <__NSCFNumber instance>") { expect(NSNumber(integer:1)).toNot(beAnInstanceOf(NSNumber)) } } func testSwiftTypesFailureMessages() { enum TestEnum { case One, Two } failsWithErrorMessage("beAnInstanceOf only works on Objective-C types since the Swift compiler" + " will automatically type check Swift-only types. This expectation is redundant.") { expect(1).to(beAnInstanceOf(Int)) } failsWithErrorMessage("beAnInstanceOf only works on Objective-C types since the Swift compiler" + " will automatically type check Swift-only types. This expectation is redundant.") { expect("test").to(beAnInstanceOf(String)) } failsWithErrorMessage("beAnInstanceOf only works on Objective-C types since the Swift compiler" + " will automatically type check Swift-only types. This expectation is redundant.") { expect(TestEnum.One).to(beAnInstanceOf(TestEnum)) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/BeCloseToTest.swift ================================================ import XCTest import Nimble class BeCloseToTest: XCTestCase { func testBeCloseTo() { expect(1.2).to(beCloseTo(1.2001)) expect(1.2 as CDouble).to(beCloseTo(1.2001)) expect(1.2 as Float).to(beCloseTo(1.2001)) failsWithErrorMessage("expected to not be close to <1.2001> (within 0.0001), got <1.2000>") { expect(1.2).toNot(beCloseTo(1.2001)) } } func testBeCloseToWithin() { expect(1.2).to(beCloseTo(9.300, within: 10)) failsWithErrorMessage("expected to not be close to <1.2001> (within 1.0000), got <1.2000>") { expect(1.2).toNot(beCloseTo(1.2001, within: 1.0)) } } func testBeCloseToWithNSNumber() { expect(NSNumber(double:1.2)).to(beCloseTo(9.300, within: 10)) expect(NSNumber(double:1.2)).to(beCloseTo(NSNumber(double:9.300), within: 10)) expect(1.2).to(beCloseTo(NSNumber(double:9.300), within: 10)) failsWithErrorMessage("expected to not be close to <1.2001> (within 1.0000), got <1.2000>") { expect(NSNumber(double:1.2)).toNot(beCloseTo(1.2001, within: 1.0)) } } func testBeCloseToWithNSDate() { expect(NSDate(dateTimeString: "2015-08-26 11:43:00")).to(beCloseTo(NSDate(dateTimeString: "2015-08-26 11:43:05"), within: 10)) failsWithErrorMessage("expected to not be close to <2015-08-26 11:43:00.0050> (within 0.0040), got <2015-08-26 11:43:00.0000>") { let expectedDate = NSDate(dateTimeString: "2015-08-26 11:43:00").dateByAddingTimeInterval(0.005) expect(NSDate(dateTimeString: "2015-08-26 11:43:00")).toNot(beCloseTo(expectedDate, within: 0.004)) } } func testBeCloseToOperator() { expect(1.2) ≈ 1.2001 expect(1.2 as CDouble) ≈ 1.2001 failsWithErrorMessage("expected to be close to <1.2002> (within 0.0001), got <1.2000>") { expect(1.2) ≈ 1.2002 } } func testBeCloseToWithinOperator() { expect(1.2) ≈ (9.300, 10) expect(1.2) == (9.300, 10) failsWithErrorMessage("expected to be close to <1.0000> (within 0.1000), got <1.2000>") { expect(1.2) ≈ (1.0, 0.1) } failsWithErrorMessage("expected to be close to <1.0000> (within 0.1000), got <1.2000>") { expect(1.2) == (1.0, 0.1) } } func testPlusMinusOperator() { expect(1.2) ≈ 9.300 ± 10 expect(1.2) == 9.300 ± 10 failsWithErrorMessage("expected to be close to <1.0000> (within 0.1000), got <1.2000>") { expect(1.2) ≈ 1.0 ± 0.1 } failsWithErrorMessage("expected to be close to <1.0000> (within 0.1000), got <1.2000>") { expect(1.2) == 1.0 ± 0.1 } } func testBeCloseToArray() { expect([0.0, 1.1, 2.2]) ≈ [0.0001, 1.1001, 2.2001] expect([0.0, 1.1, 2.2]).to(beCloseTo([0.1, 1.2, 2.3], within: 0.1)) failsWithErrorMessage("expected to be close to <[0.0000, 1.0000]> (each within 0.0001), got <[0.0, 1.1]>") { expect([0.0, 1.1]) ≈ [0.0, 1.0] } failsWithErrorMessage("expected to be close to <[0.2000, 1.2000]> (each within 0.1000), got <[0.0, 1.1]>") { expect([0.0, 1.1]).to(beCloseTo([0.2, 1.2], within: 0.1)) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/BeEmptyTest.swift ================================================ import XCTest import Nimble class BeEmptyTest: XCTestCase { func testBeEmptyPositive() { expect([] as [Int]).to(beEmpty()) expect([1]).toNot(beEmpty()) expect([] as [CInt]).to(beEmpty()) expect([1] as [CInt]).toNot(beEmpty()) expect(NSDictionary() as? [Int:Int]).to(beEmpty()) expect(NSDictionary(object: 1, forKey: 1) as? [Int:Int]).toNot(beEmpty()) expect(Dictionary()).to(beEmpty()) expect(["hi": 1]).toNot(beEmpty()) expect(NSArray() as? [Int]).to(beEmpty()) expect(NSArray(array: [1]) as? [Int]).toNot(beEmpty()) expect(NSSet()).to(beEmpty()) expect(NSSet(array: [1])).toNot(beEmpty()) expect(NSString()).to(beEmpty()) expect(NSString(string: "hello")).toNot(beEmpty()) expect("").to(beEmpty()) expect("foo").toNot(beEmpty()) } func testBeEmptyNegative() { failsWithErrorMessageForNil("expected to be empty, got ") { expect(nil as NSString?).to(beEmpty()) } failsWithErrorMessageForNil("expected to not be empty, got ") { expect(nil as [CInt]?).toNot(beEmpty()) } failsWithErrorMessage("expected to not be empty, got <()>") { expect([]).toNot(beEmpty()) } failsWithErrorMessage("expected to be empty, got <[1]>") { expect([1]).to(beEmpty()) } failsWithErrorMessage("expected to not be empty, got <>") { expect("").toNot(beEmpty()) } failsWithErrorMessage("expected to be empty, got ") { expect("foo").to(beEmpty()) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/BeGreaterThanOrEqualToTest.swift ================================================ import XCTest import Nimble class BeGreaterThanOrEqualToTest: XCTestCase { func testGreaterThanOrEqualTo() { expect(10).to(beGreaterThanOrEqualTo(10)) expect(10).to(beGreaterThanOrEqualTo(2)) expect(1).toNot(beGreaterThanOrEqualTo(2)) expect(NSNumber(int:1)).toNot(beGreaterThanOrEqualTo(2)) expect(NSNumber(int:2)).to(beGreaterThanOrEqualTo(NSNumber(int:2))) expect(1).to(beGreaterThanOrEqualTo(NSNumber(int:0))) failsWithErrorMessage("expected to be greater than or equal to <2>, got <0>") { expect(0).to(beGreaterThanOrEqualTo(2)) return } failsWithErrorMessage("expected to not be greater than or equal to <1>, got <1>") { expect(1).toNot(beGreaterThanOrEqualTo(1)) return } failsWithErrorMessageForNil("expected to be greater than or equal to <-2>, got ") { expect(nil as Int?).to(beGreaterThanOrEqualTo(-2)) } failsWithErrorMessageForNil("expected to not be greater than or equal to <1>, got ") { expect(nil as Int?).toNot(beGreaterThanOrEqualTo(1)) } } func testGreaterThanOrEqualToOperator() { expect(0) >= 0 expect(1) >= 0 expect(NSNumber(int:1)) >= 1 expect(NSNumber(int:1)) >= NSNumber(int:1) failsWithErrorMessage("expected to be greater than or equal to <2>, got <1>") { expect(1) >= 2 return } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/BeGreaterThanTest.swift ================================================ import XCTest import Nimble class BeGreaterThanTest: XCTestCase { func testGreaterThan() { expect(10).to(beGreaterThan(2)) expect(1).toNot(beGreaterThan(2)) expect(NSNumber(int:3)).to(beGreaterThan(2)) expect(NSNumber(int:1)).toNot(beGreaterThan(NSNumber(int:2))) failsWithErrorMessage("expected to be greater than <2>, got <0>") { expect(0).to(beGreaterThan(2)) } failsWithErrorMessage("expected to not be greater than <0>, got <1>") { expect(1).toNot(beGreaterThan(0)) } failsWithErrorMessageForNil("expected to be greater than <-2>, got ") { expect(nil as Int?).to(beGreaterThan(-2)) } failsWithErrorMessageForNil("expected to not be greater than <0>, got ") { expect(nil as Int?).toNot(beGreaterThan(0)) } } func testGreaterThanOperator() { expect(1) > 0 expect(NSNumber(int:1)) > NSNumber(int:0) expect(NSNumber(int:1)) > 0 failsWithErrorMessage("expected to be greater than <2.0000>, got <1.0000>") { expect(1) > 2 return } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/BeIdenticalToObjectTest.swift ================================================ import XCTest import Nimble class BeIdenticalToObjectTest: XCTestCase { private class BeIdenticalToObjectTester {} private let testObjectA = BeIdenticalToObjectTester() private let testObjectB = BeIdenticalToObjectTester() func testBeIdenticalToPositive() { expect(self.testObjectA).to(beIdenticalTo(testObjectA)) } func testBeIdenticalToNegative() { expect(self.testObjectA).toNot(beIdenticalTo(testObjectB)) } func testBeIdenticalToPositiveMessage() { let message = String(format: "expected to be identical to <%p>, got <%p>", unsafeBitCast(testObjectB, Int.self), unsafeBitCast(testObjectA, Int.self)) failsWithErrorMessage(message) { expect(self.testObjectA).to(beIdenticalTo(self.testObjectB)) } } func testBeIdenticalToNegativeMessage() { let message = String(format: "expected to not be identical to <%p>, got <%p>", unsafeBitCast(testObjectA, Int.self), unsafeBitCast(testObjectA, Int.self)) failsWithErrorMessage(message) { expect(self.testObjectA).toNot(beIdenticalTo(self.testObjectA)) } } func testFailsOnNils() { let message1 = String(format: "expected to be identical to <%p>, got nil", unsafeBitCast(testObjectA, Int.self)) failsWithErrorMessageForNil(message1) { expect(nil as BeIdenticalToObjectTester?).to(beIdenticalTo(self.testObjectA)) } let message2 = String(format: "expected to not be identical to <%p>, got nil", unsafeBitCast(testObjectA, Int.self)) failsWithErrorMessageForNil(message2) { expect(nil as BeIdenticalToObjectTester?).toNot(beIdenticalTo(self.testObjectA)) } } func testOperators() { expect(self.testObjectA) === testObjectA expect(self.testObjectA) !== testObjectB } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/BeIdenticalToTest.swift ================================================ import XCTest import Nimble class BeIdenticalToTest: XCTestCase { func testBeIdenticalToPositive() { expect(NSNumber(integer:1)).to(beIdenticalTo(NSNumber(integer:1))) } func testBeIdenticalToNegative() { expect(NSNumber(integer:1)).toNot(beIdenticalTo("yo")) expect([1]).toNot(beIdenticalTo([1])) } func testBeIdenticalToPositiveMessage() { let num1 = NSNumber(integer:1) let num2 = NSNumber(integer:2) let message = NSString(format: "expected to be identical to <%p>, got <%p>", num2, num1) failsWithErrorMessage(message.description) { expect(num1).to(beIdenticalTo(num2)) } } func testBeIdenticalToNegativeMessage() { let value1 = NSArray(array: []) let value2 = NSArray(array: []) let message = NSString(format: "expected to not be identical to <%p>, got <%p>", value2, value1) failsWithErrorMessage(message.description) { expect(value1).toNot(beIdenticalTo(value2)) } } func testOperators() { expect(NSNumber(integer:1)) === NSNumber(integer:1) expect(NSNumber(integer:1)) !== NSNumber(integer:2) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/BeLessThanOrEqualToTest.swift ================================================ import XCTest import Nimble class BeLessThanOrEqualToTest: XCTestCase { func testLessThanOrEqualTo() { expect(10).to(beLessThanOrEqualTo(10)) expect(2).to(beLessThanOrEqualTo(10)) expect(2).toNot(beLessThanOrEqualTo(1)) expect(NSNumber(int:2)).to(beLessThanOrEqualTo(10)) expect(NSNumber(int:2)).toNot(beLessThanOrEqualTo(1)) expect(2).to(beLessThanOrEqualTo(NSNumber(int:10))) expect(2).toNot(beLessThanOrEqualTo(NSNumber(int:1))) failsWithErrorMessage("expected to be less than or equal to <0>, got <2>") { expect(2).to(beLessThanOrEqualTo(0)) return } failsWithErrorMessage("expected to not be less than or equal to <0>, got <0>") { expect(0).toNot(beLessThanOrEqualTo(0)) return } failsWithErrorMessageForNil("expected to be less than or equal to <2>, got ") { expect(nil as Int?).to(beLessThanOrEqualTo(2)) return } failsWithErrorMessageForNil("expected to not be less than or equal to <-2>, got ") { expect(nil as Int?).toNot(beLessThanOrEqualTo(-2)) return } } func testLessThanOrEqualToOperator() { expect(0) <= 1 expect(1) <= 1 failsWithErrorMessage("expected to be less than or equal to <1>, got <2>") { expect(2) <= 1 return } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/BeLessThanTest.swift ================================================ import XCTest import Nimble class BeLessThanTest: XCTestCase { func testLessThan() { expect(2).to(beLessThan(10)) expect(2).toNot(beLessThan(1)) expect(NSNumber(integer:2)).to(beLessThan(10)) expect(NSNumber(integer:2)).toNot(beLessThan(1)) expect(2).to(beLessThan(NSNumber(integer:10))) expect(2).toNot(beLessThan(NSNumber(integer:1))) failsWithErrorMessage("expected to be less than <0>, got <2>") { expect(2).to(beLessThan(0)) } failsWithErrorMessage("expected to not be less than <1>, got <0>") { expect(0).toNot(beLessThan(1)) } failsWithErrorMessageForNil("expected to be less than <2>, got ") { expect(nil as Int?).to(beLessThan(2)) } failsWithErrorMessageForNil("expected to not be less than <-1>, got ") { expect(nil as Int?).toNot(beLessThan(-1)) } } func testLessThanOperator() { expect(0) < 1 expect(NSNumber(int:0)) < 1 failsWithErrorMessage("expected to be less than <1.0000>, got <2.0000>") { expect(2) < 1 return } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/BeLogicalTest.swift ================================================ import XCTest import Nimble enum ConvertsToBool : BooleanType, CustomStringConvertible { case TrueLike, FalseLike var boolValue : Bool { switch self { case .TrueLike: return true case .FalseLike: return false } } var description : String { switch self { case .TrueLike: return "TrueLike" case .FalseLike: return "FalseLike" } } } class BeTruthyTest : XCTestCase { func testShouldMatchNonNilTypes() { expect(true as Bool?).to(beTruthy()) expect(1 as Int?).to(beTruthy()) } func testShouldMatchTrue() { expect(true).to(beTruthy()) failsWithErrorMessage("expected to not be truthy, got ") { expect(true).toNot(beTruthy()) } } func testShouldNotMatchNilTypes() { expect(false as Bool?).toNot(beTruthy()) expect(nil as Bool?).toNot(beTruthy()) expect(nil as Int?).toNot(beTruthy()) } func testShouldNotMatchFalse() { expect(false).toNot(beTruthy()) failsWithErrorMessage("expected to be truthy, got ") { expect(false).to(beTruthy()) } } func testShouldNotMatchNilBools() { expect(nil as Bool?).toNot(beTruthy()) failsWithErrorMessage("expected to be truthy, got ") { expect(nil as Bool?).to(beTruthy()) } } func testShouldMatchBoolConvertibleTypesThatConvertToTrue() { expect(ConvertsToBool.TrueLike).to(beTruthy()) failsWithErrorMessage("expected to not be truthy, got ") { expect(ConvertsToBool.TrueLike).toNot(beTruthy()) } } func testShouldNotMatchBoolConvertibleTypesThatConvertToFalse() { expect(ConvertsToBool.FalseLike).toNot(beTruthy()) failsWithErrorMessage("expected to be truthy, got ") { expect(ConvertsToBool.FalseLike).to(beTruthy()) } } } class BeTrueTest : XCTestCase { func testShouldMatchTrue() { expect(true).to(beTrue()) failsWithErrorMessage("expected to not be true, got ") { expect(true).toNot(beTrue()) } } func testShouldNotMatchFalse() { expect(false).toNot(beTrue()) failsWithErrorMessage("expected to be true, got ") { expect(false).to(beTrue()) } } func testShouldNotMatchNilBools() { failsWithErrorMessageForNil("expected to not be true, got ") { expect(nil as Bool?).toNot(beTrue()) } failsWithErrorMessageForNil("expected to be true, got ") { expect(nil as Bool?).to(beTrue()) } } } class BeFalsyTest : XCTestCase { func testShouldMatchNilTypes() { expect(false as Bool?).to(beFalsy()) expect(nil as Bool?).to(beFalsy()) expect(nil as Int?).to(beFalsy()) } func testShouldNotMatchTrue() { expect(true).toNot(beFalsy()) failsWithErrorMessage("expected to be falsy, got ") { expect(true).to(beFalsy()) } } func testShouldNotMatchNonNilTypes() { expect(true as Bool?).toNot(beFalsy()) expect(1 as Int?).toNot(beFalsy()) } func testShouldMatchFalse() { expect(false).to(beFalsy()) failsWithErrorMessage("expected to not be falsy, got ") { expect(false).toNot(beFalsy()) } } func testShouldMatchNilBools() { expect(nil as Bool?).to(beFalsy()) failsWithErrorMessage("expected to not be falsy, got ") { expect(nil as Bool?).toNot(beFalsy()) } } } class BeFalseTest : XCTestCase { func testShouldNotMatchTrue() { expect(true).toNot(beFalse()) failsWithErrorMessage("expected to be false, got ") { expect(true).to(beFalse()) } } func testShouldMatchFalse() { expect(false).to(beFalse()) failsWithErrorMessage("expected to not be false, got ") { expect(false).toNot(beFalse()) } } func testShouldNotMatchNilBools() { failsWithErrorMessageForNil("expected to be false, got ") { expect(nil as Bool?).to(beFalse()) } failsWithErrorMessageForNil("expected to not be false, got ") { expect(nil as Bool?).toNot(beFalse()) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/BeNilTest.swift ================================================ import XCTest import Nimble class BeNilTest: XCTestCase { func producesNil() -> Array? { return nil } func testBeNil() { expect(nil as Int?).to(beNil()) expect(1 as Int?).toNot(beNil()) expect(self.producesNil()).to(beNil()) failsWithErrorMessage("expected to not be nil, got ") { expect(nil as Int?).toNot(beNil()) } failsWithErrorMessage("expected to be nil, got <1>") { expect(1 as Int?).to(beNil()) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/BeginWithTest.swift ================================================ import XCTest import Nimble class BeginWithTest: XCTestCase { func testPositiveMatches() { expect([1, 2, 3]).to(beginWith(1)) expect([1, 2, 3]).toNot(beginWith(2)) expect("foobar").to(beginWith("foo")) expect("foobar").toNot(beginWith("oo")) expect(NSString(string: "foobar").description).to(beginWith("foo")) expect(NSString(string: "foobar").description).toNot(beginWith("oo")) expect(NSArray(array: ["a", "b"])).to(beginWith("a")) expect(NSArray(array: ["a", "b"])).toNot(beginWith("b")) } func testNegativeMatches() { failsWithErrorMessageForNil("expected to begin with , got ") { expect(nil as NSArray?).to(beginWith("b")) } failsWithErrorMessageForNil("expected to not begin with , got ") { expect(nil as NSArray?).toNot(beginWith("b")) } failsWithErrorMessage("expected to begin with <2>, got <[1, 2, 3]>") { expect([1, 2, 3]).to(beginWith(2)) } failsWithErrorMessage("expected to not begin with <1>, got <[1, 2, 3]>") { expect([1, 2, 3]).toNot(beginWith(1)) } failsWithErrorMessage("expected to begin with , got ") { expect("batman").to(beginWith("atm")) } failsWithErrorMessage("expected to not begin with , got ") { expect("batman").toNot(beginWith("bat")) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/ContainTest.swift ================================================ import XCTest import Nimble class ContainTest: XCTestCase { func testContain() { expect([1, 2, 3]).to(contain(1)) expect([1, 2, 3] as [CInt]).to(contain(1 as CInt)) expect([1, 2, 3] as Array).to(contain(1 as CInt)) expect(["foo", "bar", "baz"]).to(contain("baz")) expect([1, 2, 3]).toNot(contain(4)) expect(["foo", "bar", "baz"]).toNot(contain("ba")) expect(NSArray(array: ["a"])).to(contain("a")) expect(NSArray(array: ["a"])).toNot(contain("b")) expect(NSArray(object: 1) as NSArray?).to(contain(1)) failsWithErrorMessage("expected to contain , got <[\"a\", \"b\", \"c\"]>") { expect(["a", "b", "c"]).to(contain("bar")) } failsWithErrorMessage("expected to not contain , got <[\"a\", \"b\", \"c\"]>") { expect(["a", "b", "c"]).toNot(contain("b")) } failsWithErrorMessageForNil("expected to contain , got ") { expect(nil as [String]?).to(contain("bar")) } failsWithErrorMessageForNil("expected to not contain , got ") { expect(nil as [String]?).toNot(contain("b")) } } func testContainSubstring() { expect("foo").to(contain("o")) expect("foo").to(contain("oo")) expect("foo").toNot(contain("z")) expect("foo").toNot(contain("zz")) failsWithErrorMessage("expected to contain , got ") { expect("foo").to(contain("bar")) } failsWithErrorMessage("expected to not contain , got ") { expect("foo").toNot(contain("oo")) } } func testContainObjCSubstring() { let str = NSString(string: "foo") expect(str).to(contain(NSString(string: "o"))) expect(str).to(contain(NSString(string: "oo"))) expect(str).toNot(contain(NSString(string: "z"))) expect(str).toNot(contain(NSString(string: "zz"))) } func testVariadicArguments() { expect([1, 2, 3]).to(contain(1, 2)) expect([1, 2, 3]).toNot(contain(1, 4)) failsWithErrorMessage("expected to contain , got <[\"a\", \"b\", \"c\"]>") { expect(["a", "b", "c"]).to(contain("a", "bar")) } failsWithErrorMessage("expected to not contain , got <[\"a\", \"b\", \"c\"]>") { expect(["a", "b", "c"]).toNot(contain("bar", "b")) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/EndWithTest.swift ================================================ import XCTest import Nimble class EndWithTest: XCTestCase { func testEndWithPositives() { expect([1, 2, 3]).to(endWith(3)) expect([1, 2, 3]).toNot(endWith(2)) expect("foobar").to(endWith("bar")) expect("foobar").toNot(endWith("oo")) expect(NSString(string: "foobar").description).to(endWith("bar")) expect(NSString(string: "foobar").description).toNot(endWith("oo")) expect(NSArray(array: ["a", "b"])).to(endWith("b")) expect(NSArray(array: ["a", "b"])).toNot(endWith("a")) } func testEndWithNegatives() { failsWithErrorMessageForNil("expected to end with <2>, got ") { expect(nil as [Int]?).to(endWith(2)) } failsWithErrorMessageForNil("expected to not end with <2>, got ") { expect(nil as [Int]?).toNot(endWith(2)) } failsWithErrorMessage("expected to end with <2>, got <[1, 2, 3]>") { expect([1, 2, 3]).to(endWith(2)) } failsWithErrorMessage("expected to not end with <3>, got <[1, 2, 3]>") { expect([1, 2, 3]).toNot(endWith(3)) } failsWithErrorMessage("expected to end with , got ") { expect("batman").to(endWith("atm")) } failsWithErrorMessage("expected to not end with , got ") { expect("batman").toNot(endWith("man")) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/EqualTest.swift ================================================ import XCTest import Nimble class EqualTest: XCTestCase { func testEquality() { expect(1 as CInt).to(equal(1 as CInt)) expect(1 as CInt).to(equal(1)) expect(1).to(equal(1)) expect("hello").to(equal("hello")) expect("hello").toNot(equal("world")) expect { 1 }.to(equal(1)) failsWithErrorMessage("expected to equal , got ") { expect("hello").to(equal("world")) } failsWithErrorMessage("expected to not equal , got ") { expect("hello").toNot(equal("hello")) } } func testArrayEquality() { expect([1, 2, 3]).to(equal([1, 2, 3])) expect([1, 2, 3]).toNot(equal([1, 2])) expect([1, 2, 3]).toNot(equal([1, 2, 4])) let array1: Array = [1, 2, 3] let array2: Array = [1, 2, 3] expect(array1).to(equal(array2)) expect(array1).to(equal([1, 2, 3])) expect(array1).toNot(equal([1, 2] as Array)) expect(NSArray(array: [1, 2, 3])).to(equal(NSArray(array: [1, 2, 3]))) failsWithErrorMessage("expected to equal <[1, 2]>, got <[1, 2, 3]>") { expect([1, 2, 3]).to(equal([1, 2])) } } func testSetEquality() { expect(Set([1, 2])).to(equal(Set([1, 2]))) expect(Set()).to(equal(Set())) expect(Set()) == Set() expect(Set([1, 2])) != Set() failsWithErrorMessageForNil("expected to equal <[1, 2]>, got ") { expect(nil as Set?).to(equal(Set([1, 2]))) } failsWithErrorMessage("expected to equal <[1, 2, 3]>, got <[2, 3]>, missing <[1]>") { expect(Set([2, 3])).to(equal(Set([1, 2, 3]))) } failsWithErrorMessage("expected to equal <[1, 2, 3]>, got <[1, 2, 3, 4]>, extra <[4]>") { expect(Set([1, 2, 3, 4])).to(equal(Set([1, 2, 3]))) } failsWithErrorMessage("expected to equal <[1, 2, 3]>, got <[2, 3, 4]>, missing <[1]>, extra <[4]>") { expect(Set([2, 3, 4])).to(equal(Set([1, 2, 3]))) } failsWithErrorMessage("expected to equal <[1, 2, 3]>, got <[2, 3, 4]>, missing <[1]>, extra <[4]>") { expect(Set([2, 3, 4])) == Set([1, 2, 3]) } failsWithErrorMessage("expected to not equal <[1, 2, 3]>, got <[1, 2, 3]>") { expect(Set([1, 2, 3])) != Set([1, 2, 3]) } } func testDoesNotMatchNils() { failsWithErrorMessageForNil("expected to equal , got ") { expect(nil as String?).to(equal(nil as String?)) } failsWithErrorMessageForNil("expected to not equal , got ") { expect("foo").toNot(equal(nil as String?)) } failsWithErrorMessageForNil("expected to not equal , got ") { expect(nil as String?).toNot(equal("bar")) } failsWithErrorMessageForNil("expected to equal , got ") { expect(nil as [Int]?).to(equal(nil as [Int]?)) } failsWithErrorMessageForNil("expected to not equal <[1]>, got ") { expect(nil as [Int]?).toNot(equal([1])) } failsWithErrorMessageForNil("expected to not equal , got <[1]>") { expect([1]).toNot(equal(nil as [Int]?)) } failsWithErrorMessageForNil("expected to equal , got ") { expect(nil as [Int: Int]?).to(equal(nil as [Int: Int]?)) } failsWithErrorMessageForNil("expected to not equal <[1: 1]>, got ") { expect(nil as [Int: Int]?).toNot(equal([1: 1])) } failsWithErrorMessageForNil("expected to not equal , got <[1: 1]>") { expect([1: 1]).toNot(equal(nil as [Int: Int]?)) } } func testDictionaryEquality() { expect(["foo": "bar"]).to(equal(["foo": "bar"])) expect(["foo": "bar"]).toNot(equal(["foo": "baz"])) let actual = ["foo": "bar"] let expected = ["foo": "bar"] let unexpected = ["foo": "baz"] expect(actual).to(equal(expected)) expect(actual).toNot(equal(unexpected)) expect(NSDictionary(object: "bar", forKey: "foo")).to(equal(["foo": "bar"])) expect(NSDictionary(object: "bar", forKey: "foo")).to(equal(expected)) } func testNSObjectEquality() { expect(NSNumber(integer:1)).to(equal(NSNumber(integer:1))) expect(NSNumber(integer:1)) == NSNumber(integer:1) expect(NSNumber(integer:1)) != NSNumber(integer:2) expect { NSNumber(integer:1) }.to(equal(1)) } func testOperatorEquality() { expect("foo") == "foo" expect("foo") != "bar" failsWithErrorMessage("expected to equal , got ") { expect("hello") == "world" return } failsWithErrorMessage("expected to not equal , got ") { expect("hello") != "hello" return } } func testOperatorEqualityWithArrays() { let array1: Array = [1, 2, 3] let array2: Array = [1, 2, 3] let array3: Array = [1, 2] expect(array1) == array2 expect(array1) != array3 } func testOperatorEqualityWithDictionaries() { let dict1 = ["foo": "bar"] let dict2 = ["foo": "bar"] let dict3 = ["foo": "baz"] expect(dict1) == dict2 expect(dict1) != dict3 } func testOptionalEquality() { expect(1 as CInt?).to(equal(1)) expect(1 as CInt?).to(equal(1 as CInt?)) expect(1).toNot(equal(nil)) } func testDictionariesWithDifferentSequences() { // see: https://github.com/Quick/Nimble/issues/61 // these dictionaries generate different orderings of sequences. let result = ["how":1, "think":1, "didnt":2, "because":1, "interesting":1, "always":1, "right":1, "such":1, "to":3, "say":1, "cool":1, "you":1, "weather":3, "be":1, "went":1, "was":2, "sometimes":1, "and":3, "mind":1, "rain":1, "whole":1, "everything":1, "weather.":1, "down":1, "kind":1, "mood.":1, "it":2, "everyday":1, "might":1, "more":1, "have":2, "person":1, "could":1, "tenth":2, "night":1, "write":1, "Youd":1, "affects":1, "of":3, "Who":1, "us":1, "an":1, "I":4, "my":1, "much":2, "wrong.":1, "peacefully.":1, "amazing":3, "would":4, "just":1, "grade.":1, "Its":2, "The":2, "had":1, "that":1, "the":5, "best":1, "but":1, "essay":1, "for":1, "summer":2, "your":1, "grade":1, "vary":1, "pretty":1, "at":1, "rain.":1, "about":1, "allow":1, "thought":1, "in":1, "sleep":1, "a":1, "hot":1, "really":1, "beach":1, "life.":1, "we":1, "although":1] let storyCount = ["The":2, "summer":2, "of":3, "tenth":2, "grade":1, "was":2, "the":5, "best":1, "my":1, "life.":1, "I":4, "went":1, "to":3, "beach":1, "everyday":1, "and":3, "we":1, "had":1, "amazing":3, "weather.":1, "weather":3, "didnt":2, "really":1, "vary":1, "much":2, "always":1, "pretty":1, "hot":1, "although":1, "sometimes":1, "at":1, "night":1, "it":2, "would":4, "rain.":1, "mind":1, "rain":1, "because":1, "cool":1, "everything":1, "down":1, "allow":1, "us":1, "sleep":1, "peacefully.":1, "Its":2, "how":1, "affects":1, "your":1, "mood.":1, "Who":1, "have":2, "thought":1, "that":1, "could":1, "write":1, "a":1, "whole":1, "essay":1, "just":1, "about":1, "in":1, "grade.":1, "kind":1, "right":1, "Youd":1, "think":1, "for":1, "such":1, "an":1, "interesting":1, "person":1, "might":1, "more":1, "say":1, "but":1, "you":1, "be":1, "wrong.":1] expect(result).to(equal(storyCount)) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/HaveCountTest.swift ================================================ import XCTest import Nimble class HaveCountTest: XCTestCase { func testHaveCountForArray() { expect([1, 2, 3]).to(haveCount(3)) expect([1, 2, 3]).notTo(haveCount(1)) failsWithErrorMessage("expected to have [1, 2, 3] with count 1, got 3") { expect([1, 2, 3]).to(haveCount(1)) } failsWithErrorMessage("expected to not have [1, 2, 3] with count 3, got 3") { expect([1, 2, 3]).notTo(haveCount(3)) } } func testHaveCountForDictionary() { expect(["1":1, "2":2, "3":3]).to(haveCount(3)) expect(["1":1, "2":2, "3":3]).notTo(haveCount(1)) failsWithErrorMessage("expected to have [\"2\": 2, \"1\": 1, \"3\": 3] with count 1, got 3") { expect(["1":1, "2":2, "3":3]).to(haveCount(1)) } failsWithErrorMessage("expected to not have [\"2\": 2, \"1\": 1, \"3\": 3] with count 3, got 3") { expect(["1":1, "2":2, "3":3]).notTo(haveCount(3)) } } func testHaveCountForSet() { expect(Set([1, 2, 3])).to(haveCount(3)) expect(Set([1, 2, 3])).notTo(haveCount(1)) failsWithErrorMessage("expected to have [2, 3, 1] with count 1, got 3") { expect(Set([1, 2, 3])).to(haveCount(1)) } failsWithErrorMessage("expected to not have [2, 3, 1] with count 3, got 3") { expect(Set([1, 2, 3])).notTo(haveCount(3)) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/MatchTest.swift ================================================ import XCTest import Nimble class MatchTest:XCTestCase { func testMatchPositive() { expect("11:14").to(match("\\d{2}:\\d{2}")) } func testMatchNegative() { expect("hello").toNot(match("\\d{2}:\\d{2}")) } func testMatchPositiveMessage() { let message = "expected to match <\\d{2}:\\d{2}>, got " failsWithErrorMessage(message) { expect("hello").to(match("\\d{2}:\\d{2}")) } } func testMatchNegativeMessage() { let message = "expected to not match <\\d{2}:\\d{2}>, got <11:14>" failsWithErrorMessage(message) { expect("11:14").toNot(match("\\d{2}:\\d{2}")) } } func testMatchNils() { failsWithErrorMessageForNil("expected to match <\\d{2}:\\d{2}>, got ") { expect(nil as String?).to(match("\\d{2}:\\d{2}")) } failsWithErrorMessageForNil("expected to not match <\\d{2}:\\d{2}>, got ") { expect(nil as String?).toNot(match("\\d{2}:\\d{2}")) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/RaisesExceptionTest.swift ================================================ import XCTest import Nimble class RaisesExceptionTest: XCTestCase { var anException = NSException(name: "laugh", reason: "Lulz", userInfo: ["key": "value"]) func testPositiveMatches() { expect { self.anException.raise() }.to(raiseException()) expect { self.anException.raise() }.to(raiseException(named: "laugh")) expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz")) expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz", userInfo: ["key": "value"])) } func testPositiveMatchesWithClosures() { expect { self.anException.raise() }.to(raiseException { (exception: NSException) in expect(exception.name).to(equal("laugh")) }) expect { self.anException.raise() }.to(raiseException(named: "laugh") { (exception: NSException) in expect(exception.name).to(beginWith("lau")) }) expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz") { (exception: NSException) in expect(exception.name).to(beginWith("lau")) }) expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz", userInfo: ["key": "value"]) { (exception: NSException) in expect(exception.name).to(beginWith("lau")) }) expect { self.anException.raise() }.to(raiseException(named: "laugh") { (exception: NSException) in expect(exception.name).toNot(beginWith("as")) }) expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz") { (exception: NSException) in expect(exception.name).toNot(beginWith("df")) }) expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz", userInfo: ["key": "value"]) { (exception: NSException) in expect(exception.name).toNot(beginWith("as")) }) } func testNegativeMatches() { failsWithErrorMessage("expected to raise exception with name , got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.to(raiseException(named: "foo")) } failsWithErrorMessage("expected to raise exception with name with reason , got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "bar")) } failsWithErrorMessage( "expected to raise exception with name with reason with userInfo <{k = v;}>, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz", userInfo: ["k": "v"])) } failsWithErrorMessage("expected to raise any exception, got no exception") { expect { self.anException }.to(raiseException()) } failsWithErrorMessage("expected to not raise any exception, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.toNot(raiseException()) } failsWithErrorMessage("expected to raise exception with name with reason , got no exception") { expect { self.anException }.to(raiseException(named: "laugh", reason: "Lulz")) } failsWithErrorMessage("expected to raise exception with name with reason , got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.to(raiseException(named: "bar", reason: "Lulz")) } failsWithErrorMessage("expected to not raise exception with name , got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.toNot(raiseException(named: "laugh")) } failsWithErrorMessage("expected to not raise exception with name with reason , got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.toNot(raiseException(named: "laugh", reason: "Lulz")) } failsWithErrorMessage("expected to not raise exception with name with reason with userInfo <{key = value;}>, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.toNot(raiseException(named: "laugh", reason: "Lulz", userInfo: ["key": "value"])) } } func testNegativeMatchesDoNotCallClosureWithoutException() { failsWithErrorMessage("expected to raise exception that satisfies block, got no exception") { expect { self.anException }.to(raiseException { (exception: NSException) in expect(exception.name).to(equal("foo")) }) } failsWithErrorMessage("expected to raise exception with name that satisfies block, got no exception") { expect { self.anException }.to(raiseException(named: "foo") { (exception: NSException) in expect(exception.name).to(equal("foo")) }) } failsWithErrorMessage("expected to raise exception with name with reason that satisfies block, got no exception") { expect { self.anException }.to(raiseException(named: "foo", reason: "ha") { (exception: NSException) in expect(exception.name).to(equal("foo")) }) } failsWithErrorMessage("expected to raise exception with name with reason with userInfo <{}> that satisfies block, got no exception") { expect { self.anException }.to(raiseException(named: "foo", reason: "Lulz", userInfo: [:]) { (exception: NSException) in expect(exception.name).to(equal("foo")) }) } failsWithErrorMessage("expected to not raise any exception, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.toNot(raiseException()) } } func testNegativeMatchesWithClosure() { failsWithErrorMessage("expected to raise exception that satisfies block, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }") { expect { self.anException.raise() }.to(raiseException { (exception: NSException) in expect(exception.name).to(equal("foo")) }) } let innerFailureMessage = "expected to begin with , got " failsWithErrorMessage([innerFailureMessage, "expected to raise exception with name that satisfies block, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }"]) { expect { self.anException.raise() }.to(raiseException(named: "laugh") { (exception: NSException) in expect(exception.name).to(beginWith("fo")) }) } failsWithErrorMessage([innerFailureMessage, "expected to raise exception with name that satisfies block, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }"]) { expect { self.anException.raise() }.to(raiseException(named: "lol") { (exception: NSException) in expect(exception.name).to(beginWith("fo")) }) } failsWithErrorMessage([innerFailureMessage, "expected to raise exception with name with reason that satisfies block, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }"]) { expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz") { (exception: NSException) in expect(exception.name).to(beginWith("fo")) }) } failsWithErrorMessage([innerFailureMessage, "expected to raise exception with name with reason that satisfies block, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }"]) { expect { self.anException.raise() }.to(raiseException(named: "lol", reason: "wrong") { (exception: NSException) in expect(exception.name).to(beginWith("fo")) }) } failsWithErrorMessage([innerFailureMessage, "expected to raise exception with name with reason with userInfo <{key = value;}> that satisfies block, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }"]) { expect { self.anException.raise() }.to(raiseException(named: "laugh", reason: "Lulz", userInfo: ["key": "value"]) { (exception: NSException) in expect(exception.name).to(beginWith("fo")) }) } failsWithErrorMessage([innerFailureMessage, "expected to raise exception with name with reason with userInfo <{}> that satisfies block, got NSException { name=laugh, reason='Lulz', userInfo=[key: value] }"]) { expect { self.anException.raise() }.to(raiseException(named: "lol", reason: "Lulz", userInfo: [:]) { (exception: NSException) in expect(exception.name).to(beginWith("fo")) }) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/Matchers/ThrowErrorTest.swift ================================================ import XCTest import Nimble enum Error : ErrorType { case Laugh case Cry } enum EquatableError : ErrorType { case Parameterized(x: Int) } extension EquatableError : Equatable { } func ==(lhs: EquatableError, rhs: EquatableError) -> Bool { switch (lhs, rhs) { case (.Parameterized(let l), .Parameterized(let r)): return l == r } } enum CustomDebugStringConvertibleError : ErrorType { case A case B } extension CustomDebugStringConvertibleError : CustomDebugStringConvertible { var debugDescription : String { return "code=\(_code)" } } class ThrowErrorTest: XCTestCase { func testPositiveMatches() { expect { throw Error.Laugh }.to(throwError()) expect { throw Error.Laugh }.to(throwError(Error.Laugh)) expect { throw Error.Laugh }.to(throwError(errorType: Error.self)) expect { throw EquatableError.Parameterized(x: 1) }.to(throwError(EquatableError.Parameterized(x: 1))) } func testPositiveMatchesWithClosures() { // Generic typed closure expect { throw EquatableError.Parameterized(x: 42) }.to(throwError { error in guard case EquatableError.Parameterized(let x) = error else { fail(); return } expect(x) >= 1 }) // Explicit typed closure expect { throw EquatableError.Parameterized(x: 42) }.to(throwError { (error: EquatableError) in guard case .Parameterized(let x) = error else { fail(); return } expect(x) >= 1 }) // Typed closure over errorType argument expect { throw EquatableError.Parameterized(x: 42) }.to(throwError(errorType: EquatableError.self) { error in guard case .Parameterized(let x) = error else { fail(); return } expect(x) >= 1 }) // Typed closure over error argument expect { throw Error.Laugh }.to(throwError(Error.Laugh) { (error: Error) in expect(error._domain).to(beginWith("Nim")) }) // Typed closure over error argument expect { throw Error.Laugh }.to(throwError(Error.Laugh) { (error: Error) in expect(error._domain).toNot(beginWith("as")) }) } func testNegativeMatches() { // Same case, different arguments failsWithErrorMessage("expected to throw error , got ") { expect { throw EquatableError.Parameterized(x: 1) }.to(throwError(EquatableError.Parameterized(x: 2))) } // Same case, different arguments failsWithErrorMessage("expected to throw error , got ") { expect { throw EquatableError.Parameterized(x: 1) }.to(throwError(EquatableError.Parameterized(x: 2))) } // Different case failsWithErrorMessage("expected to throw error , got ") { expect { throw Error.Laugh }.to(throwError(Error.Cry)) } // Different case with closure failsWithErrorMessage("expected to throw error that satisfies block, got ") { expect { throw Error.Laugh }.to(throwError(Error.Cry) { _ in return }) } // Different case, implementing CustomDebugStringConvertible failsWithErrorMessage("expected to throw error , got ") { expect { throw CustomDebugStringConvertibleError.A }.to(throwError(CustomDebugStringConvertibleError.B)) } } func testPositiveNegatedMatches() { // No error at all expect { return }.toNot(throwError()) // Different case expect { throw Error.Laugh }.toNot(throwError(Error.Cry)) } func testNegativeNegatedMatches() { // No error at all failsWithErrorMessage("expected to not throw any error, got ") { expect { throw Error.Laugh }.toNot(throwError()) } // Different error failsWithErrorMessage("expected to not throw error , got ") { expect { throw Error.Laugh }.toNot(throwError(Error.Laugh)) } } func testNegativeMatchesDoNotCallClosureWithoutError() { failsWithErrorMessage("expected to throw error that satisfies block, got no error") { expect { return }.to(throwError { error in fail() }) } failsWithErrorMessage("expected to throw error that satisfies block, got no error") { expect { return }.to(throwError(Error.Laugh) { error in fail() }) } } func testNegativeMatchesWithClosure() { let innerFailureMessage = "expected to equal , got " let closure = { (error: Error) in expect(error._domain).to(equal("foo")) } failsWithErrorMessage([innerFailureMessage, "expected to throw error from type that satisfies block, got "]) { expect { throw Error.Laugh }.to(throwError(closure: closure)) } failsWithErrorMessage([innerFailureMessage, "expected to throw error that satisfies block, got "]) { expect { throw Error.Laugh }.to(throwError(Error.Laugh, closure: closure)) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/SynchronousTests.swift ================================================ import XCTest import Nimble class SynchronousTest: XCTestCase { let errorToThrow = NSError(domain: NSInternalInconsistencyException, code: 42, userInfo: nil) private func doThrowError() throws -> Int { throw errorToThrow } func testFailAlwaysFails() { failsWithErrorMessage("My error message") { fail("My error message") } failsWithErrorMessage("fail() always fails") { fail() } } func testUnexpectedErrorsThrownFails() { failsWithErrorMessage("expected to equal <1>, got an unexpected error thrown: <\(errorToThrow)>") { expect { try self.doThrowError() }.to(equal(1)) } failsWithErrorMessage("expected to not equal <1>, got an unexpected error thrown: <\(errorToThrow)>") { expect { try self.doThrowError() }.toNot(equal(1)) } } func testToMatchesIfMatcherReturnsTrue() { expect(1).to(MatcherFunc { expr, failure in true }) expect{1}.to(MatcherFunc { expr, failure in true }) } func testToProvidesActualValueExpression() { var value: Int? expect(1).to(MatcherFunc { expr, failure in value = try expr.evaluate(); return true }) expect(value).to(equal(1)) } func testToProvidesAMemoizedActualValueExpression() { var callCount = 0 expect{ callCount++ }.to(MatcherFunc { expr, failure in try expr.evaluate() try expr.evaluate() return true }) expect(callCount).to(equal(1)) } func testToProvidesAMemoizedActualValueExpressionIsEvaluatedAtMatcherControl() { var callCount = 0 expect{ callCount++ }.to(MatcherFunc { expr, failure in expect(callCount).to(equal(0)) try expr.evaluate() return true }) expect(callCount).to(equal(1)) } func testToMatchAgainstLazyProperties() { expect(ObjectWithLazyProperty().value).to(equal("hello")) expect(ObjectWithLazyProperty().value).toNot(equal("world")) expect(ObjectWithLazyProperty().anotherValue).to(equal("world")) expect(ObjectWithLazyProperty().anotherValue).toNot(equal("hello")) } // repeated tests from to() for toNot() func testToNotMatchesIfMatcherReturnsTrue() { expect(1).toNot(MatcherFunc { expr, failure in false }) expect{1}.toNot(MatcherFunc { expr, failure in false }) } func testToNotProvidesActualValueExpression() { var value: Int? expect(1).toNot(MatcherFunc { expr, failure in value = try expr.evaluate(); return false }) expect(value).to(equal(1)) } func testToNotProvidesAMemoizedActualValueExpression() { var callCount = 0 expect{ callCount++ }.toNot(MatcherFunc { expr, failure in try expr.evaluate() try expr.evaluate() return false }) expect(callCount).to(equal(1)) } func testToNotProvidesAMemoizedActualValueExpressionIsEvaluatedAtMatcherControl() { var callCount = 0 expect{ callCount++ }.toNot(MatcherFunc { expr, failure in expect(callCount).to(equal(0)) try expr.evaluate() return false }) expect(callCount).to(equal(1)) } func testToNotNegativeMatches() { failsWithErrorMessage("expected to not match, got <1>") { expect(1).toNot(MatcherFunc { expr, failure in true }) } } func testNotToMatchesLikeToNot() { expect(1).notTo(MatcherFunc { expr, failure in false }) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/UserDescriptionTest.swift ================================================ import XCTest import Nimble class UserDescriptionTest: XCTestCase { func testToMatcher_CustomFailureMessage() { failsWithErrorMessage( "These aren't equal!\n" + "expected to match, got <1>") { expect(1).to(MatcherFunc { expr, failure in false }, description: "These aren't equal!") } } func testNotToMatcher_CustomFailureMessage() { failsWithErrorMessage( "These aren't equal!\n" + "expected to not match, got <1>") { expect(1).notTo(MatcherFunc { expr, failure in true }, description: "These aren't equal!") } } func testToNotMatcher_CustomFailureMessage() { failsWithErrorMessage( "These aren't equal!\n" + "expected to not match, got <1>") { expect(1).toNot(MatcherFunc { expr, failure in true }, description: "These aren't equal!") } } func testToEventuallyMatch_CustomFailureMessage() { failsWithErrorMessage( "These aren't eventually equal!\n" + "expected to eventually equal <1>, got <0>") { expect { 0 }.toEventually(equal(1), description: "These aren't eventually equal!") } } func testToEventuallyNotMatch_CustomFailureMessage() { failsWithErrorMessage( "These are eventually equal!\n" + "expected to eventually not equal <1>, got <1>") { expect { 1 }.toEventuallyNot(equal(1), description: "These are eventually equal!") } } func testToNotEventuallyMatch_CustomFailureMessage() { failsWithErrorMessage( "These are eventually equal!\n" + "expected to eventually not equal <1>, got <1>") { expect { 1 }.toEventuallyNot(equal(1), description: "These are eventually equal!") } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/Nimble-OSXTests-Bridging-Header.h ================================================ // // Use this file to import your target's public headers that you would like to expose to Swift. // ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/NimbleSpecHelper.h ================================================ @import Nimble; #import "NimbleTests-Swift.h" // Use this when you want to verify the failure message for when an expectation fails #define expectFailureMessage(MSG, BLOCK) \ [NimbleHelper expectFailureMessage:(MSG) block:(BLOCK) file:@(__FILE__) line:__LINE__]; #define expectFailureMessages(MSGS, BLOCK) \ [NimbleHelper expectFailureMessages:(MSGS) block:(BLOCK) file:@(__FILE__) line:__LINE__]; // Use this when you want to verify the failure message with the nil message postfixed // to it: " (use beNil() to match nils)" #define expectNilFailureMessage(MSG, BLOCK) \ [NimbleHelper expectFailureMessageForNil:(MSG) block:(BLOCK) file:@(__FILE__) line:__LINE__]; ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/NimbleTests-Bridging-Header.h ================================================ // // Use this file to import your target's public headers that you would like to expose to Swift. // ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCAllPassTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCAllPassTest : XCTestCase @end @implementation ObjCAllPassTest - (void)testPositiveMatches { expect(@[@1, @2, @3,@4]).to(allPass(beLessThan(@5))); expect(@[@1, @2, @3,@4]).toNot(allPass(beGreaterThan(@5))); expect([NSSet setWithArray:@[@1, @2, @3,@4]]).to(allPass(beLessThan(@5))); expect([NSSet setWithArray:@[@1, @2, @3,@4]]).toNot(allPass(beGreaterThan(@5))); } - (void)testNegativeMatches { expectFailureMessage(@"expected to all be less than <3.0000>, but failed first at element" " <3.0000> in <[1.0000, 2.0000, 3.0000, 4.0000]>", ^{ expect(@[@1, @2, @3,@4]).to(allPass(beLessThan(@3))); }); expectFailureMessage(@"expected to not all be less than <5.0000>", ^{ expect(@[@1, @2, @3,@4]).toNot(allPass(beLessThan(@5))); }); expectFailureMessage(@"expected to not all be less than <5.0000>", ^{ expect([NSSet setWithArray:@[@1, @2, @3,@4]]).toNot(allPass(beLessThan(@5))); }); expectFailureMessage(@"allPass only works with NSFastEnumeration" " (NSArray, NSSet, ...) of NSObjects, got <3.0000>", ^{ expect(@3).to(allPass(beLessThan(@5))); }); expectFailureMessage(@"allPass only works with NSFastEnumeration" " (NSArray, NSSet, ...) of NSObjects, got <3.0000>", ^{ expect(@3).toNot(allPass(beLessThan(@5))); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCAsyncTest.m ================================================ #import #import #import "NimbleSpecHelper.h" @interface ObjCAsyncTest : XCTestCase @end @implementation ObjCAsyncTest - (void)testAsync { __block id obj = @1; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ obj = nil; }); expect(obj).toEventually(beNil()); } - (void)testAsyncWithCustomTimeout { __block id obj = nil; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ obj = @1; }); expect(obj).withTimeout(5).toEventuallyNot(beNil()); } - (void)testAsyncCallback { waitUntil(^(void (^done)(void)){ done(); }); expectFailureMessage(@"Waited more than 1.0 second", ^{ waitUntil(^(void (^done)(void)){ /* ... */ }); }); expectFailureMessage(@"Waited more than 0.01 seconds", ^{ waitUntilTimeout(0.01, ^(void (^done)(void)){ [NSThread sleepForTimeInterval:0.1]; done(); }); }); expectFailureMessage(@"expected to equal , got ", ^{ waitUntil(^(void (^done)(void)){ [NSThread sleepForTimeInterval:0.1]; expect(@"hello").to(equal(@"goodbye")); done(); }); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCBeAnInstanceOfTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeAnInstanceOfTest : XCTestCase @end @implementation ObjCBeAnInstanceOfTest - (void)testPositiveMatches { NSNull *obj = [NSNull null]; expect(obj).to(beAnInstanceOf([NSNull class])); expect(@1).toNot(beAnInstanceOf([NSNull class])); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be an instance of NSNull, got <__NSCFNumber instance>", ^{ expect(@1).to(beAnInstanceOf([NSNull class])); }); expectFailureMessage(@"expected to not be an instance of NSNull, got ", ^{ expect([NSNull null]).toNot(beAnInstanceOf([NSNull class])); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to be an instance of NSNull, got ", ^{ expect(nil).to(beAnInstanceOf([NSNull class])); }); expectNilFailureMessage(@"expected to not be an instance of NSNull, got ", ^{ expect(nil).toNot(beAnInstanceOf([NSNull class])); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCBeCloseToTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeCloseToTest : XCTestCase @end @implementation ObjCBeCloseToTest - (void)testPositiveMatches { expect(@1.2).to(beCloseTo(@1.2001)); expect(@1.2).to(beCloseTo(@2).within(10)); expect(@2).toNot(beCloseTo(@1)); expect(@1.00001).toNot(beCloseTo(@1).within(0.00000001)); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be close to <0.0000> (within 0.0010), got <1.0000>", ^{ expect(@1).to(beCloseTo(@0)); }); expectFailureMessage(@"expected to not be close to <0.0000> (within 0.0010), got <0.0001>", ^{ expect(@(0.0001)).toNot(beCloseTo(@0)); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to be close to <0.0000> (within 0.0010), got ", ^{ expect(nil).to(beCloseTo(@0)); }); expectNilFailureMessage(@"expected to not be close to <0.0000> (within 0.0010), got ", ^{ expect(nil).toNot(beCloseTo(@0)); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCBeEmptyTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeEmptyTest : XCTestCase @end @implementation ObjCBeEmptyTest - (void)testPositiveMatches { expect(@[]).to(beEmpty()); expect(@"").to(beEmpty()); expect(@{}).to(beEmpty()); expect([NSSet set]).to(beEmpty()); expect([NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory]).to(beEmpty()); expect(@[@1, @2]).toNot(beEmpty()); expect(@"a").toNot(beEmpty()); expect(@{@"key": @"value"}).toNot(beEmpty()); expect([NSSet setWithObject:@1]).toNot(beEmpty()); NSHashTable *table = [NSHashTable hashTableWithOptions:NSPointerFunctionsStrongMemory]; [table addObject:@1]; expect(table).toNot(beEmpty()); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be empty, got ", ^{ expect(@"foo").to(beEmpty()); }); expectFailureMessage(@"expected to be empty, got <(1)>", ^{ expect(@[@1]).to(beEmpty()); }); expectFailureMessage(@"expected to be empty, got <{key = value;}>", ^{ expect(@{@"key": @"value"}).to(beEmpty()); }); expectFailureMessage(@"expected to be empty, got <{(1)}>", ^{ expect([NSSet setWithObject:@1]).to(beEmpty()); }); NSHashTable *table = [NSHashTable hashTableWithOptions:NSPointerFunctionsStrongMemory]; [table addObject:@1]; NSString *tableString = [[table description] stringByReplacingOccurrencesOfString:@"\n" withString:@""]; expectFailureMessage(([NSString stringWithFormat:@"expected to be empty, got <%@>", tableString]), ^{ expect(table).to(beEmpty()); }); expectFailureMessage(@"expected to not be empty, got <>", ^{ expect(@"").toNot(beEmpty()); }); expectFailureMessage(@"expected to not be empty, got <()>", ^{ expect(@[]).toNot(beEmpty()); }); expectFailureMessage(@"expected to not be empty, got <{}>", ^{ expect(@{}).toNot(beEmpty()); }); expectFailureMessage(@"expected to not be empty, got <{(1)}>", ^{ expect([NSSet setWithObject:@1]).toNot(beEmpty()); }); expectFailureMessage(@"expected to not be empty, got ", ^{ expect([NSHashTable hashTableWithOptions:NSPointerFunctionsStrongMemory]).toNot(beEmpty()); }); } - (void)testItDoesNotMatchNil { expectNilFailureMessage(@"expected to be empty, got ", ^{ expect(nil).to(beEmpty()); }); expectNilFailureMessage(@"expected to not be empty, got ", ^{ expect(nil).toNot(beEmpty()); }); } - (void)testItReportsTypesItMatchesAgainst { expectFailureMessage(@"expected to be empty (only works for NSArrays, NSSets, NSDictionaries, NSHashTables, and NSStrings), got __NSCFNumber type", ^{ expect(@1).to(beEmpty()); }); expectFailureMessage(@"expected to not be empty (only works for NSArrays, NSSets, NSDictionaries, NSHashTables, and NSStrings), got __NSCFNumber type", ^{ expect(@1).toNot(beEmpty()); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCBeFalseTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeFalseTest : XCTestCase @end @implementation ObjCBeFalseTest - (void)testPositiveMatches { expect(@NO).to(beFalse()); expect(@YES).toNot(beFalse()); } - (void)testNegativeMatches { expectNilFailureMessage(@"expected to be false, got ", ^{ expect(nil).to(beFalse()); }); expectNilFailureMessage(@"expected to not be false, got ", ^{ expect(nil).toNot(beFalse()); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCBeFalsyTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeFalsyTest : XCTestCase @end @implementation ObjCBeFalsyTest - (void)testPositiveMatches { expect(@NO).to(beFalsy()); expect(@YES).toNot(beFalsy()); expect(nil).to(beFalsy()); } - (void)testNegativeMatches { expectFailureMessage(@"expected to not be falsy, got ", ^{ expect(nil).toNot(beFalsy()); }); expectFailureMessage(@"expected to be falsy, got <1.0000>", ^{ expect(@1).to(beFalsy()); }); expectFailureMessage(@"expected to be truthy, got <0.0000>", ^{ expect(@NO).to(beTruthy()); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCBeGreaterThanOrEqualToTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeGreaterThanOrEqualToTest : XCTestCase @end @implementation ObjCBeGreaterThanOrEqualToTest - (void)testPositiveMatches { expect(@2).to(beGreaterThanOrEqualTo(@2)); expect(@2).toNot(beGreaterThanOrEqualTo(@3)); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be greater than or equal to <0.0000>, got <-1.0000>", ^{ expect(@(-1)).to(beGreaterThanOrEqualTo(@0)); }); expectFailureMessage(@"expected to not be greater than or equal to <1.0000>, got <2.0000>", ^{ expect(@2).toNot(beGreaterThanOrEqualTo(@(1))); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to be greater than or equal to <-1.0000>, got ", ^{ expect(nil).to(beGreaterThanOrEqualTo(@(-1))); }); expectNilFailureMessage(@"expected to not be greater than or equal to <1.0000>, got ", ^{ expect(nil).toNot(beGreaterThanOrEqualTo(@(1))); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCBeGreaterThanTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeGreaterThanTest : XCTestCase @end @implementation ObjCBeGreaterThanTest - (void)testPositiveMatches { expect(@2).to(beGreaterThan(@1)); expect(@2).toNot(beGreaterThan(@2)); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be greater than <0.0000>, got <-1.0000>", ^{ expect(@(-1)).to(beGreaterThan(@(0))); }); expectFailureMessage(@"expected to not be greater than <1.0000>, got <0.0000>", ^{ expect(@0).toNot(beGreaterThan(@(1))); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to be greater than <-1.0000>, got ", ^{ expect(nil).to(beGreaterThan(@(-1))); }); expectNilFailureMessage(@"expected to not be greater than <1.0000>, got ", ^{ expect(nil).toNot(beGreaterThan(@(1))); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCBeIdenticalToTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeIdenticalToTest : XCTestCase @end @implementation ObjCBeIdenticalToTest - (void)testPositiveMatches { NSNull *obj = [NSNull null]; expect(obj).to(beIdenticalTo([NSNull null])); expect(@2).toNot(beIdenticalTo(@3)); } - (void)testNegativeMatches { NSNull *obj = [NSNull null]; expectFailureMessage(([NSString stringWithFormat:@"expected to be identical to <%p>, got <%p>", obj, @2]), ^{ expect(@2).to(beIdenticalTo(obj)); }); expectFailureMessage(([NSString stringWithFormat:@"expected to not be identical to <%p>, got <%p>", obj, obj]), ^{ expect(obj).toNot(beIdenticalTo(obj)); }); } - (void)testNilMatches { NSNull *obj = [NSNull null]; expectNilFailureMessage(@"expected to be identical to nil, got nil", ^{ expect(nil).to(beIdenticalTo(nil)); }); expectNilFailureMessage(([NSString stringWithFormat:@"expected to not be identical to <%p>, got nil", obj]), ^{ expect(nil).toNot(beIdenticalTo(obj)); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCBeKindOfTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeKindOfTest : XCTestCase @end @implementation ObjCBeKindOfTest - (void)testPositiveMatches { NSMutableArray *array = [NSMutableArray array]; expect(array).to(beAKindOf([NSArray class])); expect(@1).toNot(beAKindOf([NSNull class])); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be a kind of NSNull, got <__NSCFNumber instance>", ^{ expect(@1).to(beAKindOf([NSNull class])); }); expectFailureMessage(@"expected to not be a kind of NSNull, got ", ^{ expect([NSNull null]).toNot(beAKindOf([NSNull class])); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to be a kind of NSNull, got ", ^{ expect(nil).to(beAKindOf([NSNull class])); }); expectNilFailureMessage(@"expected to not be a kind of NSNull, got ", ^{ expect(nil).toNot(beAKindOf([NSNull class])); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCBeLessThanOrEqualToTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeLessThanOrEqualToTest : XCTestCase @end @implementation ObjCBeLessThanOrEqualToTest - (void)testPositiveMatches { expect(@2).to(beLessThanOrEqualTo(@2)); expect(@2).toNot(beLessThanOrEqualTo(@1)); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be less than or equal to <1.0000>, got <2.0000>", ^{ expect(@2).to(beLessThanOrEqualTo(@1)); }); expectFailureMessage(@"expected to not be less than or equal to <1.0000>, got <1.0000>", ^{ expect(@1).toNot(beLessThanOrEqualTo(@1)); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to be less than or equal to <1.0000>, got ", ^{ expect(nil).to(beLessThanOrEqualTo(@1)); }); expectNilFailureMessage(@"expected to not be less than or equal to <-1.0000>, got ", ^{ expect(nil).toNot(beLessThanOrEqualTo(@(-1))); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCBeLessThanTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeLessThanTest : XCTestCase @end @implementation ObjCBeLessThanTest - (void)testPositiveMatches { expect(@2).to(beLessThan(@3)); expect(@2).toNot(beLessThan(@2)); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be less than <0.0000>, got <-1.0000>", ^{ expect(@(-1)).to(beLessThan(@0)); }); expectFailureMessage(@"expected to not be less than <1.0000>, got <0.0000>", ^{ expect(@0).toNot(beLessThan(@1)); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to be less than <-1.0000>, got ", ^{ expect(nil).to(beLessThan(@(-1))); }); expectNilFailureMessage(@"expected to not be less than <1.0000>, got ", ^{ expect(nil).toNot(beLessThan(@1)); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCBeNilTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeNilTest : XCTestCase @end @implementation ObjCBeNilTest - (void)testPositiveMatches { expect(nil).to(beNil()); expect(@NO).toNot(beNil()); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be nil, got <1.0000>", ^{ expect(@1).to(beNil()); }); expectFailureMessage(@"expected to not be nil, got ", ^{ expect(nil).toNot(beNil()); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCBeTrueTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeTrueTest : XCTestCase @end @implementation ObjCBeTrueTest - (void)testPositiveMatches { expect(@YES).to(beTrue()); expect(@NO).toNot(beTrue()); expect(nil).toNot(beTrue()); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be true, got <0.0000>", ^{ expect(@NO).to(beTrue()); }); expectFailureMessage(@"expected to be true, got ", ^{ expect(nil).to(beTrue()); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCBeTruthyTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeTruthyTest : XCTestCase @end @implementation ObjCBeTruthyTest - (void)testPositiveMatches { expect(@YES).to(beTruthy()); expect(@NO).toNot(beTruthy()); expect(nil).toNot(beTruthy()); } - (void)testNegativeMatches { expectFailureMessage(@"expected to be truthy, got ", ^{ expect(nil).to(beTruthy()); }); expectFailureMessage(@"expected to not be truthy, got <1.0000>", ^{ expect(@1).toNot(beTruthy()); }); expectFailureMessage(@"expected to be truthy, got <0.0000>", ^{ expect(@NO).to(beTruthy()); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCBeginWithTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCBeginWithTest : XCTestCase @end @implementation ObjCBeginWithTest - (void)testPositiveMatches { expect(@"hello world!").to(beginWith(@"hello")); expect(@"hello world!").toNot(beginWith(@"world")); NSArray *array = @[@1, @2]; expect(array).to(beginWith(@1)); expect(array).toNot(beginWith(@2)); } - (void)testNegativeMatches { expectFailureMessage(@"expected to begin with , got ", ^{ expect(@"foo").to(beginWith(@"bar")); }); expectFailureMessage(@"expected to not begin with , got ", ^{ expect(@"foo").toNot(beginWith(@"foo")); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to begin with <1>, got ", ^{ expect(nil).to(beginWith(@1)); }); expectNilFailureMessage(@"expected to not begin with <1>, got ", ^{ expect(nil).toNot(beginWith(@1)); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCContainTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCContainTest : XCTestCase @end @implementation ObjCContainTest - (void)testPositiveMatches { NSArray *array = @[@1, @2]; expect(array).to(contain(@1)); expect(array).toNot(contain(@"HI")); expect(@"String").to(contain(@"Str")); expect(@"Other").toNot(contain(@"Str")); } - (void)testNegativeMatches { expectFailureMessage(@"expected to contain , got <(1,2)>", ^{ expect((@[@1, @2])).to(contain(@3)); }); expectFailureMessage(@"expected to not contain , got <(1,2)>", ^{ expect((@[@1, @2])).toNot(contain(@2)); }); expectFailureMessage(@"expected to contain , got ", ^{ expect(@"la").to(contain(@"hi")); }); expectFailureMessage(@"expected to not contain , got ", ^{ expect(@"hihihi").toNot(contain(@"hi")); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to contain <3.0000>, got ", ^{ expect(nil).to(contain(@3)); }); expectNilFailureMessage(@"expected to not contain <3.0000>, got ", ^{ expect(nil).toNot(contain(@3)); }); expectNilFailureMessage(@"expected to contain , got ", ^{ expect(nil).to(contain(@"hi")); }); expectNilFailureMessage(@"expected to not contain , got ", ^{ expect(nil).toNot(contain(@"hi")); }); } - (void)testVariadicArguments { NSArray *array = @[@1, @2]; expect(array).to(contain(@1, @2)); expect(array).toNot(contain(@"HI", @"whale")); expect(@"String").to(contain(@"Str", @"ng")); expect(@"Other").toNot(contain(@"Str", @"Oth")); expectFailureMessage(@"expected to contain , got <(a,b,c)>", ^{ expect(@[@"a", @"b", @"c"]).to(contain(@"a", @"bar")); }); expectFailureMessage(@"expected to not contain , got <(a,b,c)>", ^{ expect(@[@"a", @"b", @"c"]).toNot(contain(@"bar", @"b")); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCEndWithTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCEndWithTest : XCTestCase @end @implementation ObjCEndWithTest - (void)testPositiveMatches { NSArray *array = @[@1, @2]; expect(@"hello world!").to(endWith(@"world!")); expect(@"hello world!").toNot(endWith(@"hello")); expect(array).to(endWith(@2)); expect(array).toNot(endWith(@1)); expect(@1).toNot(contain(@"foo")); } - (void)testNegativeMatches { expectFailureMessage(@"expected to end with , got ", ^{ expect(@"hello world!").to(endWith(@"?")); }); expectFailureMessage(@"expected to not end with , got ", ^{ expect(@"hello world!").toNot(endWith(@"!")); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to end with <1>, got ", ^{ expect(nil).to(endWith(@1)); }); expectNilFailureMessage(@"expected to not end with <1>, got ", ^{ expect(nil).toNot(endWith(@1)); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCEqualTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCEqualTest : XCTestCase @end @implementation ObjCEqualTest - (void)testPositiveMatches { expect(@1).to(equal(@1)); expect(@1).toNot(equal(@2)); expect(@1).notTo(equal(@2)); expect(@"hello").to(equal(@"hello")); } - (void)testNegativeMatches { expectFailureMessage(@"expected to equal <2.0000>, got <1.0000>", ^{ expect(@1).to(equal(@2)); }); expectFailureMessage(@"expected to not equal <1.0000>, got <1.0000>", ^{ expect(@1).toNot(equal(@1)); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to equal , got ", ^{ expect(nil).to(equal(nil)); }); expectNilFailureMessage(@"expected to not equal , got ", ^{ expect(nil).toNot(equal(nil)); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCHaveCount.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCHaveCountTest : XCTestCase @end @implementation ObjCHaveCountTest - (void)testHaveCountForNSArray { expect(@[@1, @2, @3]).to(haveCount(@3)); expect(@[@1, @2, @3]).notTo(haveCount(@1)); expect(@[]).to(haveCount(@0)); expect(@[@1]).notTo(haveCount(@0)); expectFailureMessage(@"expected to have (1,2,3) with count 1, got 3", ^{ expect(@[@1, @2, @3]).to(haveCount(@1)); }); expectFailureMessage(@"expected to not have (1,2,3) with count 3, got 3", ^{ expect(@[@1, @2, @3]).notTo(haveCount(@3)); }); } - (void)testHaveCountForNSDictionary { expect(@{@"1":@1, @"2":@2, @"3":@3}).to(haveCount(@3)); expect(@{@"1":@1, @"2":@2, @"3":@3}).notTo(haveCount(@1)); expectFailureMessage(@"expected to have {1 = 1;2 = 2;3 = 3;} with count 1, got 3", ^{ expect(@{@"1":@1, @"2":@2, @"3":@3}).to(haveCount(@1)); }); expectFailureMessage(@"expected to not have {1 = 1;2 = 2;3 = 3;} with count 3, got 3", ^{ expect(@{@"1":@1, @"2":@2, @"3":@3}).notTo(haveCount(@3)); }); } - (void)testHaveCountForNSHashtable { NSHashTable *const table = [NSHashTable hashTableWithOptions:NSPointerFunctionsStrongMemory]; [table addObject:@1]; [table addObject:@2]; [table addObject:@3]; expect(table).to(haveCount(@3)); expect(table).notTo(haveCount(@1)); expectFailureMessage(@"expected to have NSHashTable {[2] 2[12] 1[13] 3}with count 1, got 3", ^{ expect(table).to(haveCount(@1)); }); expectFailureMessage(@"expected to not have NSHashTable {[2] 2[12] 1[13] 3}with count 3, got 3", ^{ expect(table).notTo(haveCount(@3)); }); } - (void)testHaveCountForNSSet { NSSet *const set = [NSSet setWithArray:@[@1, @2, @3]]; expect(set).to(haveCount(@3)); expect(set).notTo(haveCount(@1)); expectFailureMessage(@"expected to have {(3,1,2)} with count 1, got 3", ^{ expect(set).to(haveCount(@1)); }); expectFailureMessage(@"expected to not have {(3,1,2)} with count 3, got 3", ^{ expect(set).notTo(haveCount(@3)); }); } - (void)testHaveCountForUnsupportedTypes { expectFailureMessage(@"expected to get type of NSArray, NSSet, NSDictionary, or NSHashTable, got __NSCFConstantString", ^{ expect(@"string").to(haveCount(@6)); }); expectFailureMessage(@"expected to get type of NSArray, NSSet, NSDictionary, or NSHashTable, got __NSCFNumber", ^{ expect(@1).to(haveCount(@6)); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCMatchTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCMatchTest : XCTestCase @end @implementation ObjCMatchTest - (void)testPositiveMatches { expect(@"11:14").to(match(@"\\d{2}:\\d{2}")); expect(@"hello").toNot(match(@"\\d{2}:\\d{2}")); } - (void)testNegativeMatches { expectFailureMessage(@"expected to match <\\d{2}:\\d{2}>, got ", ^{ expect(@"hello").to(match(@"\\d{2}:\\d{2}")); }); expectFailureMessage(@"expected to not match <\\d{2}:\\d{2}>, got <11:22>", ^{ expect(@"11:22").toNot(match(@"\\d{2}:\\d{2}")); }); } - (void)testNilMatches { expectNilFailureMessage(@"expected to match <\\d{2}:\\d{2}>, got ", ^{ expect(nil).to(match(@"\\d{2}:\\d{2}")); }); expectNilFailureMessage(@"expected to not match <\\d{2}:\\d{2}>, got ", ^{ expect(nil).toNot(match(@"\\d{2}:\\d{2}")); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCRaiseExceptionTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCRaiseExceptionTest : XCTestCase @end @implementation ObjCRaiseExceptionTest - (void)testPositiveMatches { __block NSException *exception = [NSException exceptionWithName:NSInvalidArgumentException reason:@"No food" userInfo:@{@"key": @"value"}]; expectAction(^{ @throw exception; }).to(raiseException()); expectAction(^{ [exception raise]; }).to(raiseException()); expectAction(^{ [exception raise]; }).to(raiseException().named(NSInvalidArgumentException)); expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). reason(@"No food")); expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). reason(@"No food"). userInfo(@{@"key": @"value"})); expectAction(^{ }).toNot(raiseException()); } - (void)testPositiveMatchesWithBlocks { __block NSException *exception = [NSException exceptionWithName:NSInvalidArgumentException reason:@"No food" userInfo:@{@"key": @"value"}]; expectAction(^{ [exception raise]; }).to(raiseException(). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(NSInvalidArgumentException)); })); expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(NSInvalidArgumentException)); })); expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). reason(@"No food"). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(NSInvalidArgumentException)); })); expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). reason(@"No food"). userInfo(@{@"key": @"value"}). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(NSInvalidArgumentException)); })); } - (void)testNegativeMatches { __block NSException *exception = [NSException exceptionWithName:NSInvalidArgumentException reason:@"No food" userInfo:@{@"key": @"value"}]; expectFailureMessage(@"expected to raise any exception, got no exception", ^{ expectAction(^{ }).to(raiseException()); }); expectFailureMessage(@"expected to raise exception with name , got no exception", ^{ expectAction(^{ }).to(raiseException(). named(@"foo")); }); expectFailureMessage(@"expected to raise exception with name with reason , got no exception", ^{ expectAction(^{ }).to(raiseException(). named(NSInvalidArgumentException). reason(@"cakes")); }); expectFailureMessage(@"expected to raise exception with name with reason with userInfo <{k = v;}>, got no exception", ^{ expectAction(^{ }).to(raiseException(). named(NSInvalidArgumentException). reason(@"No food"). userInfo(@{@"k": @"v"})); }); expectFailureMessage(@"expected to not raise any exception, got NSException { name=NSInvalidArgumentException, reason='No food', userInfo=[key: value] }", ^{ expectAction(^{ [exception raise]; }).toNot(raiseException()); }); } - (void)testNegativeMatchesWithPassingBlocks { __block NSException *exception = [NSException exceptionWithName:NSInvalidArgumentException reason:@"No food" userInfo:@{@"key": @"value"}]; expectFailureMessage(@"expected to raise exception that satisfies block, got no exception", ^{ expect(exception).to(raiseException(). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(@"LOL")); })); }); NSString *outerFailureMessage = @"expected to raise exception that satisfies block, got NSException { name=NSInvalidArgumentException, reason='No food', userInfo=[key: value] }"; expectFailureMessages((@[outerFailureMessage]), ^{ expectAction(^{ [exception raise]; }).to(raiseException(). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(NSInvalidArgumentException)); })); }); outerFailureMessage = @"expected to raise exception with name that satisfies block, got NSException { name=NSInvalidArgumentException, reason='No food', userInfo=[key: value] }"; expectFailureMessages((@[outerFailureMessage]), ^{ expectAction(^{ [exception raise]; }).to(raiseException(). named(@"foo"). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(NSInvalidArgumentException)); })); }); outerFailureMessage = @"expected to raise exception with name with reason that satisfies block, got NSException { name=NSInvalidArgumentException, reason='No food', userInfo=[key: value] }"; expectFailureMessages((@[outerFailureMessage]), ^{ expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). reason(@"bar"). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(NSInvalidArgumentException)); })); }); outerFailureMessage = @"expected to raise exception with name with reason with userInfo <{}> that satisfies block, got NSException { name=NSInvalidArgumentException, reason='No food', userInfo=[key: value] }"; expectFailureMessages((@[outerFailureMessage]), ^{ expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). reason(@"No food"). userInfo(@{}). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(NSInvalidArgumentException)); })); }); } - (void)testNegativeMatchesWithNegativeBlocks { __block NSException *exception = [NSException exceptionWithName:NSInvalidArgumentException reason:@"No food" userInfo:@{@"key": @"value"}]; NSString *outerFailureMessage; NSString const *innerFailureMessage = @"expected to equal , got "; outerFailureMessage = @"expected to raise exception with name that satisfies block, got NSException { name=NSInvalidArgumentException, reason='No food', userInfo=[key: value] }"; expectFailureMessages((@[outerFailureMessage, innerFailureMessage]), ^{ expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(@"foo")); })); }); outerFailureMessage = @"expected to raise exception with name with reason that satisfies block, got NSException { name=NSInvalidArgumentException, reason='No food', userInfo=[key: value] }"; expectFailureMessages((@[outerFailureMessage, innerFailureMessage]), ^{ expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). reason(@"No food"). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(@"foo")); })); }); outerFailureMessage = @"expected to raise exception with name with reason with userInfo <{key = value;}> that satisfies block, got NSException { name=NSInvalidArgumentException, reason='No food', userInfo=[key: value] }"; expectFailureMessages((@[outerFailureMessage, innerFailureMessage]), ^{ expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInvalidArgumentException). reason(@"No food"). userInfo(@{@"key": @"value"}). satisfyingBlock(^(NSException *exception) { expect(exception.name).to(equal(@"foo")); })); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCSyncTest.m ================================================ #import #import #import "NimbleSpecHelper.h" @interface ObjCSyncTest : XCTestCase @end @implementation ObjCSyncTest - (void)testFailureExpectation { expectFailureMessage(@"fail() always fails", ^{ fail(); }); expectFailureMessage(@"This always fails", ^{ failWithMessage(@"This always fails"); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/NimbleTests/objc/ObjCUserDescriptionTest.m ================================================ #import #import "NimbleSpecHelper.h" @interface ObjCUserDescriptionTest : XCTestCase @end @implementation ObjCUserDescriptionTest - (void)testToWithDescription { expectFailureMessage(@"These are equal!\n" "expected to equal <2.0000>, got <1.0000>", ^{ expect(@1).toWithDescription(equal(@2), @"These are equal!"); }); } - (void)testToNotWithDescription { expectFailureMessage(@"These aren't equal!\n" "expected to not equal <1.0000>, got <1.0000>", ^{ expect(@1).toNotWithDescription(equal(@1), @"These aren't equal!"); }); } - (void)testNotToWithDescription { expectFailureMessage(@"These aren't equal!\n" "expected to not equal <1.0000>, got <1.0000>", ^{ expect(@1).notToWithDescription(equal(@1), @"These aren't equal!"); }); } - (void)testToEventuallyWithDescription { expectFailureMessage(@"These are equal!\n" "expected to eventually equal <2.0000>, got <1.0000>", ^{ expect(@1).toEventuallyWithDescription(equal(@2), @"These are equal!"); }); } - (void)testToEventuallyNotWithDescription { expectFailureMessage(@"These aren't equal!\n" "expected to eventually not equal <1.0000>, got <1.0000>", ^{ expect(@1).toEventuallyNotWithDescription(equal(@1), @"These aren't equal!"); }); } - (void)testToNotEventuallyWithDescription { expectFailureMessage(@"These aren't equal!\n" "expected to eventually not equal <1.0000>, got <1.0000>", ^{ expect(@1).toNotEventuallyWithDescription(equal(@1), @"These aren't equal!"); }); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/README.md ================================================ # Nimble Use Nimble to express the expected outcomes of Swift or Objective-C expressions. Inspired by [Cedar](https://github.com/pivotal/cedar). ```swift // Swift expect(1 + 1).to(equal(2)) expect(1.2).to(beCloseTo(1.1, within: 0.1)) expect(3) > 2 expect("seahorse").to(contain("sea")) expect(["Atlantic", "Pacific"]).toNot(contain("Mississippi")) expect(ocean.isClean).toEventually(beTruthy()) ``` # How to Use Nimble **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [Some Background: Expressing Outcomes Using Assertions in XCTest](#some-background-expressing-outcomes-using-assertions-in-xctest) - [Nimble: Expectations Using `expect(...).to`](#nimble-expectations-using-expectto) - [Custom Failure Messages](#custom-failure-messages) - [Type Checking](#type-checking) - [Operator Overloads](#operator-overloads) - [Lazily Computed Values](#lazily-computed-values) - [C Primitives](#c-primitives) - [Asynchronous Expectations](#asynchronous-expectations) - [Objective-C Support](#objective-c-support) - [Disabling Objective-C Shorthand](#disabling-objective-c-shorthand) - [Built-in Matcher Functions](#built-in-matcher-functions) - [Equivalence](#equivalence) - [Identity](#identity) - [Comparisons](#comparisons) - [Types/Classes](#typesclasses) - [Truthiness](#truthiness) - [Swift Error Handling](#swift-error-handling) - [Exceptions](#exceptions) - [Collection Membership](#collection-membership) - [Strings](#strings) - [Checking if all elements of a collection pass a condition](#checking-if-all-elements-of-a-collection-pass-a-condition) - [Verify collection count](#verify-collection-count) - [Writing Your Own Matchers](#writing-your-own-matchers) - [Lazy Evaluation](#lazy-evaluation) - [Type Checking via Swift Generics](#type-checking-via-swift-generics) - [Customizing Failure Messages](#customizing-failure-messages) - [Supporting Objective-C](#supporting-objective-c) - [Properly Handling `nil` in Objective-C Matchers](#properly-handling-nil-in-objective-c-matchers) - [Installing Nimble](#installing-nimble) - [Installing Nimble as a Submodule](#installing-nimble-as-a-submodule) - [Installing Nimble via CocoaPods](#installing-nimble-via-cocoapods) - [Using Nimble without XCTest](#using-nimble-without-xctest) # Some Background: Expressing Outcomes Using Assertions in XCTest Apple's Xcode includes the XCTest framework, which provides assertion macros to test whether code behaves properly. For example, to assert that `1 + 1 = 2`, XCTest has you write: ```swift // Swift XCTAssertEqual(1 + 1, 2, "expected one plus one to equal two") ``` Or, in Objective-C: ```objc // Objective-C XCTAssertEqual(1 + 1, 2, @"expected one plus one to equal two"); ``` XCTest assertions have a couple of drawbacks: 1. **Not enough macros.** There's no easy way to assert that a string contains a particular substring, or that a number is less than or equal to another. 2. **It's hard to write asynchronous tests.** XCTest forces you to write a lot of boilerplate code. Nimble addresses these concerns. # Nimble: Expectations Using `expect(...).to` Nimble allows you to express expectations using a natural, easily understood language: ```swift // Swift import Nimble expect(seagull.squawk).to(equal("Squee!")) ``` ```objc // Objective-C @import Nimble; expect(seagull.squawk).to(equal(@"Squee!")); ``` > The `expect` function autocompletes to include `file:` and `line:`, but these parameters are optional. Use the default values to have Xcode highlight the correct line when an expectation is not met. To perform the opposite expectation--to assert something is *not* equal--use `toNot` or `notTo`: ```swift // Swift import Nimble expect(seagull.squawk).toNot(equal("Oh, hello there!")) expect(seagull.squawk).notTo(equal("Oh, hello there!")) ``` ```objc // Objective-C @import Nimble; expect(seagull.squawk).toNot(equal(@"Oh, hello there!")); expect(seagull.squawk).notTo(equal(@"Oh, hello there!")); ``` ## Custom Failure Messages Would you like to add more information to the test's failure messages? Use the `description` optional argument to add your own text: ```swift // Swift expect(1 + 1).to(equal(3)) // failed - expected to equal <3>, got <2> expect(1 + 1).to(equal(3), description: "Make sure libKindergartenMath is loaded") // failed - Make sure libKindergartenMath is loaded // expected to equal <3>, got <2> ``` Or the *WithDescription version in Objective-C: ```objc // Objective-C @import Nimble; expect(@(1+1)).to(equal(@3)); // failed - expected to equal <3.0000>, got <2.0000> expect(@(1+1)).toWithDescription(equal(@3), @"Make sure libKindergartenMath is loaded"); // failed - Make sure libKindergartenMath is loaded // expected to equal <3.0000>, got <2.0000> ``` ## Type Checking Nimble makes sure you don't compare two types that don't match: ```swift // Swift // Does not compile: expect(1 + 1).to(equal("Squee!")) ``` > Nimble uses generics--only available in Swift--to ensure type correctness. That means type checking is not available when using Nimble in Objective-C. :sob: ## Operator Overloads Tired of so much typing? With Nimble, you can use overloaded operators like `==` for equivalence, or `>` for comparisons: ```swift // Swift // Passes if squawk does not equal "Hi!": expect(seagull.squawk) != "Hi!" // Passes if 10 is greater than 2: expect(10) > 2 ``` > Operator overloads are only available in Swift, so you won't be able to use this syntax in Objective-C. :broken_heart: ## Lazily Computed Values The `expect` function doesn't evalaute the value it's given until it's time to match. So Nimble can test whether an expression raises an exception once evaluated: ```swift // Swift // Note: Swift currently doesn't have exceptions. // Only Objective-C code can raise exceptions // that Nimble will catch. let exception = NSException( name: NSInternalInconsistencyException, reason: "Not enough fish in the sea.", userInfo: ["something": "is fishy"]) expect { exception.raise() }.to(raiseException()) // Also, you can customize raiseException to be more specific expect { exception.raise() }.to(raiseException(named: NSInternalInconsistencyException)) expect { exception.raise() }.to(raiseException( named: NSInternalInconsistencyException, reason: "Not enough fish in the sea")) expect { exception.raise() }.to(raiseException( named: NSInternalInconsistencyException, reason: "Not enough fish in the sea", userInfo: ["something": "is fishy"])) ``` Objective-C works the same way, but you must use the `expectAction` macro when making an expectation on an expression that has no return value: ```objc // Objective-C NSException *exception = [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Not enough fish in the sea." userInfo:nil]; expectAction(^{ [exception raise]; }).to(raiseException()); // Use the property-block syntax to be more specific. expectAction(^{ [exception raise]; }).to(raiseException().named(NSInternalInconsistencyException)); expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInternalInconsistencyException). reason("Not enough fish in the sea")); expectAction(^{ [exception raise]; }).to(raiseException(). named(NSInternalInconsistencyException). reason("Not enough fish in the sea"). userInfo(@{@"something": @"is fishy"})); // You can also pass a block for custom matching of the raised exception expectAction(exception.raise()).to(raiseException().satisfyingBlock(^(NSException *exception) { expect(exception.name).to(beginWith(NSInternalInconsistencyException)); })); ``` ## C Primitives Some testing frameworks make it hard to test primitive C values. In Nimble, it just works: ```swift // Swift let actual: CInt = 1 let expectedValue: CInt = 1 expect(actual).to(equal(expectedValue)) ``` In fact, Nimble uses type inference, so you can write the above without explicitly specifying both types: ```swift // Swift expect(1 as CInt).to(equal(1)) ``` > In Objective-C, Nimble only supports Objective-C objects. To make expectations on primitive C values, wrap then in an object literal: ```objc expect(@(1 + 1)).to(equal(@2)); ``` ## Asynchronous Expectations In Nimble, it's easy to make expectations on values that are updated asynchronously. Just use `toEventually` or `toEventuallyNot`: ```swift // Swift dispatch_async(dispatch_get_main_queue()) { ocean.add("dolphins") ocean.add("whales") } expect(ocean).toEventually(contain("dolphins", "whales")) ``` ```objc // Objective-C dispatch_async(dispatch_get_main_queue(), ^{ [ocean add:@"dolphins"]; [ocean add:@"whales"]; }); expect(ocean).toEventually(contain(@"dolphins", @"whales")); ``` In the above example, `ocean` is constantly re-evaluated. If it ever contains dolphins and whales, the expectation passes. If `ocean` still doesn't contain them, even after being continuously re-evaluated for one whole second, the expectation fails. Sometimes it takes more than a second for a value to update. In those cases, use the `timeout` parameter: ```swift // Swift // Waits three seconds for ocean to contain "starfish": expect(ocean).toEventually(contain("starfish"), timeout: 3) ``` ```objc // Objective-C // Waits three seconds for ocean to contain "starfish": expect(ocean).withTimeout(3).toEventually(contain(@"starfish")); ``` You can also provide a callback by using the `waitUntil` function: ```swift // Swift waitUntil { done in // do some stuff that takes a while... NSThread.sleepForTimeInterval(0.5) done() } ``` ```objc // Objective-C waitUntil(^(void (^done)(void)){ // do some stuff that takes a while... [NSThread sleepForTimeInterval:0.5]; done(); }); ``` `waitUntil` also optionally takes a timeout parameter: ```swift // Swift waitUntil(timeout: 10) { done in // do some stuff that takes a while... NSThread.sleepForTimeInterval(1) done() } ``` ```objc // Objective-C waitUntilTimeout(10, ^(void (^done)(void)){ // do some stuff that takes a while... [NSThread sleepForTimeInterval:1]; done(); }); ``` ## Objective-C Support Nimble has full support for Objective-C. However, there are two things to keep in mind when using Nimble in Objective-C: 1. All parameters passed to the `expect` function, as well as matcher functions like `equal`, must be Objective-C objects: ```objc // Objective-C @import Nimble; expect(@(1 + 1)).to(equal(@2)); expect(@"Hello world").to(contain(@"world")); ``` 2. To make an expectation on an expression that does not return a value, such as `-[NSException raise]`, use `expectAction` instead of `expect`: ```objc // Objective-C expectAction(^{ [exception raise]; }).to(raiseException()); ``` ## Disabling Objective-C Shorthand Nimble provides a shorthand for expressing expectations using the `expect` function. To disable this shorthand in Objective-C, define the `NIMBLE_DISABLE_SHORT_SYNTAX` macro somewhere in your code before importing Nimble: ```objc #define NIMBLE_DISABLE_SHORT_SYNTAX 1 @import Nimble; NMB_expect(^{ return seagull.squawk; }, __FILE__, __LINE__).to(NMB_equal(@"Squee!")); ``` > Disabling the shorthand is useful if you're testing functions with names that conflict with Nimble functions, such as `expect` or `equal`. If that's not the case, there's no point in disabling the shorthand. # Built-in Matcher Functions Nimble includes a wide variety of matcher functions. ## Equivalence ```swift // Swift // Passes if actual is equivalent to expected: expect(actual).to(equal(expected)) expect(actual) == expected // Passes if actual is not equivalent to expected: expect(actual).toNot(equal(expected)) expect(actual) != expected ``` ```objc // Objective-C // Passes if actual is equivalent to expected: expect(actual).to(equal(expected)) // Passes if actual is not equivalent to expected: expect(actual).toNot(equal(expected)) ``` Values must be `Equatable`, `Comparable`, or subclasses of `NSObject`. `equal` will always fail when used to compare one or more `nil` values. ## Identity ```swift // Swift // Passes if actual has the same pointer address as expected: expect(actual).to(beIdenticalTo(expected)) expect(actual) === expected // Passes if actual does not have the same pointer address as expected: expect(actual).toNot(beIdenticalTo(expected)) expect(actual) !== expected ``` ```objc // Objective-C // Passes if actual has the same pointer address as expected: expect(actual).to(beIdenticalTo(expected)); // Passes if actual does not have the same pointer address as expected: expect(actual).toNot(beIdenticalTo(expected)); ``` ## Comparisons ```swift // Swift expect(actual).to(beLessThan(expected)) expect(actual) < expected expect(actual).to(beLessThanOrEqualTo(expected)) expect(actual) <= expected expect(actual).to(beGreaterThan(expected)) expect(actual) > expected expect(actual).to(beGreaterThanOrEqualTo(expected)) expect(actual) >= expected ``` ```objc // Objective-C expect(actual).to(beLessThan(expected)); expect(actual).to(beLessThanOrEqualTo(expected)); expect(actual).to(beGreaterThan(expected)); expect(actual).to(beGreaterThanOrEqualTo(expected)); ``` > Values given to the comparison matchers above must implement `Comparable`. Because of how computers represent floating point numbers, assertions that two floating point numbers be equal will sometimes fail. To express that two numbers should be close to one another within a certain margin of error, use `beCloseTo`: ```swift // Swift expect(actual).to(beCloseTo(expected, within: delta)) ``` ```objc // Objective-C expect(actual).to(beCloseTo(expected).within(delta)); ``` For example, to assert that `10.01` is close to `10`, you can write: ```swift // Swift expect(10.01).to(beCloseTo(10, within: 0.1)) ``` ```objc // Objective-C expect(@(10.01)).to(beCloseTo(@10).within(0.1)); ``` There is also an operator shortcut available in Swift: ```swift // Swift expect(actual) ≈ expected expect(actual) ≈ (expected, delta) ``` (Type Option-x to get ≈ on a U.S. keyboard) The former version uses the default delta of 0.0001. Here is yet another way to do this: ```swift // Swift expect(actual) ≈ expected ± delta expect(actual) == expected ± delta ``` (Type Option-Shift-= to get ± on a U.S. keyboard) If you are comparing arrays of floating point numbers, you'll find the following useful: ```swift // Swift expect([0.0, 2.0]) ≈ [0.0001, 2.0001] expect([0.0, 2.0]).to(beCloseTo([0.1, 2.1], within: 0.1)) ``` > Values given to the `beCloseTo` matcher must be coercable into a `Double`. ## Types/Classes ```swift // Swift // Passes if instance is an instance of aClass: expect(instance).to(beAnInstanceOf(aClass)) // Passes if instance is an instance of aClass or any of its subclasses: expect(instance).to(beAKindOf(aClass)) ``` ```objc // Objective-C // Passes if instance is an instance of aClass: expect(instance).to(beAnInstanceOf(aClass)); // Passes if instance is an instance of aClass or any of its subclasses: expect(instance).to(beAKindOf(aClass)); ``` > Instances must be Objective-C objects: subclasses of `NSObject`, or Swift objects bridged to Objective-C with the `@objc` prefix. For example, to assert that `dolphin` is a kind of `Mammal`: ```swift // Swift expect(dolphin).to(beAKindOf(Mammal)) ``` ```objc // Objective-C expect(dolphin).to(beAKindOf([Mammal class])); ``` > `beAnInstanceOf` uses the `-[NSObject isMemberOfClass:]` method to test membership. `beAKindOf` uses `-[NSObject isKindOfClass:]`. ## Truthiness ```swift // Passes if actual is not nil, false, or an object with a boolean value of false: expect(actual).to(beTruthy()) // Passes if actual is only true (not nil or an object conforming to BooleanType true): expect(actual).to(beTrue()) // Passes if actual is nil, false, or an object with a boolean value of false: expect(actual).to(beFalsy()) // Passes if actual is only false (not nil or an object conforming to BooleanType false): expect(actual).to(beFalse()) // Passes if actual is nil: expect(actual).to(beNil()) ``` ```objc // Objective-C // Passes if actual is not nil, false, or an object with a boolean value of false: expect(actual).to(beTruthy()); // Passes if actual is only true (not nil or an object conforming to BooleanType true): expect(actual).to(beTrue()); // Passes if actual is nil, false, or an object with a boolean value of false: expect(actual).to(beFalsy()); // Passes if actual is only false (not nil or an object conforming to BooleanType false): expect(actual).to(beFalse()); // Passes if actual is nil: expect(actual).to(beNil()); ``` ## Swift Error Handling If you're using Swift 2.0+, you can use the `throwError` matcher to check if an error is thrown. ```swift // Swift // Passes if somethingThatThrows() throws an ErrorType: expect{ try somethingThatThrows() }.to(throwError()) // Passes if somethingThatThrows() throws an error with a given domain: expect{ try somethingThatThrows() }.to(throwError { (error: ErrorType) in expect(error._domain).to(equal(NSCocoaErrorDomain)) }) // Passes if somethingThatThrows() throws an error with a given case: expect{ try somethingThatThrows() }.to(throwError(NSCocoaError.PropertyListReadCorruptError)) // Passes if somethingThatThrows() throws an error with a given type: expect{ try somethingThatThrows() }.to(throwError(errorType: MyError.self)) ``` Note: This feature is only available in Swift. ## Exceptions ```swift // Swift // Passes if actual, when evaluated, raises an exception: expect(actual).to(raiseException()) // Passes if actual raises an exception with the given name: expect(actual).to(raiseException(named: name)) // Passes if actual raises an exception with the given name and reason: expect(actual).to(raiseException(named: name, reason: reason)) // Passes if actual raises an exception and it passes expectations in the block // (in this case, if name begins with 'a r') expect { exception.raise() }.to(raiseException { (exception: NSException) in expect(exception.name).to(beginWith("a r")) }) ``` ```objc // Objective-C // Passes if actual, when evaluated, raises an exception: expect(actual).to(raiseException()) // Passes if actual raises an exception with the given name expect(actual).to(raiseException().named(name)) // Passes if actual raises an exception with the given name and reason: expect(actual).to(raiseException().named(name).reason(reason)) // Passes if actual raises an exception and it passes expectations in the block // (in this case, if name begins with 'a r') expect(actual).to(raiseException().satisfyingBlock(^(NSException *exception) { expect(exception.name).to(beginWith(@"a r")); })); ``` Note: Swift currently doesn't have exceptions. Only Objective-C code can raise exceptions that Nimble will catch. ## Collection Membership ```swift // Swift // Passes if all of the expected values are members of actual: expect(actual).to(contain(expected...)) // Passes if actual is an empty collection (it contains no elements): expect(actual).to(beEmpty()) ``` ```objc // Objective-C // Passes if expected is a member of actual: expect(actual).to(contain(expected)); // Passes if actual is an empty collection (it contains no elements): expect(actual).to(beEmpty()); ``` > In Swift `contain` takes any number of arguments. The expectation passes if all of them are members of the collection. In Objective-C, `contain` only takes one argument [for now](https://github.com/Quick/Nimble/issues/27). For example, to assert that a list of sea creature names contains "dolphin" and "starfish": ```swift // Swift expect(["whale", "dolphin", "starfish"]).to(contain("dolphin", "starfish")) ``` ```objc // Objective-C expect(@[@"whale", @"dolphin", @"starfish"]).to(contain(@"dolphin")); expect(@[@"whale", @"dolphin", @"starfish"]).to(contain(@"starfish")); ``` > `contain` and `beEmpty` expect collections to be instances of `NSArray`, `NSSet`, or a Swift collection composed of `Equatable` elements. To test whether a set of elements is present at the beginning or end of an ordered collection, use `beginWith` and `endWith`: ```swift // Swift // Passes if the elements in expected appear at the beginning of actual: expect(actual).to(beginWith(expected...)) // Passes if the the elements in expected come at the end of actual: expect(actual).to(endWith(expected...)) ``` ```objc // Objective-C // Passes if the elements in expected appear at the beginning of actual: expect(actual).to(beginWith(expected)); // Passes if the the elements in expected come at the end of actual: expect(actual).to(endWith(expected)); ``` > `beginWith` and `endWith` expect collections to be instances of `NSArray`, or ordered Swift collections composed of `Equatable` elements. Like `contain`, in Objective-C `beginWith` and `endWith` only support a single argument [for now](https://github.com/Quick/Nimble/issues/27). ## Strings ```swift // Swift // Passes if actual contains substring expected: expect(actual).to(contain(expected)) // Passes if actual begins with substring: expect(actual).to(beginWith(expected)) // Passes if actual ends with substring: expect(actual).to(endWith(expected)) // Passes if actual is an empty string, "": expect(actual).to(beEmpty()) // Passes if actual matches the regular expression defined in expected: expect(actual).to(match(expected)) ``` ```objc // Objective-C // Passes if actual contains substring expected: expect(actual).to(contain(expected)); // Passes if actual begins with substring: expect(actual).to(beginWith(expected)); // Passes if actual ends with substring: expect(actual).to(endWith(expected)); // Passes if actual is an empty string, "": expect(actual).to(beEmpty()); // Passes if actual matches the regular expression defined in expected: expect(actual).to(match(expected)) ``` ## Checking if all elements of a collection pass a condition ```swift // Swift // with a custom function: expect([1,2,3,4]).to(allPass({$0 < 5})) // with another matcher: expect([1,2,3,4]).to(allPass(beLessThan(5))) ``` ```objc // Objective-C expect(@[@1, @2, @3,@4]).to(allPass(beLessThan(@5))); ``` For Swift the actual value has to be a SequenceType, e.g. an array, a set or a custom seqence type. For Objective-C the actual value has to be a NSFastEnumeration, e.g. NSArray and NSSet, of NSObjects and only the variant which uses another matcher is available here. ## Verify collection count ```swift // passes if actual collection's count is equal to expected expect(actual).to(haveCount(expected)) // passes if actual collection's count is not equal to expected expect(actual).notTo(haveCount(expected)) ``` ```objc // passes if actual collection's count is equal to expected expect(actual).to(haveCount(expected)) // passes if actual collection's count is not equal to expected expect(actual).notTo(haveCount(expected)) ``` For Swift the actual value must be a `CollectionType` such as array, dictionary or set. For Objective-C the actual value has to be one of the following classes `NSArray`, `NSDictionary`, `NSSet`, `NSHashTable` or one of their subclasses. # Writing Your Own Matchers In Nimble, matchers are Swift functions that take an expected value and return a `MatcherFunc` closure. Take `equal`, for example: ```swift // Swift public func equal(expectedValue: T?) -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "equal <\(expectedValue)>" return actualExpression.evaluate() == expectedValue } } ``` The return value of a `MatcherFunc` closure is a `Bool` that indicates whether the actual value matches the expectation: `true` if it does, or `false` if it doesn't. > The actual `equal` matcher function does not match when either `actual` or `expected` are nil; the example above has been edited for brevity. Since matchers are just Swift functions, you can define them anywhere: at the top of your test file, in a file shared by all of your tests, or in an Xcode project you distribute to others. > If you write a matcher you think everyone can use, consider adding it to Nimble's built-in set of matchers by sending a pull request! Or distribute it yourself via GitHub. For examples of how to write your own matchers, just check out the [`Matchers` directory](https://github.com/Quick/Nimble/tree/master/Nimble/Matchers) to see how Nimble's built-in set of matchers are implemented. You can also check out the tips below. ## Lazy Evaluation `actualExpression` is a lazy, memoized closure around the value provided to the `expect` function. The expression can either be a closure or a value directly passed to `expect(...)`. In order to determine whether that value matches, custom matchers should call `actualExpression.evaluate()`: ```swift // Swift public func beNil() -> MatcherFunc { return MatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "be nil" return actualExpression.evaluate() == nil } } ``` In the above example, `actualExpression` is not `nil`--it is a closure that returns a value. The value it returns, which is accessed via the `evaluate()` method, may be `nil`. If that value is `nil`, the `beNil` matcher function returns `true`, indicating that the expectation passed. Use `expression.isClosure` to determine if the expression will be invoking a closure to produce its value. ## Type Checking via Swift Generics Using Swift's generics, matchers can constrain the type of the actual value passed to the `expect` function by modifying the return type. For example, the following matcher, `haveDescription`, only accepts actual values that implement the `Printable` protocol. It checks their `description` against the one provided to the matcher function, and passes if they are the same: ```swift // Swift public func haveDescription(description: String) -> MatcherFunc { return MatcherFunc { actual, failureMessage in return actual.evaluate().description == description } } ``` ## Customizing Failure Messages By default, Nimble outputs the following failure message when an expectation fails: ``` expected to match, got <\(actual)> ``` You can customize this message by modifying the `failureMessage` struct from within your `MatcherFunc` closure. To change the verb "match" to something else, update the `postfixMessage` property: ```swift // Swift // Outputs: expected to be under the sea, got <\(actual)> failureMessage.postfixMessage = "be under the sea" ``` You can change how the `actual` value is displayed by updating `failureMessage.actualValue`. Or, to remove it altogether, set it to `nil`: ```swift // Swift // Outputs: expected to be under the sea failureMessage.actualValue = nil failureMessage.postfixMessage = "be under the sea" ``` ## Supporting Objective-C To use a custom matcher written in Swift from Objective-C, you'll have to extend the `NMBObjCMatcher` class, adding a new class method for your custom matcher. The example below defines the class method `+[NMBObjCMatcher beNilMatcher]`: ```swift // Swift extension NMBObjCMatcher { public class func beNilMatcher() -> NMBObjCMatcher { return NMBObjCMatcher { actualBlock, failureMessage, location in let block = ({ actualBlock() as NSObject? }) let expr = Expression(expression: block, location: location) return beNil().matches(expr, failureMessage: failureMessage) } } } ``` The above allows you to use the matcher from Objective-C: ```objc // Objective-C expect(actual).to([NMBObjCMatcher beNilMatcher]()); ``` To make the syntax easier to use, define a C function that calls the class method: ```objc // Objective-C FOUNDATION_EXPORT id beNil() { return [NMBObjCMatcher beNilMatcher]; } ``` ### Properly Handling `nil` in Objective-C Matchers When supporting Objective-C, make sure you handle `nil` appropriately. Like [Cedar](https://github.com/pivotal/cedar/issues/100), **most matchers do not match with nil**. This is to bring prevent test writers from being surprised by `nil` values where they did not expect them. Nimble provides the `beNil` matcher function for test writer that want to make expectations on `nil` objects: ```objc // Objective-C expect(nil).to(equal(nil)); // fails expect(nil).to(beNil()); // passes ``` If your matcher does not want to match with nil, you use `NonNilMatcherFunc` and the `canMatchNil` constructor on `NMBObjCMatcher`. Using both types will automatically generate expected value failure messages when they're nil. ```swift public func beginWith(startingElement: T) -> NonNilMatcherFunc { return NonNilMatcherFunc { actualExpression, failureMessage in failureMessage.postfixMessage = "begin with <\(startingElement)>" if let actualValue = actualExpression.evaluate() { var actualGenerator = actualValue.generate() return actualGenerator.next() == startingElement } return false } } extension NMBObjCMatcher { public class func beginWithMatcher(expected: AnyObject) -> NMBObjCMatcher { return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in let actual = actualExpression.evaluate() let expr = actualExpression.cast { $0 as? NMBOrderedCollection } return beginWith(expected).matches(expr, failureMessage: failureMessage) } } } ``` # Installing Nimble > Nimble can be used on its own, or in conjunction with its sister project, [Quick](https://github.com/Quick/Quick). To install both Quick and Nimble, follow [the installation instructions in the Quick README](https://github.com/Quick/Quick#how-to-install-quick). Nimble can currently be installed in one of two ways: using CocoaPods, or with git submodules. - The `swift-2.0` branch support Swift 2.0. - The `master` branch of Nimble supports Swift 1.2. - For Swift 1.1 support, use the `swift-1.1` branch. ## Installing Nimble as a Submodule To use Nimble as a submodule to test your iOS or OS X applications, follow these 4 easy steps: 1. Clone the Nimble repository 2. Add Nimble.xcodeproj to the Xcode workspace for your project 3. Link Nimble.framework to your test target 4. Start writing expectations! For more detailed instructions on each of these steps, read [How to Install Quick](https://github.com/Quick/Quick#how-to-install-quick). Ignore the steps involving adding Quick to your project in order to install just Nimble. ## Installing Nimble via CocoaPods To use Nimble in CocoaPods to test your iOS or OS X applications, add Nimble to your podfile and add the ```use_frameworks!``` line to enable Swift support for Cocoapods. ```ruby platform :ios, '8.0' source 'https://github.com/CocoaPods/Specs.git' # Whatever pods you need for your app go here target 'YOUR_APP_NAME_HERE_Tests', :exclusive => true do use_frameworks! # If you're using Swift 2.0 (Xcode 7), use this: pod 'Nimble', '~> 2.0.0' # If you're using Swift 1.2 (Xcode 6), use this: pod 'Nimble', '~> 1.0.0' end ``` Finally run `pod install`. ## Using Nimble without XCTest Nimble is integrated with XCTest to allow it work well when used in Xcode test bundles, however it can also be used in a standalone app. After installing Nimble using one of the above methods, there are two additional steps required to make this work. 1. Create a custom assertion handler and assign an instance of it to the global `NimbleAssertionHandler` variable. For example: ```swift class MyAssertionHandler : AssertionHandler { func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { if (!assertion) { print("Expectation failed: \(message.stringValue)") } } } ``` ```swift // Somewhere before you use any assertions NimbleAssertionHandler = MyAssertionHandler() ``` 2. Add a post-build action to fix an issue with the Swift XCTest support library being unnecessarily copied into your app * Edit your scheme in Xcode, and navigate to Build -> Post-actions * Click the "+" icon and select "New Run Script Action" * Open the "Provide build settings from" dropdown and select your target * Enter the following script contents: ``` rm "${SWIFT_STDLIB_TOOL_DESTINATION_DIR}/libswiftXCTest.dylib" ``` You can now use Nimble assertions in your code and handle failures as you see fit. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/circle.yml ================================================ machine: xcode: version: "7.0" test: override: - NIMBLE_RUNTIME_IOS_SDK_VERSION=9.0 ./test ios - NIMBLE_RUNTIME_OSX_SDK_VERSION=10.10 ./test osx ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/script/release ================================================ #!/usr/bin/env sh REMOTE_BRANCH=master POD_NAME=Nimble PODSPEC=Nimble.podspec GITHUB_TAGS_URL=https://github.com/Quick/Nimble/tags CARTHAGE_FRAMEWORK_NAME=Nimble CARTHAGE=${CARTHAGE:-carthage} POD=${COCOAPODS:-pod} function help { echo "Usage: release VERSION RELEASE_NOTES [-f]" echo echo "VERSION should be the version to release, should not include the 'v' prefix" echo "RELEASE_NOTES should be a file that lists all the release notes for this version" echo " if file does not exist, creates a git-style commit with a diff as a comment" echo echo "FLAGS" echo " -f Forces override of tag" echo echo " Example: ./release 1.0.0-rc.2 ./release-notes.txt" echo echo "HINT: use 'git diff ...HEAD' to build the release notes" echo exit 2 } function die { echo "[ERROR] $@" echo exit 1 } if [ $# -lt 2 ]; then help fi VERSION=$1 RELEASE_NOTES=$2 FORCE_TAG=$3 VERSION_TAG="v$VERSION" echo "-> Verifying Local Directory for Release" if [ -z "`which $CARTHAGE`" ]; then die "Carthage is required to produce a release. Aborting." fi echo " > Carthage is installed" if [ -z "`which $POD`" ]; then die "Cocoapods is required to produce a release. Aborting." fi echo " > Cocoapods is installed" echo " > Is this a reasonable tag?" echo $VERSION_TAG | grep -q "^vv" if [ $? -eq 0 ]; then die "This tag ($VERSION) is an incorrect format. You should remove the 'v' prefix." fi echo $VERSION_TAG | grep -q -E "^v\d+\.\d+\.\d+(-\w+(\.\d)?)?\$" if [ $? -ne 0 ]; then die "This tag ($VERSION) is an incorrect format. It should be in 'v{MAJOR}.{MINOR}.{PATCH}(-{PRERELEASE_NAME}.{PRERELEASE_VERSION})' form." fi echo " > Is this version ($VERSION) unique?" git describe --exact-match "$VERSION_TAG" > /dev/null 2>&1 if [ $? -eq 0 ]; then if [ -z "$FORCE_TAG" ]; then die "This tag ($VERSION) already exists. Aborting. Append '-f' to override" else echo " > NO, but force was specified." fi else echo " > Yes, tag is unique" fi if [ ! -f "$RELEASE_NOTES" ]; then echo " > Failed to find $RELEASE_NOTES. Prompting editor" RELEASE_NOTES=.release-changes LATEST_TAG=`git for-each-ref refs/tags --sort=-refname --format="%(refname:short)" | grep -E "^v\d+\.\d+\.\d+(-\w+(\.\d)?)?\$" | ruby -e 'puts STDIN.read.split("\n").sort { |a,b| Gem::Version.new(a.gsub(/^v/, "")) <=> Gem::Version.new(b.gsub(/^v/, "")) }.last'` echo " > Latest tag ${LATEST_TAG}" echo "${POD_NAME} v$VERSION" > $RELEASE_NOTES echo "================" >> $RELEASE_NOTES echo >> $RELEASE_NOTES echo "# Changelog from ${LATEST_TAG}..HEAD" >> $RELEASE_NOTES git log ${LATEST_TAG}..HEAD | sed -e 's/^/# /' >> $RELEASE_NOTES $EDITOR $RELEASE_NOTES diff -q $RELEASE_NOTES ${RELEASE_NOTES}.backup > /dev/null 2>&1 STATUS=$? rm ${RELEASE_NOTES}.backup if [ $STATUS -eq 0 ]; then rm $RELEASE_NOTES die "No changes in release notes file. Aborting." fi fi echo " > Release notes: $RELEASE_NOTES" if [ ! -f "$PODSPEC" ]; then die "Cannot find podspec: $PODSPEC. Aborting." fi echo " > Podspec exists" git config --get user.signingkey > /dev/null || { echo "[ERROR] No PGP found to sign tag. Aborting." echo echo " Creating a release requires signing the tag for security purposes. This allows users to verify the git cloned tree is from a trusted source." echo " From a security perspective, it is not considered safe to trust the commits (including Author & Signed-off fields). It is easy for any" echo " intermediate between you and the end-users to modify the git repository." echo echo " While not all users may choose to verify the PGP key for tagged releases. It is a good measure to ensure 'this is an official release'" echo " from the official maintainers." echo echo " If you're creating your PGP key for the first time, use RSA with at least 4096 bits." echo echo "Related resources:" echo " - Configuring your system for PGP: https://git-scm.com/book/tr/v2/Git-Tools-Signing-Your-Work" echo " - Why: http://programmers.stackexchange.com/questions/212192/what-are-the-advantages-and-disadvantages-of-cryptographically-signing-commits-a" echo exit 2 } echo " > Found PGP key for git" # Verify cocoapods trunk ownership pod trunk me | grep -q "$POD_NAME" || die "You do not have access to pod repository $POD_NAME. Aborting." echo " > Verified ownership to $POD_NAME pod" echo "--- Releasing version $VERSION (tag: $VERSION_TAG)..." function restore_podspec { if [ -f "${PODSPEC}.backup" ]; then mv -f ${PODSPEC}{.backup,} fi } echo "-> Ensuring no differences to origin/$REMOTE_BRANCH" git fetch origin || die "Failed to fetch origin" git diff --quiet HEAD "origin/$REMOTE_BRANCH" || die "HEAD is not aligned to origin/$REMOTE_BRANCH. Cannot update version safely" echo "-> Building Carthage release" $CARTHAGE build --no-skip-current || die "Failed to build framework for carthage" echo "-> Setting podspec version" cat "$PODSPEC" | grep 's.version' | grep -q "\"$VERSION\"" SET_PODSPEC_VERSION=$? if [ $SET_PODSPEC_VERSION -eq 0 ]; then echo " > Podspec already set to $VERSION. Skipping." else sed -i.backup "s/s.version *= *\".*\"/s.version = \"$VERSION\"/g" "$PODSPEC" || { restore_podspec die "Failed to update version in podspec" } git add ${PODSPEC} || { restore_podspec; die "Failed to add ${PODSPEC} to INDEX"; } git commit -m "Bumping version to $VERSION" || { restore_podspec; die "Failed to push updated version: $VERSION"; } fi if [ -z "$FORCE_TAG" ]; then echo "-> Tagging version" git tag -s "$VERSION_TAG" -F "$RELEASE_NOTES" || die "Failed to tag version" echo "-> Pushing tag to origin" git push origin "$VERSION_TAG" || die "Failed to push tag '$VERSION_TAG' to origin" else echo "-> Tagging version (force)" git tag -f -s "$VERSION_TAG" -F "$RELEASE_NOTES" || die "Failed to tag version" echo "-> Pushing tag to origin (force)" git push origin "$VERSION_TAG" -f || die "Failed to push tag '$VERSION_TAG' to origin" fi if [ $SET_PODSPEC_VERSION -ne 0 ]; then rm $RELEASE_NOTES git push origin "$REMOTE_BRANCH" || die "Failed to push to origin" echo " > Pushed version to origin" fi echo echo "---------------- Released as $VERSION_TAG ----------------" echo echo "Archiving carthage release..." $CARTHAGE archive "$CARTHAGE_FRAMEWORK_NAME" || die "Failed to archive framework for carthage" echo echo "Pushing to pod trunk..." $POD trunk push "$PODSPEC" echo echo "================ Finalizing the Release ================" echo echo " - Go to $GITHUB_TAGS_URL and mark this as a release." echo " - Paste the contents of $RELEASE_NOTES into the release notes. Tweak for Github styling." echo " - Attach ${CARTHAGE_FRAMEWORK_NAME}.framework.zip to it." echo " - Announce!" rm ${PODSPEC}.backup ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Externals/Nimble/test ================================================ #!/bin/sh BUILD_DIR=`pwd`/build LATEST_IOS_SDK_VERSION=`xcodebuild -showsdks | grep iphonesimulator | cut -d ' ' -f 4 | ruby -e 'puts STDIN.read.chomp.split("\n").last'` LATEST_OSX_SDK_VERSION=`xcodebuild -showsdks | grep 'macosx' | cut -d ' ' -f 3 | ruby -e 'puts STDIN.read.chomp.split("\n").last'` BUILD_IOS_SDK_VERSION=${NIMBLE_BUILD_IOS_SDK_VERSION:-$LATEST_IOS_SDK_VERSION} RUNTIME_IOS_SDK_VERSION=${NIMBLE_RUNTIME_IOS_SDK_VERSION:-$LATEST_IOS_SDK_VERSION} BUILD_OSX_SDK_VERSION=${NIMBLE_BUILD_OSX_SDK_VERSION:-$LATEST_OSX_SDK_VERSION} set -e GREEN="\x1B[01;92m" CLEAR="\x1B[0m" function color_if_overridden { local actual=$1 local env_var=$2 if [ -z "$env_var" ]; then printf "$actual" else printf "$GREEN$actual$CLEAR" fi } function print_env { echo "=== Environment ===" echo " iOS:" echo " Latest iOS SDK: $LATEST_IOS_SDK_VERSION" echo " Building with iOS SDK: `color_if_overridden $BUILD_IOS_SDK_VERSION $NIMBLE_BUILD_IOS_SDK_VERSION`" echo " Running with iOS SDK: `color_if_overridden $RUNTIME_IOS_SDK_VERSION $NIMBLE_RUNTIME_IOS_SDK_VERSION`" echo echo " Mac OS X:" echo " Latest OS X SDK: $LATEST_OSX_SDK_VERSION" echo " Building with OS X SDK: `color_if_overridden $BUILD_OSX_SDK_VERSION $NIMBLE_BUILD_OSX_SDK_VERSION`" echo echo "======= END =======" echo } function run { echo "$GREEN==>$CLEAR $@" "$@" } function test_ios { run osascript -e 'tell app "iOS Simulator" to quit' run xcodebuild -project Nimble.xcodeproj -scheme "Nimble-iOS" -configuration "Debug" -sdk "iphonesimulator$BUILD_IOS_SDK_VERSION" -destination "name=iPad Air,OS=$RUNTIME_IOS_SDK_VERSION" build test run osascript -e 'tell app "iOS Simulator" to quit' run xcodebuild -project Nimble.xcodeproj -scheme "Nimble-iOS" -configuration "Debug" -sdk "iphonesimulator$BUILD_IOS_SDK_VERSION" -destination "name=iPhone 5s,OS=$RUNTIME_IOS_SDK_VERSION" build test } function test_osx { run xcodebuild -project Nimble.xcodeproj -scheme "Nimble-OSX" -configuration "Debug" -sdk "macosx$BUILD_OSX_SDK_VERSION" build test } function test() { test_ios test_osx } function clean { run rm -rf ~/Library/Developer/Xcode/DerivedData\; true } function help { echo "Usage: $0 COMMANDS" echo echo "COMMANDS:" echo " clean - Cleans the derived data directory of Xcode. Assumes default location" echo " ios - Runs the tests as an iOS device" echo " osx - Runs the tests on Mac OS X 10.10 (Yosemite and newer only)" echo " all - Runs both ios and osx tests" echo " help - Displays this help" echo exit 1 } function main { print_env for arg in $@ do case "$arg" in clean) clean ;; ios) test_ios ;; osx) test_osx ;; test) test ;; all) test ;; help) help ;; esac done if [ $# -eq 0 ]; then clean test fi } main $@ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2014, Quick Team Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/Callsite.swift ================================================ /** An object encapsulating the file and line number at which a particular example is defined. */ final public class Callsite: NSObject { /** The absolute path of the file in which an example is defined. */ public let file: String /** The line number on which an example is defined. */ public let line: UInt internal init(file: String, line: UInt) { self.file = file self.line = line } } /** Returns a boolean indicating whether two Callsite objects are equal. If two callsites are in the same file and on the same line, they must be equal. */ public func ==(lhs: Callsite, rhs: Callsite) -> Bool { return lhs.file == rhs.file && lhs.line == rhs.line } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/Configuration/Configuration.swift ================================================ /** A closure that temporarily exposes a Configuration object within the scope of the closure. */ public typealias QuickConfigurer = (configuration: Configuration) -> () /** A closure that, given metadata about an example, returns a boolean value indicating whether that example should be run. */ public typealias ExampleFilter = (example: Example) -> Bool /** A configuration encapsulates various options you can use to configure Quick's behavior. */ final public class Configuration: NSObject { internal let exampleHooks = ExampleHooks() internal let suiteHooks = SuiteHooks() internal var exclusionFilters: [ExampleFilter] = [{ example in if let pending = example.filterFlags[Filter.pending] { return pending } else { return false } }] internal var inclusionFilters: [ExampleFilter] = [{ example in if let focused = example.filterFlags[Filter.focused] { return focused } else { return false } }] /** Run all examples if none match the configured filters. True by default. */ public var runAllWhenEverythingFiltered = true /** Registers an inclusion filter. All examples are filtered using all inclusion filters. The remaining examples are run. If no examples remain, all examples are run. - parameter filter: A filter that, given an example, returns a value indicating whether that example should be included in the examples that are run. */ public func include(filter: ExampleFilter) { inclusionFilters.append(filter) } /** Registers an exclusion filter. All examples that remain after being filtered by the inclusion filters are then filtered via all exclusion filters. - parameter filter: A filter that, given an example, returns a value indicating whether that example should be excluded from the examples that are run. */ public func exclude(filter: ExampleFilter) { exclusionFilters.append(filter) } /** Identical to Quick.Configuration.beforeEach, except the closure is provided with metadata on the example that the closure is being run prior to. */ @objc(beforeEachWithMetadata:) public func beforeEach(closure: BeforeExampleWithMetadataClosure) { exampleHooks.appendBefore(closure) } /** Like Quick.DSL.beforeEach, this configures Quick to execute the given closure before each example that is run. The closure passed to this method is executed before each example Quick runs, globally across the test suite. You may call this method multiple times across mulitple +[QuickConfigure configure:] methods in order to define several closures to run before each example. Note that, since Quick makes no guarantee as to the order in which +[QuickConfiguration configure:] methods are evaluated, there is no guarantee as to the order in which beforeEach closures are evaluated either. Mulitple beforeEach defined on a single configuration, however, will be executed in the order they're defined. - parameter closure: The closure to be executed before each example in the test suite. */ public func beforeEach(closure: BeforeExampleClosure) { exampleHooks.appendBefore(closure) } /** Identical to Quick.Configuration.afterEach, except the closure is provided with metadata on the example that the closure is being run after. */ @objc(afterEachWithMetadata:) public func afterEach(closure: AfterExampleWithMetadataClosure) { exampleHooks.appendAfter(closure) } /** Like Quick.DSL.afterEach, this configures Quick to execute the given closure after each example that is run. The closure passed to this method is executed after each example Quick runs, globally across the test suite. You may call this method multiple times across mulitple +[QuickConfigure configure:] methods in order to define several closures to run after each example. Note that, since Quick makes no guarantee as to the order in which +[QuickConfiguration configure:] methods are evaluated, there is no guarantee as to the order in which afterEach closures are evaluated either. Mulitple afterEach defined on a single configuration, however, will be executed in the order they're defined. - parameter closure: The closure to be executed before each example in the test suite. */ public func afterEach(closure: AfterExampleClosure) { exampleHooks.appendAfter(closure) } /** Like Quick.DSL.beforeSuite, this configures Quick to execute the given closure prior to any and all examples that are run. The two methods are functionally equivalent. */ public func beforeSuite(closure: BeforeSuiteClosure) { suiteHooks.appendBefore(closure) } /** Like Quick.DSL.afterSuite, this configures Quick to execute the given closure after all examples have been run. The two methods are functionally equivalent. */ public func afterSuite(closure: AfterSuiteClosure) { suiteHooks.appendAfter(closure) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/Configuration/QuickConfiguration.h ================================================ #import @class Configuration; /** Subclass QuickConfiguration and override the +[QuickConfiguration configure:] method in order to configure how Quick behaves when running specs, or to define shared examples that are used across spec files. */ @interface QuickConfiguration : NSObject /** This method is executed on each subclass of this class before Quick runs any examples. You may override this method on as many subclasses as you like, but there is no guarantee as to the order in which these methods are executed. You can override this method in order to: 1. Configure how Quick behaves, by modifying properties on the Configuration object. Setting the same properties in several methods has undefined behavior. 2. Define shared examples using `sharedExamples`. @param configuration A mutable object that is used to configure how Quick behaves on a framework level. For details on all the options, see the documentation in Configuration.swift. */ + (void)configure:(Configuration *)configuration; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/Configuration/QuickConfiguration.m ================================================ #import "QuickConfiguration.h" #import "World.h" #import typedef void (^QCKClassEnumerationBlock)(Class klass); /** Finds all direct subclasses of the given class and passes them to the block provided. The classes are iterated over in the order that objc_getClassList returns them. @param klass The base class to find subclasses of. @param block A block that takes a Class. This block will be executed once for each subclass of klass. */ void qck_enumerateSubclasses(Class klass, QCKClassEnumerationBlock block) { Class *classes = NULL; int classesCount = objc_getClassList(NULL, 0); if (classesCount > 0) { classes = (Class *)calloc(sizeof(Class), classesCount); classesCount = objc_getClassList(classes, classesCount); Class subclass, superclass; for(int i = 0; i < classesCount; i++) { subclass = classes[i]; superclass = class_getSuperclass(subclass); if (superclass == klass && block) { block(subclass); } } free(classes); } } @implementation QuickConfiguration #pragma mark - Object Lifecycle /** QuickConfiguration is not meant to be instantiated; it merely provides a hook for users to configure how Quick behaves. Raise an exception if an instance of QuickConfiguration is created. */ - (instancetype)init { NSString *className = NSStringFromClass([self class]); NSString *selectorName = NSStringFromSelector(@selector(configure:)); [NSException raise:NSInternalInconsistencyException format:@"%@ is not meant to be instantiated; " @"subclass %@ and override %@ to configure Quick.", className, className, selectorName]; return nil; } #pragma mark - NSObject Overrides /** Hook into when QuickConfiguration is initialized in the runtime in order to call +[QuickConfiguration configure:] on each of its subclasses. */ + (void)initialize { // Only enumerate over the subclasses of QuickConfiguration, not any of its subclasses. if ([self class] == [QuickConfiguration class]) { // Only enumerate over subclasses once, even if +[QuickConfiguration initialize] // were to be called several times. This is necessary because +[QuickSpec initialize] // manually calls +[QuickConfiguration initialize]. static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ qck_enumerateSubclasses([QuickConfiguration class], ^(__unsafe_unretained Class klass) { [[World sharedWorld] configure:^(Configuration *configuration) { [klass configure:configuration]; }]; }); [[World sharedWorld] finalizeConfiguration]; }); } } #pragma mark - Public Interface + (void)configure:(Configuration *)configuration { } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/DSL/DSL.swift ================================================ /** Defines a closure to be run prior to any examples in the test suite. You may define an unlimited number of these closures, but there is no guarantee as to the order in which they're run. If the test suite crashes before the first example is run, this closure will not be executed. - parameter closure: The closure to be run prior to any examples in the test suite. */ public func beforeSuite(closure: BeforeSuiteClosure) { World.sharedWorld().beforeSuite(closure) } /** Defines a closure to be run after all of the examples in the test suite. You may define an unlimited number of these closures, but there is no guarantee as to the order in which they're run. If the test suite crashes before all examples are run, this closure will not be executed. - parameter closure: The closure to be run after all of the examples in the test suite. */ public func afterSuite(closure: AfterSuiteClosure) { World.sharedWorld().afterSuite(closure) } /** Defines a group of shared examples. These examples can be re-used in several locations by using the `itBehavesLike` function. - parameter name: The name of the shared example group. This must be unique across all shared example groups defined in a test suite. - parameter closure: A closure containing the examples. This behaves just like an example group defined using `describe` or `context`--the closure may contain any number of `beforeEach` and `afterEach` closures, as well as any number of examples (defined using `it`). */ public func sharedExamples(name: String, closure: () -> ()) { World.sharedWorld().sharedExamples(name, closure: { (NSDictionary) in closure() }) } /** Defines a group of shared examples. These examples can be re-used in several locations by using the `itBehavesLike` function. - parameter name: The name of the shared example group. This must be unique across all shared example groups defined in a test suite. - parameter closure: A closure containing the examples. This behaves just like an example group defined using `describe` or `context`--the closure may contain any number of `beforeEach` and `afterEach` closures, as well as any number of examples (defined using `it`). The closure takes a SharedExampleContext as an argument. This context is a function that can be executed to retrieve parameters passed in via an `itBehavesLike` function. */ public func sharedExamples(name: String, closure: SharedExampleClosure) { World.sharedWorld().sharedExamples(name, closure: closure) } /** Defines an example group. Example groups are logical groupings of examples. Example groups can share setup and teardown code. - parameter description: An arbitrary string describing the example group. - parameter closure: A closure that can contain other examples. - parameter flags: A mapping of string keys to booleans that can be used to filter examples or example groups. */ public func describe(description: String, flags: FilterFlags = [:], closure: () -> ()) { World.sharedWorld().describe(description, flags: flags, closure: closure) } /** Defines an example group. Equivalent to `describe`. */ public func context(description: String, flags: FilterFlags = [:], closure: () -> ()) { describe(description, flags: flags, closure: closure) } /** Defines a closure to be run prior to each example in the current example group. This closure is not run for pending or otherwise disabled examples. An example group may contain an unlimited number of beforeEach. They'll be run in the order they're defined, but you shouldn't rely on that behavior. - parameter closure: The closure to be run prior to each example. */ public func beforeEach(closure: BeforeExampleClosure) { World.sharedWorld().beforeEach(closure) } /** Identical to Quick.DSL.beforeEach, except the closure is provided with metadata on the example that the closure is being run prior to. */ public func beforeEach(closure: BeforeExampleWithMetadataClosure) { World.sharedWorld().beforeEach(closure: closure) } /** Defines a closure to be run after each example in the current example group. This closure is not run for pending or otherwise disabled examples. An example group may contain an unlimited number of afterEach. They'll be run in the order they're defined, but you shouldn't rely on that behavior. - parameter closure: The closure to be run after each example. */ public func afterEach(closure: AfterExampleClosure) { World.sharedWorld().afterEach(closure) } /** Identical to Quick.DSL.afterEach, except the closure is provided with metadata on the example that the closure is being run after. */ public func afterEach(closure: AfterExampleWithMetadataClosure) { World.sharedWorld().afterEach(closure: closure) } /** Defines an example. Examples use assertions to demonstrate how code should behave. These are like "tests" in XCTest. - parameter description: An arbitrary string describing what the example is meant to specify. - parameter closure: A closure that can contain assertions. - parameter flags: A mapping of string keys to booleans that can be used to filter examples or example groups. Empty by default. - parameter file: The absolute path to the file containing the example. A sensible default is provided. - parameter line: The line containing the example. A sensible default is provided. */ public func it(description: String, flags: FilterFlags = [:], file: String = __FILE__, line: UInt = __LINE__, closure: () -> ()) { World.sharedWorld().it(description, flags: flags, file: file, line: line, closure: closure) } /** Inserts the examples defined using a `sharedExamples` function into the current example group. The shared examples are executed at this location, as if they were written out manually. - parameter name: The name of the shared examples group to be executed. This must be identical to the name of a shared examples group defined using `sharedExamples`. If there are no shared examples that match the name given, an exception is thrown and the test suite will crash. - parameter flags: A mapping of string keys to booleans that can be used to filter examples or example groups. Empty by default. - parameter file: The absolute path to the file containing the current example group. A sensible default is provided. - parameter line: The line containing the current example group. A sensible default is provided. */ public func itBehavesLike(name: String, flags: FilterFlags = [:], file: String = __FILE__, line: UInt = __LINE__) { itBehavesLike(name, flags: flags, file: file, line: line, sharedExampleContext: { return [:] }) } /** Inserts the examples defined using a `sharedExamples` function into the current example group. The shared examples are executed at this location, as if they were written out manually. This function also passes those shared examples a context that can be evaluated to give the shared examples extra information on the subject of the example. - parameter name: The name of the shared examples group to be executed. This must be identical to the name of a shared examples group defined using `sharedExamples`. If there are no shared examples that match the name given, an exception is thrown and the test suite will crash. - parameter sharedExampleContext: A closure that, when evaluated, returns key-value pairs that provide the shared examples with extra information on the subject of the example. - parameter flags: A mapping of string keys to booleans that can be used to filter examples or example groups. Empty by default. - parameter file: The absolute path to the file containing the current example group. A sensible default is provided. - parameter line: The line containing the current example group. A sensible default is provided. */ public func itBehavesLike(name: String, flags: FilterFlags = [:], file: String = __FILE__, line: UInt = __LINE__, sharedExampleContext: SharedExampleContext) { World.sharedWorld().itBehavesLike(name, sharedExampleContext: sharedExampleContext, flags: flags, file: file, line: line) } /** Defines an example or example group that should not be executed. Use `pending` to temporarily disable examples or groups that should not be run yet. - parameter description: An arbitrary string describing the example or example group. - parameter closure: A closure that will not be evaluated. */ public func pending(description: String, closure: () -> ()) { World.sharedWorld().pending(description, closure: closure) } /** Use this to quickly mark a `describe` closure as pending. This disables all examples within the closure. */ public func xdescribe(description: String, flags: FilterFlags, closure: () -> ()) { World.sharedWorld().xdescribe(description, flags: flags, closure: closure) } /** Use this to quickly mark a `context` closure as pending. This disables all examples within the closure. */ public func xcontext(description: String, flags: FilterFlags, closure: () -> ()) { xdescribe(description, flags: flags, closure: closure) } /** Use this to quickly mark an `it` closure as pending. This disables the example and ensures the code within the closure is never run. */ public func xit(description: String, flags: FilterFlags = [:], file: String = __FILE__, line: UInt = __LINE__, closure: () -> ()) { World.sharedWorld().xit(description, flags: flags, file: file, line: line, closure: closure) } /** Use this to quickly focus a `describe` closure, focusing the examples in the closure. If any examples in the test suite are focused, only those examples are executed. This trumps any explicitly focused or unfocused examples within the closure--they are all treated as focused. */ public func fdescribe(description: String, flags: FilterFlags = [:], closure: () -> ()) { World.sharedWorld().fdescribe(description, flags: flags, closure: closure) } /** Use this to quickly focus a `context` closure. Equivalent to `fdescribe`. */ public func fcontext(description: String, flags: FilterFlags = [:], closure: () -> ()) { fdescribe(description, flags: flags, closure: closure) } /** Use this to quickly focus an `it` closure, focusing the example. If any examples in the test suite are focused, only those examples are executed. */ public func fit(description: String, flags: FilterFlags = [:], file: String = __FILE__, line: UInt = __LINE__, closure: () -> ()) { World.sharedWorld().fit(description, flags: flags, file: file, line: line, closure: closure) } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/DSL/QCKDSL.h ================================================ #import @class ExampleMetadata; /** Provides a hook for Quick to be configured before any examples are run. Within this scope, override the +[QuickConfiguration configure:] method to set properties on a configuration object to customize Quick behavior. For details, see the documentation for Configuraiton.swift. @param name The name of the configuration class. Like any Objective-C class name, this must be unique to the current runtime environment. */ #define QuickConfigurationBegin(name) \ @interface name : QuickConfiguration; @end \ @implementation name \ /** Marks the end of a Quick configuration. Make sure you put this after `QuickConfigurationBegin`. */ #define QuickConfigurationEnd \ @end \ /** Defines a new QuickSpec. Define examples and example groups within the space between this and `QuickSpecEnd`. @param name The name of the spec class. Like any Objective-C class name, this must be unique to the current runtime environment. */ #define QuickSpecBegin(name) \ @interface name : QuickSpec; @end \ @implementation name \ - (void)spec { \ /** Marks the end of a QuickSpec. Make sure you put this after `QuickSpecBegin`. */ #define QuickSpecEnd \ } \ @end \ typedef NSDictionary *(^QCKDSLSharedExampleContext)(void); typedef void (^QCKDSLSharedExampleBlock)(QCKDSLSharedExampleContext); typedef void (^QCKDSLEmptyBlock)(void); typedef void (^QCKDSLExampleMetadataBlock)(ExampleMetadata *exampleMetadata); #define QUICK_EXPORT FOUNDATION_EXPORT QUICK_EXPORT void qck_beforeSuite(QCKDSLEmptyBlock closure); QUICK_EXPORT void qck_afterSuite(QCKDSLEmptyBlock closure); QUICK_EXPORT void qck_sharedExamples(NSString *name, QCKDSLSharedExampleBlock closure); QUICK_EXPORT void qck_describe(NSString *description, QCKDSLEmptyBlock closure); QUICK_EXPORT void qck_context(NSString *description, QCKDSLEmptyBlock closure); QUICK_EXPORT void qck_beforeEach(QCKDSLEmptyBlock closure); QUICK_EXPORT void qck_beforeEachWithMetadata(QCKDSLExampleMetadataBlock closure); QUICK_EXPORT void qck_afterEach(QCKDSLEmptyBlock closure); QUICK_EXPORT void qck_afterEachWithMetadata(QCKDSLExampleMetadataBlock closure); QUICK_EXPORT void qck_pending(NSString *description, QCKDSLEmptyBlock closure); QUICK_EXPORT void qck_xdescribe(NSString *description, QCKDSLEmptyBlock closure); QUICK_EXPORT void qck_xcontext(NSString *description, QCKDSLEmptyBlock closure); QUICK_EXPORT void qck_fdescribe(NSString *description, QCKDSLEmptyBlock closure); QUICK_EXPORT void qck_fcontext(NSString *description, QCKDSLEmptyBlock closure); #ifndef QUICK_DISABLE_SHORT_SYNTAX /** Defines a closure to be run prior to any examples in the test suite. You may define an unlimited number of these closures, but there is no guarantee as to the order in which they're run. If the test suite crashes before the first example is run, this closure will not be executed. @param closure The closure to be run prior to any examples in the test suite. */ static inline void beforeSuite(QCKDSLEmptyBlock closure) { qck_beforeSuite(closure); } /** Defines a closure to be run after all of the examples in the test suite. You may define an unlimited number of these closures, but there is no guarantee as to the order in which they're run. If the test suite crashes before all examples are run, this closure will not be executed. @param closure The closure to be run after all of the examples in the test suite. */ static inline void afterSuite(QCKDSLEmptyBlock closure) { qck_afterSuite(closure); } /** Defines a group of shared examples. These examples can be re-used in several locations by using the `itBehavesLike` function. @param name The name of the shared example group. This must be unique across all shared example groups defined in a test suite. @param closure A closure containing the examples. This behaves just like an example group defined using `describe` or `context`--the closure may contain any number of `beforeEach` and `afterEach` closures, as well as any number of examples (defined using `it`). */ static inline void sharedExamples(NSString *name, QCKDSLSharedExampleBlock closure) { qck_sharedExamples(name, closure); } /** Defines an example group. Example groups are logical groupings of examples. Example groups can share setup and teardown code. @param description An arbitrary string describing the example group. @param closure A closure that can contain other examples. */ static inline void describe(NSString *description, QCKDSLEmptyBlock closure) { qck_describe(description, closure); } /** Defines an example group. Equivalent to `describe`. */ static inline void context(NSString *description, QCKDSLEmptyBlock closure) { qck_context(description, closure); } /** Defines a closure to be run prior to each example in the current example group. This closure is not run for pending or otherwise disabled examples. An example group may contain an unlimited number of beforeEach. They'll be run in the order they're defined, but you shouldn't rely on that behavior. @param closure The closure to be run prior to each example. */ static inline void beforeEach(QCKDSLEmptyBlock closure) { qck_beforeEach(closure); } /** Identical to QCKDSL.beforeEach, except the closure is provided with metadata on the example that the closure is being run prior to. */ static inline void beforeEachWithMetadata(QCKDSLExampleMetadataBlock closure) { qck_beforeEachWithMetadata(closure); } /** Defines a closure to be run after each example in the current example group. This closure is not run for pending or otherwise disabled examples. An example group may contain an unlimited number of afterEach. They'll be run in the order they're defined, but you shouldn't rely on that behavior. @param closure The closure to be run after each example. */ static inline void afterEach(QCKDSLEmptyBlock closure) { qck_afterEach(closure); } /** Identical to QCKDSL.afterEach, except the closure is provided with metadata on the example that the closure is being run after. */ static inline void afterEachWithMetadata(QCKDSLExampleMetadataBlock closure) { qck_afterEachWithMetadata(closure); } /** Defines an example or example group that should not be executed. Use `pending` to temporarily disable examples or groups that should not be run yet. @param description An arbitrary string describing the example or example group. @param closure A closure that will not be evaluated. */ static inline void pending(NSString *description, QCKDSLEmptyBlock closure) { qck_pending(description, closure); } /** Use this to quickly mark a `describe` block as pending. This disables all examples within the block. */ static inline void xdescribe(NSString *description, QCKDSLEmptyBlock closure) { qck_xdescribe(description, closure); } /** Use this to quickly mark a `context` block as pending. This disables all examples within the block. */ static inline void xcontext(NSString *description, QCKDSLEmptyBlock closure) { qck_xcontext(description, closure); } /** Use this to quickly focus a `describe` block, focusing the examples in the block. If any examples in the test suite are focused, only those examples are executed. This trumps any explicitly focused or unfocused examples within the block--they are all treated as focused. */ static inline void fdescribe(NSString *description, QCKDSLEmptyBlock closure) { qck_fdescribe(description, closure); } /** Use this to quickly focus a `context` block. Equivalent to `fdescribe`. */ static inline void fcontext(NSString *description, QCKDSLEmptyBlock closure) { qck_fcontext(description, closure); } #define it qck_it #define xit qck_xit #define fit qck_fit #define itBehavesLike qck_itBehavesLike #define xitBehavesLike qck_xitBehavesLike #define fitBehavesLike qck_fitBehavesLike #endif #define qck_it qck_it_builder(@{}, @(__FILE__), __LINE__) #define qck_xit qck_it_builder(@{Filter.pending: @YES}, @(__FILE__), __LINE__) #define qck_fit qck_it_builder(@{Filter.focused: @YES}, @(__FILE__), __LINE__) #define qck_itBehavesLike qck_itBehavesLike_builder(@{}, @(__FILE__), __LINE__) #define qck_xitBehavesLike qck_itBehavesLike_builder(@{Filter.pending: @YES}, @(__FILE__), __LINE__) #define qck_fitBehavesLike qck_itBehavesLike_builder(@{Filter.focused: @YES}, @(__FILE__), __LINE__) typedef void (^QCKItBlock)(NSString *description, QCKDSLEmptyBlock closure); typedef void (^QCKItBehavesLikeBlock)(NSString *description, QCKDSLSharedExampleContext context); QUICK_EXPORT QCKItBlock qck_it_builder(NSDictionary *flags, NSString *file, NSUInteger line); QUICK_EXPORT QCKItBehavesLikeBlock qck_itBehavesLike_builder(NSDictionary *flags, NSString *file, NSUInteger line); ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/DSL/QCKDSL.m ================================================ #import "QCKDSL.h" #import "World.h" #import "World+DSL.h" void qck_beforeSuite(QCKDSLEmptyBlock closure) { [[World sharedWorld] beforeSuite:closure]; } void qck_afterSuite(QCKDSLEmptyBlock closure) { [[World sharedWorld] afterSuite:closure]; } void qck_sharedExamples(NSString *name, QCKDSLSharedExampleBlock closure) { [[World sharedWorld] sharedExamples:name closure:closure]; } void qck_describe(NSString *description, QCKDSLEmptyBlock closure) { [[World sharedWorld] describe:description flags:@{} closure:closure]; } void qck_context(NSString *description, QCKDSLEmptyBlock closure) { qck_describe(description, closure); } void qck_beforeEach(QCKDSLEmptyBlock closure) { [[World sharedWorld] beforeEach:closure]; } void qck_beforeEachWithMetadata(QCKDSLExampleMetadataBlock closure) { [[World sharedWorld] beforeEachWithMetadata:closure]; } void qck_afterEach(QCKDSLEmptyBlock closure) { [[World sharedWorld] afterEach:closure]; } void qck_afterEachWithMetadata(QCKDSLExampleMetadataBlock closure) { [[World sharedWorld] afterEachWithMetadata:closure]; } QCKItBlock qck_it_builder(NSDictionary *flags, NSString *file, NSUInteger line) { return ^(NSString *description, QCKDSLEmptyBlock closure) { [[World sharedWorld] itWithDescription:description flags:flags file:file line:line closure:closure]; }; } QCKItBehavesLikeBlock qck_itBehavesLike_builder(NSDictionary *flags, NSString *file, NSUInteger line) { return ^(NSString *name, QCKDSLSharedExampleContext context) { [[World sharedWorld] itBehavesLikeSharedExampleNamed:name sharedExampleContext:context flags:flags file:file line:line]; }; } void qck_pending(NSString *description, QCKDSLEmptyBlock closure) { [[World sharedWorld] pending:description closure:closure]; } void qck_xdescribe(NSString *description, QCKDSLEmptyBlock closure) { [[World sharedWorld] xdescribe:description flags:@{} closure:closure]; } void qck_xcontext(NSString *description, QCKDSLEmptyBlock closure) { qck_xdescribe(description, closure); } void qck_fdescribe(NSString *description, QCKDSLEmptyBlock closure) { [[World sharedWorld] fdescribe:description flags:@{} closure:closure]; } void qck_fcontext(NSString *description, QCKDSLEmptyBlock closure) { qck_fdescribe(description, closure); } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/DSL/World+DSL.h ================================================ #import @interface World (SWIFT_EXTENSION(Quick)) - (void)beforeSuite:(void (^ __nonnull)(void))closure; - (void)afterSuite:(void (^ __nonnull)(void))closure; - (void)sharedExamples:(NSString * __nonnull)name closure:(void (^ __nonnull)(NSDictionary * __nonnull (^ __nonnull)(void)))closure; - (void)describe:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags closure:(void (^ __nonnull)(void))closure; - (void)context:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags closure:(void (^ __nonnull)(void))closure; - (void)fdescribe:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags closure:(void (^ __nonnull)(void))closure; - (void)xdescribe:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags closure:(void (^ __nonnull)(void))closure; - (void)beforeEach:(void (^ __nonnull)(void))closure; - (void)beforeEachWithMetadata:(void (^ __nonnull)(ExampleMetadata * __nonnull))closure; - (void)afterEach:(void (^ __nonnull)(void))closure; - (void)afterEachWithMetadata:(void (^ __nonnull)(ExampleMetadata * __nonnull))closure; - (void)itWithDescription:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags file:(NSString * __nonnull)file line:(NSUInteger)line closure:(void (^ __nonnull)(void))closure; - (void)fitWithDescription:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags file:(NSString * __nonnull)file line:(NSUInteger)line closure:(void (^ __nonnull)(void))closure; - (void)xitWithDescription:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags file:(NSString * __nonnull)file line:(NSUInteger)line closure:(void (^ __nonnull)(void))closure; - (void)itBehavesLikeSharedExampleNamed:(NSString * __nonnull)name sharedExampleContext:(NSDictionary * __nonnull (^ __nonnull)(void))sharedExampleContext flags:(NSDictionary * __nonnull)flags file:(NSString * __nonnull)file line:(NSUInteger)line; - (void)pending:(NSString * __nonnull)description closure:(void (^ __nonnull)(void))closure; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/DSL/World+DSL.swift ================================================ /** Adds methods to World to support top-level DSL functions (Swift) and macros (Objective-C). These functions map directly to the DSL that test writers use in their specs. */ extension World { internal func beforeSuite(closure: BeforeSuiteClosure) { suiteHooks.appendBefore(closure) } internal func afterSuite(closure: AfterSuiteClosure) { suiteHooks.appendAfter(closure) } internal func sharedExamples(name: String, closure: SharedExampleClosure) { registerSharedExample(name, closure: closure) } internal func describe(description: String, flags: FilterFlags, closure: () -> ()) { let group = ExampleGroup(description: description, flags: flags) currentExampleGroup!.appendExampleGroup(group) currentExampleGroup = group closure() currentExampleGroup = group.parent } internal func context(description: String, flags: FilterFlags, closure: () -> ()) { self.describe(description, flags: flags, closure: closure) } internal func fdescribe(description: String, flags: FilterFlags, closure: () -> ()) { var focusedFlags = flags focusedFlags[Filter.focused] = true self.describe(description, flags: focusedFlags, closure: closure) } internal func xdescribe(description: String, flags: FilterFlags, closure: () -> ()) { var pendingFlags = flags pendingFlags[Filter.pending] = true self.describe(description, flags: pendingFlags, closure: closure) } internal func beforeEach(closure: BeforeExampleClosure) { currentExampleGroup!.hooks.appendBefore(closure) } @objc(beforeEachWithMetadata:) internal func beforeEach(closure closure: BeforeExampleWithMetadataClosure) { currentExampleGroup!.hooks.appendBefore(closure) } internal func afterEach(closure: AfterExampleClosure) { currentExampleGroup!.hooks.appendAfter(closure) } @objc(afterEachWithMetadata:) internal func afterEach(closure closure: AfterExampleWithMetadataClosure) { currentExampleGroup!.hooks.appendAfter(closure) } @objc(itWithDescription:flags:file:line:closure:) internal func it(description: String, flags: FilterFlags, file: String, line: UInt, closure: () -> ()) { let callsite = Callsite(file: file, line: line) let example = Example(description: description, callsite: callsite, flags: flags, closure: closure) currentExampleGroup!.appendExample(example) } @objc(fitWithDescription:flags:file:line:closure:) internal func fit(description: String, flags: FilterFlags, file: String, line: UInt, closure: () -> ()) { var focusedFlags = flags focusedFlags[Filter.focused] = true self.it(description, flags: focusedFlags, file: file, line: line, closure: closure) } @objc(xitWithDescription:flags:file:line:closure:) internal func xit(description: String, flags: FilterFlags, file: String, line: UInt, closure: () -> ()) { var pendingFlags = flags pendingFlags[Filter.pending] = true self.it(description, flags: pendingFlags, file: file, line: line, closure: closure) } @objc(itBehavesLikeSharedExampleNamed:sharedExampleContext:flags:file:line:) internal func itBehavesLike(name: String, sharedExampleContext: SharedExampleContext, flags: FilterFlags, file: String, line: UInt) { let callsite = Callsite(file: file, line: line) let closure = World.sharedWorld().sharedExample(name) let group = ExampleGroup(description: name, flags: flags) currentExampleGroup!.appendExampleGroup(group) currentExampleGroup = group closure(sharedExampleContext) currentExampleGroup!.walkDownExamples { (example: Example) in example.isSharedExample = true example.callsite = callsite } currentExampleGroup = group.parent } internal func pending(description: String, closure: () -> ()) { print("Pending: \(description)") } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/Example.swift ================================================ private var numberOfExamplesRun = 0 /** Examples, defined with the `it` function, use assertions to demonstrate how code should behave. These are like "tests" in XCTest. */ final public class Example: NSObject { /** A boolean indicating whether the example is a shared example; i.e.: whether it is an example defined with `itBehavesLike`. */ public var isSharedExample = false /** The site at which the example is defined. This must be set correctly in order for Xcode to highlight the correct line in red when reporting a failure. */ public var callsite: Callsite weak internal var group: ExampleGroup? private let internalDescription: String private let closure: () -> () private let flags: FilterFlags internal init(description: String, callsite: Callsite, flags: FilterFlags, closure: () -> ()) { self.internalDescription = description self.closure = closure self.callsite = callsite self.flags = flags } public override var description: String { return internalDescription } /** The example name. A name is a concatenation of the name of the example group the example belongs to, followed by the description of the example itself. The example name is used to generate a test method selector to be displayed in Xcode's test navigator. */ public var name: String { switch group!.name { case .Some(let groupName): return "\(groupName), \(description)" case .None: return description } } /** Executes the example closure, as well as all before and after closures defined in the its surrounding example groups. */ public func run() { let world = World.sharedWorld() if numberOfExamplesRun == 0 { world.suiteHooks.executeBefores() } let exampleMetadata = ExampleMetadata(example: self, exampleIndex: numberOfExamplesRun) world.currentExampleMetadata = exampleMetadata world.exampleHooks.executeBefores(exampleMetadata) for before in group!.befores { before(exampleMetadata: exampleMetadata) } closure() for after in group!.afters { after(exampleMetadata: exampleMetadata) } world.exampleHooks.executeAfters(exampleMetadata) ++numberOfExamplesRun if !world.isRunningAdditionalSuites && numberOfExamplesRun >= world.exampleCount { world.suiteHooks.executeAfters() } } /** Evaluates the filter flags set on this example and on the example groups this example belongs to. Flags set on the example are trumped by flags on the example group it belongs to. Flags on inner example groups are trumped by flags on outer example groups. */ internal var filterFlags: FilterFlags { var aggregateFlags = flags for (key, value) in group!.filterFlags { aggregateFlags[key] = value } return aggregateFlags } } /** Returns a boolean indicating whether two Example objects are equal. If two examples are defined at the exact same callsite, they must be equal. */ public func ==(lhs: Example, rhs: Example) -> Bool { return lhs.callsite == rhs.callsite } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/ExampleGroup.swift ================================================ /** Example groups are logical groupings of examples, defined with the `describe` and `context` functions. Example groups can share setup and teardown code. */ final public class ExampleGroup: NSObject { weak internal var parent: ExampleGroup? internal let hooks = ExampleHooks() private let internalDescription: String private let flags: FilterFlags private let isInternalRootExampleGroup: Bool private var childGroups = [ExampleGroup]() private var childExamples = [Example]() internal init(description: String, flags: FilterFlags, isInternalRootExampleGroup: Bool = false) { self.internalDescription = description self.flags = flags self.isInternalRootExampleGroup = isInternalRootExampleGroup } public override var description: String { return internalDescription } /** Returns a list of examples that belong to this example group, or to any of its descendant example groups. */ public var examples: [Example] { var examples = childExamples for group in childGroups { examples.appendContentsOf(group.examples) } return examples } internal var name: String? { if let parent = parent { switch(parent.name) { case .Some(let name): return "\(name), \(description)" case .None: return description } } else { return isInternalRootExampleGroup ? nil : description } } internal var filterFlags: FilterFlags { var aggregateFlags = flags walkUp() { (group: ExampleGroup) -> () in for (key, value) in group.flags { aggregateFlags[key] = value } } return aggregateFlags } internal var befores: [BeforeExampleWithMetadataClosure] { var closures = Array(hooks.befores.reverse()) walkUp() { (group: ExampleGroup) -> () in closures.appendContentsOf(Array(group.hooks.befores.reverse())) } return Array(closures.reverse()) } internal var afters: [AfterExampleWithMetadataClosure] { var closures = hooks.afters walkUp() { (group: ExampleGroup) -> () in closures.appendContentsOf(group.hooks.afters) } return closures } internal func walkDownExamples(callback: (example: Example) -> ()) { for example in childExamples { callback(example: example) } for group in childGroups { group.walkDownExamples(callback) } } internal func appendExampleGroup(group: ExampleGroup) { group.parent = self childGroups.append(group) } internal func appendExample(example: Example) { example.group = self childExamples.append(example) } private func walkUp(callback: (group: ExampleGroup) -> ()) { var group = self while let parent = group.parent { callback(group: parent) group = parent } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/ExampleMetadata.swift ================================================ /** A class that encapsulates information about an example, including the index at which the example was executed, as well as the example itself. */ final public class ExampleMetadata: NSObject { /** The example for which this metadata was collected. */ public let example: Example /** The index at which this example was executed in the test suite. */ public let exampleIndex: Int internal init(example: Example, exampleIndex: Int) { self.example = example self.exampleIndex = exampleIndex } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/Filter.swift ================================================ import Foundation /** A mapping of string keys to booleans that can be used to filter examples or example groups. For example, a "focused" example would have the flags [Focused: true]. */ public typealias FilterFlags = [String: Bool] /** A namespace for filter flag keys, defined primarily to make the keys available in Objective-C. */ final public class Filter: NSObject { /** Example and example groups with [Focused: true] are included in test runs, excluding all other examples without this flag. Use this to only run one or two tests that you're currently focusing on. */ public class var focused: String { return "focused" } /** Example and example groups with [Pending: true] are excluded from test runs. Use this to temporarily suspend examples that you know do not pass yet. */ public class var pending: String { return "pending" } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/Hooks/Closures.swift ================================================ // MARK: Example Hooks /** A closure executed before an example is run. */ public typealias BeforeExampleClosure = () -> () /** A closure executed before an example is run. The closure is given example metadata, which contains information about the example that is about to be run. */ public typealias BeforeExampleWithMetadataClosure = (exampleMetadata: ExampleMetadata) -> () /** A closure executed after an example is run. */ public typealias AfterExampleClosure = BeforeExampleClosure /** A closure executed after an example is run. The closure is given example metadata, which contains information about the example that has just finished running. */ public typealias AfterExampleWithMetadataClosure = BeforeExampleWithMetadataClosure // MARK: Suite Hooks /** A closure executed before any examples are run. */ public typealias BeforeSuiteClosure = () -> () /** A closure executed after all examples have finished running. */ public typealias AfterSuiteClosure = BeforeSuiteClosure ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/Hooks/ExampleHooks.swift ================================================ /** A container for closures to be executed before and after each example. */ final internal class ExampleHooks { internal var befores: [BeforeExampleWithMetadataClosure] = [] internal var afters: [AfterExampleWithMetadataClosure] = [] internal func appendBefore(closure: BeforeExampleWithMetadataClosure) { befores.append(closure) } internal func appendBefore(closure: BeforeExampleClosure) { befores.append { (exampleMetadata: ExampleMetadata) in closure() } } internal func appendAfter(closure: AfterExampleWithMetadataClosure) { afters.append(closure) } internal func appendAfter(closure: AfterExampleClosure) { afters.append { (exampleMetadata: ExampleMetadata) in closure() } } internal func executeBefores(exampleMetadata: ExampleMetadata) { for before in befores { before(exampleMetadata: exampleMetadata) } } internal func executeAfters(exampleMetadata: ExampleMetadata) { for after in afters { after(exampleMetadata: exampleMetadata) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/Hooks/SuiteHooks.swift ================================================ /** A container for closures to be executed before and after all examples. */ final internal class SuiteHooks { internal var befores: [BeforeSuiteClosure] = [] internal var beforesAlreadyExecuted = false internal var afters: [AfterSuiteClosure] = [] internal var aftersAlreadyExecuted = false internal func appendBefore(closure: BeforeSuiteClosure) { befores.append(closure) } internal func appendAfter(closure: AfterSuiteClosure) { afters.append(closure) } internal func executeBefores() { assert(!beforesAlreadyExecuted) for before in befores { before() } beforesAlreadyExecuted = true } internal func executeAfters() { assert(!aftersAlreadyExecuted) for after in afters { after() } aftersAlreadyExecuted = true } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSHumanReadableCopyright Copyright © 2014 - present, Quick Team. All rights reserved. NSPrincipalClass ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/NSString+QCKSelectorName.h ================================================ #import /** QuickSpec converts example names into test methods. Those test methods need valid selector names, which means no whitespace, control characters, etc. This category gives NSString objects an easy way to replace those illegal characters with underscores. */ @interface NSString (QCKSelectorName) /** Returns a string with underscores in place of all characters that cannot be included in a selector (SEL) name. */ @property (nonatomic, readonly) NSString *qck_selectorName; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/NSString+QCKSelectorName.m ================================================ #import "NSString+QCKSelectorName.h" @implementation NSString (QCKSelectorName) - (NSString *)qck_selectorName { static NSMutableCharacterSet *invalidCharacters = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ invalidCharacters = [NSMutableCharacterSet new]; NSCharacterSet *whitespaceCharacterSet = [NSCharacterSet whitespaceCharacterSet]; NSCharacterSet *newlineCharacterSet = [NSCharacterSet newlineCharacterSet]; NSCharacterSet *illegalCharacterSet = [NSCharacterSet illegalCharacterSet]; NSCharacterSet *controlCharacterSet = [NSCharacterSet controlCharacterSet]; NSCharacterSet *punctuationCharacterSet = [NSCharacterSet punctuationCharacterSet]; NSCharacterSet *nonBaseCharacterSet = [NSCharacterSet nonBaseCharacterSet]; NSCharacterSet *symbolCharacterSet = [NSCharacterSet symbolCharacterSet]; [invalidCharacters formUnionWithCharacterSet:whitespaceCharacterSet]; [invalidCharacters formUnionWithCharacterSet:newlineCharacterSet]; [invalidCharacters formUnionWithCharacterSet:illegalCharacterSet]; [invalidCharacters formUnionWithCharacterSet:controlCharacterSet]; [invalidCharacters formUnionWithCharacterSet:punctuationCharacterSet]; [invalidCharacters formUnionWithCharacterSet:nonBaseCharacterSet]; [invalidCharacters formUnionWithCharacterSet:symbolCharacterSet]; }); NSArray *validComponents = [self componentsSeparatedByCharactersInSet:invalidCharacters]; return [validComponents componentsJoinedByString:@"_"]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/Quick.h ================================================ #import //! Project version number for Quick. FOUNDATION_EXPORT double QuickVersionNumber; //! Project version string for Quick. FOUNDATION_EXPORT const unsigned char QuickVersionString[]; #import "QuickSpec.h" #import "QCKDSL.h" #import "QuickConfiguration.h" ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/QuickSpec.h ================================================ #import /** QuickSpec is a base class all specs written in Quick inherit from. They need to inherit from QuickSpec, a subclass of XCTestCase, in order to be discovered by the XCTest framework. XCTest automatically compiles a list of XCTestCase subclasses included in the test target. It iterates over each class in that list, and creates a new instance of that class for each test method. It then creates an "invocation" to execute that test method. The invocation is an instance of NSInvocation, which represents a single message send in Objective-C. The invocation is set on the XCTestCase instance, and the test is run. Most of the code in QuickSpec is dedicated to hooking into XCTest events. First, when the spec is first loaded and before it is sent any messages, the +[NSObject initialize] method is called. QuickSpec overrides this method to call +[QuickSpec spec]. This builds the example group stacks and registers them with Quick.World, a global register of examples. Then, XCTest queries QuickSpec for a list of test methods. Normally, XCTest automatically finds all methods whose selectors begin with the string "test". However, QuickSpec overrides this default behavior by implementing the +[XCTestCase testInvocations] method. This method iterates over each example registered in Quick.World, defines a new method for that example, and returns an invocation to call that method to XCTest. Those invocations are the tests that are run by XCTest. Their selector names are displayed in the Xcode test navigation bar. */ @interface QuickSpec : XCTestCase /** Override this method in your spec to define a set of example groups and examples. override class func spec() { describe("winter") { it("is coming") { // ... } } } See DSL.swift for more information on what syntax is available. */ - (void)spec; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/QuickSpec.m ================================================ #import "QuickSpec.h" #import "QuickConfiguration.h" #import "NSString+QCKSelectorName.h" #import "World.h" #import static QuickSpec *currentSpec = nil; const void * const QCKExampleKey = &QCKExampleKey; @interface QuickSpec () @property (nonatomic, strong) Example *example; @end @implementation QuickSpec #pragma mark - XCTestCase Overrides /** The runtime sends initialize to each class in a program just before the class, or any class that inherits from it, is sent its first message from within the program. QuickSpec hooks into this event to compile the example groups for this spec subclass. If an exception occurs when compiling the examples, report it to the user. Chances are they included an expectation outside of a "it", "describe", or "context" block. */ + (void)initialize { [QuickConfiguration initialize]; World *world = [World sharedWorld]; world.currentExampleGroup = [world rootExampleGroupForSpecClass:[self class]]; QuickSpec *spec = [self new]; @try { [spec spec]; } @catch (NSException *exception) { [NSException raise:NSInternalInconsistencyException format:@"An exception occurred when building Quick's example groups.\n" @"Some possible reasons this might happen include:\n\n" @"- An 'expect(...).to' expectation was evaluated outside of " @"an 'it', 'context', or 'describe' block\n" @"- 'sharedExamples' was called twice with the same name\n" @"- 'itBehavesLike' was called with a name that is not registered as a shared example\n\n" @"Here's the original exception: '%@', reason: '%@', userInfo: '%@'", exception.name, exception.reason, exception.userInfo]; } [self testInvocations]; } /** Invocations for each test method in the test case. QuickSpec overrides this method to define a new method for each example defined in +[QuickSpec spec]. @return An array of invocations that execute the newly defined example methods. */ + (NSArray *)testInvocations { NSArray *examples = [[World sharedWorld] examplesForSpecClass:[self class]]; NSMutableArray *invocations = [NSMutableArray arrayWithCapacity:[examples count]]; for (Example *example in examples) { SEL selector = [self addInstanceMethodForExample:example]; NSInvocation *invocation = [self invocationForInstanceMethodWithSelector:selector example:example]; [invocations addObject:invocation]; } return invocations; } /** XCTest sets the invocation for the current test case instance using this setter. QuickSpec hooks into this event to give the test case a reference to the current example. It will need this reference to correctly report its name to XCTest. */ - (void)setInvocation:(NSInvocation *)invocation { self.example = objc_getAssociatedObject(invocation, QCKExampleKey); [super setInvocation:invocation]; } #pragma mark - Public Interface - (void)spec { } #pragma mark - Internal Methods /** QuickSpec uses this method to dynamically define a new instance method for the given example. The instance method runs the example, catching any exceptions. The exceptions are then reported as test failures. In order to report the correct file and line number, examples must raise exceptions containing following keys in their userInfo: - "SenTestFilenameKey": A String representing the file name - "SenTestLineNumberKey": An Int representing the line number These keys used to be used by SenTestingKit, and are still used by some testing tools in the wild. See: https://github.com/Quick/Quick/pull/41 @return The selector of the newly defined instance method. */ + (SEL)addInstanceMethodForExample:(Example *)example { IMP implementation = imp_implementationWithBlock(^(QuickSpec *self){ currentSpec = self; [example run]; }); NSCharacterSet *characterSet = [NSCharacterSet alphanumericCharacterSet]; NSMutableString *sanitizedFileName = [NSMutableString string]; for (NSUInteger i = 0; i < example.callsite.file.length; i++) { unichar ch = [example.callsite.file characterAtIndex:i]; if ([characterSet characterIsMember:ch]) { [sanitizedFileName appendFormat:@"%c", ch]; } } const char *types = [[NSString stringWithFormat:@"%s%s%s", @encode(id), @encode(id), @encode(SEL)] UTF8String]; NSString *selectorName = [NSString stringWithFormat:@"%@_%@_%ld", example.name.qck_selectorName, sanitizedFileName, (long)example.callsite.line]; SEL selector = NSSelectorFromString(selectorName); class_addMethod(self, selector, implementation, types); return selector; } + (NSInvocation *)invocationForInstanceMethodWithSelector:(SEL)selector example:(Example *)example { NSMethodSignature *signature = [self instanceMethodSignatureForSelector:selector]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; invocation.selector = selector; objc_setAssociatedObject(invocation, QCKExampleKey, example, OBJC_ASSOCIATION_RETAIN_NONATOMIC); return invocation; } /** This method is used to record failures, whether they represent example expectations that were not met, or exceptions raised during test setup and teardown. By default, the failure will be reported as an XCTest failure, and the example will be highlighted in Xcode. */ - (void)recordFailureWithDescription:(NSString *)description inFile:(NSString *)filePath atLine:(NSUInteger)lineNumber expected:(BOOL)expected { if (self.example.isSharedExample) { filePath = self.example.callsite.file; lineNumber = self.example.callsite.line; } [currentSpec.testRun recordFailureWithDescription:description inFile:filePath atLine:lineNumber expected:expected]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/World.h ================================================ #import @class ExampleGroup; @class ExampleMetadata; SWIFT_CLASS("_TtC5Quick5World") @interface World @property (nonatomic) ExampleGroup * __nullable currentExampleGroup; @property (nonatomic) ExampleMetadata * __nullable currentExampleMetadata; @property (nonatomic) BOOL isRunningAdditionalSuites; + (World * __nonnull)sharedWorld; - (void)configure:(void (^ __nonnull)(Configuration * __nonnull))closure; - (void)finalizeConfiguration; - (ExampleGroup * __nonnull)rootExampleGroupForSpecClass:(Class __nonnull)cls; - (NSArray * __nonnull)examplesForSpecClass:(Class __nonnull)specClass; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick/World.swift ================================================ import Foundation /** A closure that, when evaluated, returns a dictionary of key-value pairs that can be accessed from within a group of shared examples. */ public typealias SharedExampleContext = () -> (NSDictionary) /** A closure that is used to define a group of shared examples. This closure may contain any number of example and example groups. */ public typealias SharedExampleClosure = (SharedExampleContext) -> () /** A collection of state Quick builds up in order to work its magic. World is primarily responsible for maintaining a mapping of QuickSpec classes to root example groups for those classes. It also maintains a mapping of shared example names to shared example closures. You may configure how Quick behaves by calling the -[World configure:] method from within an overridden +[QuickConfiguration configure:] method. */ final internal class World: NSObject { /** The example group that is currently being run. The DSL requires that this group is correctly set in order to build a correct hierarchy of example groups and their examples. */ internal var currentExampleGroup: ExampleGroup? /** The example metadata of the test that is currently being run. This is useful for using the Quick test metadata (like its name) at runtime. */ internal var currentExampleMetadata: ExampleMetadata? /** A flag that indicates whether additional test suites are being run within this test suite. This is only true within the context of Quick functional tests. */ internal var isRunningAdditionalSuites = false private var specs: Dictionary = [:] private var sharedExamples: [String: SharedExampleClosure] = [:] private let configuration = Configuration() private var isConfigurationFinalized = false internal var exampleHooks: ExampleHooks {return configuration.exampleHooks } internal var suiteHooks: SuiteHooks { return configuration.suiteHooks } // MARK: Singleton Constructor private override init() {} private struct Shared { static let instance = World() } internal class func sharedWorld() -> World { return Shared.instance } // MARK: Public Interface /** Exposes the World's Configuration object within the scope of the closure so that it may be configured. This method must not be called outside of an overridden +[QuickConfiguration configure:] method. - parameter closure: A closure that takes a Configuration object that can be mutated to change Quick's behavior. */ internal func configure(closure: QuickConfigurer) { assert(!isConfigurationFinalized, "Quick cannot be configured outside of a +[QuickConfiguration configure:] method. You should not call -[World configure:] directly. Instead, subclass QuickConfiguration and override the +[QuickConfiguration configure:] method.") closure(configuration: configuration) } /** Finalizes the World's configuration. Any subsequent calls to World.configure() will raise. */ internal func finalizeConfiguration() { isConfigurationFinalized = true } /** Returns an internally constructed root example group for the given QuickSpec class. A root example group with the description "root example group" is lazily initialized for each QuickSpec class. This root example group wraps the top level of a -[QuickSpec spec] method--it's thanks to this group that users can define beforeEach and it closures at the top level, like so: override func spec() { // These belong to the root example group beforeEach {} it("is at the top level") {} } - parameter cls: The QuickSpec class for which to retrieve the root example group. - returns: The root example group for the class. */ internal func rootExampleGroupForSpecClass(cls: AnyClass) -> ExampleGroup { let name = NSStringFromClass(cls) if let group = specs[name] { return group } else { let group = ExampleGroup( description: "root example group", flags: [:], isInternalRootExampleGroup: true ) specs[name] = group return group } } /** Returns all examples that should be run for a given spec class. There are two filtering passes that occur when determining which examples should be run. That is, these examples are the ones that are included by inclusion filters, and are not excluded by exclusion filters. - parameter specClass: The QuickSpec subclass for which examples are to be returned. - returns: A list of examples to be run as test invocations. */ @objc(examplesForSpecClass:) internal func examples(specClass: AnyClass) -> [Example] { // 1. Grab all included examples. let included = includedExamples // 2. Grab the intersection of (a) examples for this spec, and (b) included examples. let spec = rootExampleGroupForSpecClass(specClass).examples.filter { included.contains($0) } // 3. Remove all excluded examples. return spec.filter { example in !self.configuration.exclusionFilters.reduce(false) { $0 || $1(example: example) } } } // MARK: Internal internal func registerSharedExample(name: String, closure: SharedExampleClosure) { raiseIfSharedExampleAlreadyRegistered(name) sharedExamples[name] = closure } internal func sharedExample(name: String) -> SharedExampleClosure { raiseIfSharedExampleNotRegistered(name) return sharedExamples[name]! } internal var exampleCount: Int { return allExamples.count } private var allExamples: [Example] { var all: [Example] = [] for (_, group) in specs { group.walkDownExamples { all.append($0) } } return all } private var includedExamples: [Example] { let all = allExamples let included = all.filter { example in return self.configuration.inclusionFilters.reduce(false) { $0 || $1(example: example) } } if included.isEmpty && configuration.runAllWhenEverythingFiltered { return all } else { return included } } private func raiseIfSharedExampleAlreadyRegistered(name: String) { if sharedExamples[name] != nil { NSException(name: NSInternalInconsistencyException, reason: "A shared example named '\(name)' has already been registered.", userInfo: nil).raise() } } private func raiseIfSharedExampleNotRegistered(name: String) { if sharedExamples[name] == nil { NSException(name: NSInternalInconsistencyException, reason: "No shared example named '\(name)' has been registered. Registered shared examples: '\(Array(sharedExamples.keys))'", userInfo: nil).raise() } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick Templates/Quick Configuration Class.xctemplate/Objective-C/___FILEBASENAME___.h ================================================ @import Quick; @interface ___FILEBASENAMEASIDENTIFIER___ : QuickConfiguration @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick Templates/Quick Configuration Class.xctemplate/Objective-C/___FILEBASENAME___.m ================================================ #import "___FILEBASENAMEASIDENTIFIER___.h" @implementation ___FILEBASENAMEASIDENTIFIER___ + (void)configure:(Configuration *)configuration { } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick Templates/Quick Configuration Class.xctemplate/Swift/___FILEBASENAME___.swift ================================================ import Quick class ___FILEBASENAMEASIDENTIFIER___: QuickConfiguration { override class func configure(configuration: Configuration) { } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick Templates/Quick Configuration Class.xctemplate/TemplateInfo.plist ================================================ Kind Xcode.IDEKit.TextSubstitutionFileTemplateKind Description A QuickConfiguration subclass. Summary A QuickConfiguration subclass, overload +configure: to configure the behaviour when running specs, shared examples that are used across spec files. SortOrder 1 BuildableType Test DefaultCompletionName Spec Options Description Name of the Quick Configuration Identifier productName Name QuickConfiguration Name: NotPersisted Required Type text AllowedTypes Swift public.swift-source Objective-C public.objective-c-source public.objective-c-plus-plus-source Default Swift Description The implementation language Identifier languageChoice MainTemplateFiles Objective-C ___FILEBASENAME___.m Swift ___FILEBASENAME___.swift Name Language: Required Yes Type popup Values Swift Objective-C ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick Templates/Quick Spec Class.xctemplate/Objective-C/___FILEBASENAME___.m ================================================ #import #import QuickSpecBegin(___FILEBASENAMEASIDENTIFIER___) QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick Templates/Quick Spec Class.xctemplate/Swift/___FILEBASENAME___.swift ================================================ import Quick import Nimble class ___FILEBASENAMEASIDENTIFIER___: QuickSpec { override func spec() { } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick Templates/Quick Spec Class.xctemplate/TemplateInfo.plist ================================================ Kind Xcode.IDEKit.TextSubstitutionFileTemplateKind Description A class implementing a Quick spec. Summary A class implementing a Quick spec SortOrder 1 BuildableType Test DefaultCompletionName Spec Options Description Name of the Quick spec class Identifier productName Name Spec Name: NotPersisted Required Type text AllowedTypes Swift public.swift-source Objective-C public.objective-c-source public.objective-c-plus-plus-source Default Swift Description The implementation language Identifier languageChoice MainTemplateFiles Objective-C ___FILEBASENAME___.m Swift ___FILEBASENAME___.swift Name Language: Required Yes Type popup Values Swift Objective-C ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick.podspec ================================================ Pod::Spec.new do |s| s.name = "Quick" s.version = "0.8.0" s.summary = "The Swift (and Objective-C) testing framework." s.description = <<-DESC Quick is a behavior-driven development framework for Swift and Objective-C. Inspired by RSpec, Specta, and Ginkgo. DESC s.homepage = "https://github.com/Quick/Quick" s.license = { :type => "Apache 2.0", :file => "LICENSE" } s.author = "Quick Contributors" s.ios.deployment_target = "7.0" s.osx.deployment_target = "10.9" s.tvos.deployment_target = '9.0' s.source = { :git => "https://github.com/Quick/Quick.git", :tag => "v#{s.version}" } s.source_files = "Quick", "Quick/**/*.{swift,h,m}" s.public_header_files = [ 'Quick/Configuration/QuickConfiguration.h', 'Quick/DSL/QCKDSL.h', 'Quick/Quick.h', 'Quick/QuickSpec.h', ] s.framework = "XCTest" s.requires_arc = true s.pod_target_xcconfig = { 'ENABLE_BITCODE' => 'NO' } end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 1F118CDF1BDCA4AB005013A2 /* Quick.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F118CD51BDCA4AB005013A2 /* Quick.framework */; }; 1F118CF51BDCA4BB005013A2 /* Quick.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F118CD51BDCA4AB005013A2 /* Quick.framework */; }; 1F118CFB1BDCA536005013A2 /* QuickConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE714FD19FF6A62005905B8 /* QuickConfiguration.m */; }; 1F118CFC1BDCA536005013A2 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA169E4719FF5DF100619816 /* Configuration.swift */; }; 1F118CFD1BDCA536005013A2 /* World+DSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3124E519FCAEE8002858A7 /* World+DSL.swift */; }; 1F118CFE1BDCA536005013A2 /* DSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3124E219FCAEE8002858A7 /* DSL.swift */; }; 1F118CFF1BDCA536005013A2 /* QCKDSL.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3124E419FCAEE8002858A7 /* QCKDSL.m */; }; 1F118D001BDCA536005013A2 /* Closures.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA408BDF19FF5599005DF92A /* Closures.swift */; }; 1F118D011BDCA536005013A2 /* ExampleHooks.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA408BE019FF5599005DF92A /* ExampleHooks.swift */; }; 1F118D021BDCA536005013A2 /* SuiteHooks.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA408BE119FF5599005DF92A /* SuiteHooks.swift */; }; 1F118D031BDCA536005013A2 /* World.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F375A619515CA700CE1B99 /* World.swift */; }; 1F118D041BDCA536005013A2 /* Example.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F3759E19515CA700CE1B99 /* Example.swift */; }; 1F118D051BDCA536005013A2 /* ExampleMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA02C91819A8073100093156 /* ExampleMetadata.swift */; }; 1F118D061BDCA536005013A2 /* ExampleGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F3759F19515CA700CE1B99 /* ExampleGroup.swift */; }; 1F118D071BDCA536005013A2 /* Callsite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F3759C19515CA700CE1B99 /* Callsite.swift */; }; 1F118D081BDCA536005013A2 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA6B30171A4DB0D500FFB148 /* Filter.swift */; }; 1F118D091BDCA536005013A2 /* QuickSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F375A519515CA700CE1B99 /* QuickSpec.m */; }; 1F118D0A1BDCA536005013A2 /* NSString+QCKSelectorName.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F375A119515CA700CE1B99 /* NSString+QCKSelectorName.m */; }; 1F118D0C1BDCA543005013A2 /* QuickConfigurationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8C00201A01E4B900CE58A6 /* QuickConfigurationTests.m */; }; 1F118D0D1BDCA547005013A2 /* QCKSpecRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8F919619F31680006F6675 /* QCKSpecRunner.m */; }; 1F118D0E1BDCA547005013A2 /* QCKSpecRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8F919619F31680006F6675 /* QCKSpecRunner.m */; }; 1F118D0F1BDCA54B005013A2 /* FunctionalTests_SharedExamplesTests_SharedExamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA8F91AD19F32CE2006F6675 /* FunctionalTests_SharedExamplesTests_SharedExamples.swift */; }; 1F118D101BDCA556005013A2 /* Configuration+AfterEach.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE714F619FF6812005905B8 /* Configuration+AfterEach.swift */; }; 1F118D111BDCA556005013A2 /* Configuration+AfterEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE714F919FF682A005905B8 /* Configuration+AfterEachTests.swift */; }; 1F118D121BDCA556005013A2 /* ItTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA7AE6F019FC493F000AFDCE /* ItTests.swift */; }; 1F118D131BDCA556005013A2 /* ItTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 479C31E11A36156E00DA8718 /* ItTests+ObjC.m */; }; 1F118D141BDCA556005013A2 /* FailureTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8F919C19F31921006F6675 /* FailureTests+ObjC.m */; }; 1F118D151BDCA556005013A2 /* FailureUsingXCTAssertTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8940EF1B35B1FA00161061 /* FailureUsingXCTAssertTests+ObjC.m */; }; 1F118D161BDCA556005013A2 /* BeforeEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA87078219F48775008C04AC /* BeforeEachTests.swift */; }; 1F118D171BDCA556005013A2 /* BeforeEachTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 47FAEA341A3F45ED005A1D2F /* BeforeEachTests+ObjC.m */; }; 1F118D181BDCA556005013A2 /* AfterEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA05D60F19F73A3800771050 /* AfterEachTests.swift */; }; 1F118D191BDCA556005013A2 /* AfterEachTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 470D6EC91A43409600043E50 /* AfterEachTests+ObjC.m */; }; 1F118D1A1BDCA556005013A2 /* PendingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAA63EA219F7637300CD0A3B /* PendingTests.swift */; }; 1F118D1B1BDCA556005013A2 /* PendingTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 4715903F1A488F3F00FBA644 /* PendingTests+ObjC.m */; }; 1F118D1C1BDCA556005013A2 /* BeforeSuiteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA8F91A419F3208B006F6675 /* BeforeSuiteTests.swift */; }; 1F118D1D1BDCA556005013A2 /* BeforeSuiteTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 47876F7B1A4999B0002575C7 /* BeforeSuiteTests+ObjC.m */; }; 1F118D1E1BDCA556005013A2 /* AfterSuiteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA8F91A719F32556006F6675 /* AfterSuiteTests.swift */; }; 1F118D1F1BDCA556005013A2 /* AfterSuiteTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 477217391A59C1B00022013E /* AfterSuiteTests+ObjC.m */; }; 1F118D201BDCA556005013A2 /* SharedExamplesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA8F91AA19F3299E006F6675 /* SharedExamplesTests.swift */; }; 1F118D211BDCA556005013A2 /* SharedExamplesTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 4728253A1A5EECCE008DC74F /* SharedExamplesTests+ObjC.m */; }; 1F118D221BDCA556005013A2 /* SharedExamples+BeforeEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB0136E19FC4315006AFBEE /* SharedExamples+BeforeEachTests.swift */; }; 1F118D231BDCA556005013A2 /* SharedExamples+BeforeEachTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 4748E8931A6AEBB3009EC992 /* SharedExamples+BeforeEachTests+ObjC.m */; }; 1F118D241BDCA561005013A2 /* FocusedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9876BF1A4C87200004AA17 /* FocusedTests.swift */; }; 1F118D251BDCA561005013A2 /* FocusedTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = DAF28BC21A4DB8EC00A5D9BF /* FocusedTests+ObjC.m */; }; 1F118D261BDCA5AF005013A2 /* World+DSL.h in Headers */ = {isa = PBXBuildFile; fileRef = DAED1EC81B110699006F61EC /* World+DSL.h */; }; 1F118D271BDCA5AF005013A2 /* World.h in Headers */ = {isa = PBXBuildFile; fileRef = DAED1EC21B1105BC006F61EC /* World.h */; }; 1F118D281BDCA5AF005013A2 /* NSString+QCKSelectorName.h in Headers */ = {isa = PBXBuildFile; fileRef = 34F375A019515CA700CE1B99 /* NSString+QCKSelectorName.h */; }; 1F118D291BDCA5B6005013A2 /* QuickConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE714FC19FF6A62005905B8 /* QuickConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F118D2A1BDCA5B6005013A2 /* QCKDSL.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3124E319FCAEE8002858A7 /* QCKDSL.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F118D2B1BDCA5B6005013A2 /* Quick.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB6B931943873100289F44 /* Quick.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F118D2C1BDCA5B6005013A2 /* QuickSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 34F375A419515CA700CE1B99 /* QuickSpec.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F118D351BDCA657005013A2 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F118D341BDCA657005013A2 /* Nimble.framework */; }; 1F118D371BDCA65C005013A2 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F118D361BDCA65C005013A2 /* Nimble.framework */; }; 1F118D381BDCA6E1005013A2 /* Configuration+BeforeEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE714EF19FF65D3005905B8 /* Configuration+BeforeEachTests.swift */; }; 1F118D391BDCA6E6005013A2 /* Configuration+BeforeEach.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE714F219FF65E7005905B8 /* Configuration+BeforeEach.swift */; }; 1FD0CFAD1AFA0B8C00874CC1 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8100E901A1E4447007595ED /* Nimble.framework */; }; 34F375A719515CA700CE1B99 /* Callsite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F3759C19515CA700CE1B99 /* Callsite.swift */; }; 34F375A819515CA700CE1B99 /* Callsite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F3759C19515CA700CE1B99 /* Callsite.swift */; }; 34F375AB19515CA700CE1B99 /* Example.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F3759E19515CA700CE1B99 /* Example.swift */; }; 34F375AC19515CA700CE1B99 /* Example.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F3759E19515CA700CE1B99 /* Example.swift */; }; 34F375AD19515CA700CE1B99 /* ExampleGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F3759F19515CA700CE1B99 /* ExampleGroup.swift */; }; 34F375AE19515CA700CE1B99 /* ExampleGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F3759F19515CA700CE1B99 /* ExampleGroup.swift */; }; 34F375AF19515CA700CE1B99 /* NSString+QCKSelectorName.h in Headers */ = {isa = PBXBuildFile; fileRef = 34F375A019515CA700CE1B99 /* NSString+QCKSelectorName.h */; }; 34F375B019515CA700CE1B99 /* NSString+QCKSelectorName.h in Headers */ = {isa = PBXBuildFile; fileRef = 34F375A019515CA700CE1B99 /* NSString+QCKSelectorName.h */; }; 34F375B119515CA700CE1B99 /* NSString+QCKSelectorName.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F375A119515CA700CE1B99 /* NSString+QCKSelectorName.m */; }; 34F375B219515CA700CE1B99 /* NSString+QCKSelectorName.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F375A119515CA700CE1B99 /* NSString+QCKSelectorName.m */; }; 34F375B719515CA700CE1B99 /* QuickSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 34F375A419515CA700CE1B99 /* QuickSpec.h */; settings = {ATTRIBUTES = (Public, ); }; }; 34F375B819515CA700CE1B99 /* QuickSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 34F375A419515CA700CE1B99 /* QuickSpec.h */; settings = {ATTRIBUTES = (Public, ); }; }; 34F375B919515CA700CE1B99 /* QuickSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F375A519515CA700CE1B99 /* QuickSpec.m */; }; 34F375BA19515CA700CE1B99 /* QuickSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F375A519515CA700CE1B99 /* QuickSpec.m */; }; 34F375BB19515CA700CE1B99 /* World.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F375A619515CA700CE1B99 /* World.swift */; }; 34F375BC19515CA700CE1B99 /* World.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34F375A619515CA700CE1B99 /* World.swift */; }; 470D6ECB1A43442400043E50 /* AfterEachTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 470D6EC91A43409600043E50 /* AfterEachTests+ObjC.m */; }; 470D6ECC1A43442900043E50 /* AfterEachTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 470D6EC91A43409600043E50 /* AfterEachTests+ObjC.m */; }; 471590401A488F3F00FBA644 /* PendingTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 4715903F1A488F3F00FBA644 /* PendingTests+ObjC.m */; }; 471590411A488F3F00FBA644 /* PendingTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 4715903F1A488F3F00FBA644 /* PendingTests+ObjC.m */; }; 4728253B1A5EECCE008DC74F /* SharedExamplesTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 4728253A1A5EECCE008DC74F /* SharedExamplesTests+ObjC.m */; }; 4728253C1A5EECCE008DC74F /* SharedExamplesTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 4728253A1A5EECCE008DC74F /* SharedExamplesTests+ObjC.m */; }; 4748E8941A6AEBB3009EC992 /* SharedExamples+BeforeEachTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 4748E8931A6AEBB3009EC992 /* SharedExamples+BeforeEachTests+ObjC.m */; }; 4748E8951A6AEBB3009EC992 /* SharedExamples+BeforeEachTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 4748E8931A6AEBB3009EC992 /* SharedExamples+BeforeEachTests+ObjC.m */; }; 4772173A1A59C1B00022013E /* AfterSuiteTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 477217391A59C1B00022013E /* AfterSuiteTests+ObjC.m */; }; 4772173B1A59C1B00022013E /* AfterSuiteTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 477217391A59C1B00022013E /* AfterSuiteTests+ObjC.m */; }; 47876F7D1A49AD63002575C7 /* BeforeSuiteTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 47876F7B1A4999B0002575C7 /* BeforeSuiteTests+ObjC.m */; }; 47876F7E1A49AD71002575C7 /* BeforeSuiteTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 47876F7B1A4999B0002575C7 /* BeforeSuiteTests+ObjC.m */; }; 479C31E31A36171B00DA8718 /* ItTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 479C31E11A36156E00DA8718 /* ItTests+ObjC.m */; }; 479C31E41A36172700DA8718 /* ItTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 479C31E11A36156E00DA8718 /* ItTests+ObjC.m */; }; 47FAEA361A3F49E6005A1D2F /* BeforeEachTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 47FAEA341A3F45ED005A1D2F /* BeforeEachTests+ObjC.m */; }; 47FAEA371A3F49EB005A1D2F /* BeforeEachTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = 47FAEA341A3F45ED005A1D2F /* BeforeEachTests+ObjC.m */; }; 5A5D118719473F2100F6D13D /* Quick.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A5D117C19473F2100F6D13D /* Quick.framework */; }; 5A5D11A7194740E000F6D13D /* Quick.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB6B931943873100289F44 /* Quick.h */; settings = {ATTRIBUTES = (Public, ); }; }; DA02C91919A8073100093156 /* ExampleMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA02C91819A8073100093156 /* ExampleMetadata.swift */; }; DA02C91A19A8073100093156 /* ExampleMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA02C91819A8073100093156 /* ExampleMetadata.swift */; }; DA05D61019F73A3800771050 /* AfterEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA05D60F19F73A3800771050 /* AfterEachTests.swift */; }; DA05D61119F73A3800771050 /* AfterEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA05D60F19F73A3800771050 /* AfterEachTests.swift */; }; DA07722E1A4E5B7B0098839D /* QCKSpecRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8F919619F31680006F6675 /* QCKSpecRunner.m */; }; DA07722F1A4E5B7C0098839D /* QCKSpecRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8F919619F31680006F6675 /* QCKSpecRunner.m */; }; DA169E4819FF5DF100619816 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA169E4719FF5DF100619816 /* Configuration.swift */; }; DA169E4919FF5DF100619816 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA169E4719FF5DF100619816 /* Configuration.swift */; }; DA3124E619FCAEE8002858A7 /* DSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3124E219FCAEE8002858A7 /* DSL.swift */; }; DA3124E719FCAEE8002858A7 /* DSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3124E219FCAEE8002858A7 /* DSL.swift */; }; DA3124E819FCAEE8002858A7 /* QCKDSL.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3124E319FCAEE8002858A7 /* QCKDSL.h */; settings = {ATTRIBUTES = (Public, ); }; }; DA3124E919FCAEE8002858A7 /* QCKDSL.h in Headers */ = {isa = PBXBuildFile; fileRef = DA3124E319FCAEE8002858A7 /* QCKDSL.h */; settings = {ATTRIBUTES = (Public, ); }; }; DA3124EA19FCAEE8002858A7 /* QCKDSL.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3124E419FCAEE8002858A7 /* QCKDSL.m */; }; DA3124EB19FCAEE8002858A7 /* QCKDSL.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3124E419FCAEE8002858A7 /* QCKDSL.m */; }; DA3124EC19FCAEE8002858A7 /* World+DSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3124E519FCAEE8002858A7 /* World+DSL.swift */; }; DA3124ED19FCAEE8002858A7 /* World+DSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3124E519FCAEE8002858A7 /* World+DSL.swift */; }; DA3E7A341A1E66C600CCE408 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8100E901A1E4447007595ED /* Nimble.framework */; }; DA3E7A351A1E66CB00CCE408 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8100E901A1E4447007595ED /* Nimble.framework */; }; DA408BE219FF5599005DF92A /* Closures.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA408BDF19FF5599005DF92A /* Closures.swift */; }; DA408BE319FF5599005DF92A /* Closures.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA408BDF19FF5599005DF92A /* Closures.swift */; }; DA408BE419FF5599005DF92A /* ExampleHooks.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA408BE019FF5599005DF92A /* ExampleHooks.swift */; }; DA408BE519FF5599005DF92A /* ExampleHooks.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA408BE019FF5599005DF92A /* ExampleHooks.swift */; }; DA408BE619FF5599005DF92A /* SuiteHooks.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA408BE119FF5599005DF92A /* SuiteHooks.swift */; }; DA408BE719FF5599005DF92A /* SuiteHooks.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA408BE119FF5599005DF92A /* SuiteHooks.swift */; }; DA5663EE1A4C8D8500193C88 /* Quick.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAEB6B8E1943873100289F44 /* Quick.framework */; }; DA5663F41A4C8D9A00193C88 /* FocusedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9876BF1A4C87200004AA17 /* FocusedTests.swift */; }; DA6B30181A4DB0D500FFB148 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA6B30171A4DB0D500FFB148 /* Filter.swift */; }; DA6B30191A4DB0D500FFB148 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA6B30171A4DB0D500FFB148 /* Filter.swift */; }; DA7AE6F119FC493F000AFDCE /* ItTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA7AE6F019FC493F000AFDCE /* ItTests.swift */; }; DA7AE6F219FC493F000AFDCE /* ItTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA7AE6F019FC493F000AFDCE /* ItTests.swift */; }; DA8940F01B35B1FA00161061 /* FailureUsingXCTAssertTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8940EF1B35B1FA00161061 /* FailureUsingXCTAssertTests+ObjC.m */; }; DA8940F11B35B1FA00161061 /* FailureUsingXCTAssertTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8940EF1B35B1FA00161061 /* FailureUsingXCTAssertTests+ObjC.m */; }; DA8C00211A01E4B900CE58A6 /* QuickConfigurationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8C00201A01E4B900CE58A6 /* QuickConfigurationTests.m */; }; DA8C00221A01E4B900CE58A6 /* QuickConfigurationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8C00201A01E4B900CE58A6 /* QuickConfigurationTests.m */; }; DA8F919919F31680006F6675 /* QCKSpecRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8F919619F31680006F6675 /* QCKSpecRunner.m */; }; DA8F919A19F31680006F6675 /* QCKSpecRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8F919619F31680006F6675 /* QCKSpecRunner.m */; }; DA8F919D19F31921006F6675 /* FailureTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8F919C19F31921006F6675 /* FailureTests+ObjC.m */; }; DA8F919E19F31921006F6675 /* FailureTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8F919C19F31921006F6675 /* FailureTests+ObjC.m */; }; DA8F91A519F3208B006F6675 /* BeforeSuiteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA8F91A419F3208B006F6675 /* BeforeSuiteTests.swift */; }; DA8F91A619F3208B006F6675 /* BeforeSuiteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA8F91A419F3208B006F6675 /* BeforeSuiteTests.swift */; }; DA8F91A819F32556006F6675 /* AfterSuiteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA8F91A719F32556006F6675 /* AfterSuiteTests.swift */; }; DA8F91A919F32556006F6675 /* AfterSuiteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA8F91A719F32556006F6675 /* AfterSuiteTests.swift */; }; DA8F91AB19F3299E006F6675 /* SharedExamplesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA8F91AA19F3299E006F6675 /* SharedExamplesTests.swift */; }; DA8F91AC19F3299E006F6675 /* SharedExamplesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA8F91AA19F3299E006F6675 /* SharedExamplesTests.swift */; }; DA8F91AE19F32CE2006F6675 /* FunctionalTests_SharedExamplesTests_SharedExamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA8F91AD19F32CE2006F6675 /* FunctionalTests_SharedExamplesTests_SharedExamples.swift */; }; DA8F91AF19F32CE2006F6675 /* FunctionalTests_SharedExamplesTests_SharedExamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA8F91AD19F32CE2006F6675 /* FunctionalTests_SharedExamplesTests_SharedExamples.swift */; }; DA9876B81A4C70EB0004AA17 /* Quick.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A5D117C19473F2100F6D13D /* Quick.framework */; }; DA9876C11A4C87200004AA17 /* FocusedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA9876BF1A4C87200004AA17 /* FocusedTests.swift */; }; DAA63EA319F7637300CD0A3B /* PendingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAA63EA219F7637300CD0A3B /* PendingTests.swift */; }; DAA63EA419F7637300CD0A3B /* PendingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAA63EA219F7637300CD0A3B /* PendingTests.swift */; }; DAA7C0D719F777EB0093D1D9 /* BeforeEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA87078219F48775008C04AC /* BeforeEachTests.swift */; }; DAB0136F19FC4315006AFBEE /* SharedExamples+BeforeEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB0136E19FC4315006AFBEE /* SharedExamples+BeforeEachTests.swift */; }; DAB0137019FC4315006AFBEE /* SharedExamples+BeforeEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAB0136E19FC4315006AFBEE /* SharedExamples+BeforeEachTests.swift */; }; DAB067E919F7801C00F970AC /* BeforeEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA87078219F48775008C04AC /* BeforeEachTests.swift */; }; DAD297651AA8129D001D25CD /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8100E901A1E4447007595ED /* Nimble.framework */; }; DAE714F019FF65D3005905B8 /* Configuration+BeforeEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE714EF19FF65D3005905B8 /* Configuration+BeforeEachTests.swift */; }; DAE714F119FF65D3005905B8 /* Configuration+BeforeEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE714EF19FF65D3005905B8 /* Configuration+BeforeEachTests.swift */; }; DAE714F319FF65E7005905B8 /* Configuration+BeforeEach.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE714F219FF65E7005905B8 /* Configuration+BeforeEach.swift */; }; DAE714F419FF65E7005905B8 /* Configuration+BeforeEach.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE714F219FF65E7005905B8 /* Configuration+BeforeEach.swift */; }; DAE714F719FF6812005905B8 /* Configuration+AfterEach.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE714F619FF6812005905B8 /* Configuration+AfterEach.swift */; }; DAE714F819FF6812005905B8 /* Configuration+AfterEach.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE714F619FF6812005905B8 /* Configuration+AfterEach.swift */; }; DAE714FA19FF682A005905B8 /* Configuration+AfterEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE714F919FF682A005905B8 /* Configuration+AfterEachTests.swift */; }; DAE714FB19FF682A005905B8 /* Configuration+AfterEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAE714F919FF682A005905B8 /* Configuration+AfterEachTests.swift */; }; DAE714FE19FF6A62005905B8 /* QuickConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE714FC19FF6A62005905B8 /* QuickConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; DAE714FF19FF6A62005905B8 /* QuickConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE714FC19FF6A62005905B8 /* QuickConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; DAE7150019FF6A62005905B8 /* QuickConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE714FD19FF6A62005905B8 /* QuickConfiguration.m */; }; DAE7150119FF6A62005905B8 /* QuickConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE714FD19FF6A62005905B8 /* QuickConfiguration.m */; }; DAEB6B941943873100289F44 /* Quick.h in Headers */ = {isa = PBXBuildFile; fileRef = DAEB6B931943873100289F44 /* Quick.h */; settings = {ATTRIBUTES = (Public, ); }; }; DAEB6B9A1943873100289F44 /* Quick.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAEB6B8E1943873100289F44 /* Quick.framework */; }; DAED1EC41B1105BC006F61EC /* World.h in Headers */ = {isa = PBXBuildFile; fileRef = DAED1EC21B1105BC006F61EC /* World.h */; }; DAED1EC51B1105BC006F61EC /* World.h in Headers */ = {isa = PBXBuildFile; fileRef = DAED1EC21B1105BC006F61EC /* World.h */; }; DAED1ECA1B110699006F61EC /* World+DSL.h in Headers */ = {isa = PBXBuildFile; fileRef = DAED1EC81B110699006F61EC /* World+DSL.h */; }; DAED1ECB1B110699006F61EC /* World+DSL.h in Headers */ = {isa = PBXBuildFile; fileRef = DAED1EC81B110699006F61EC /* World+DSL.h */; }; DAF28BC31A4DB8EC00A5D9BF /* FocusedTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = DAF28BC21A4DB8EC00A5D9BF /* FocusedTests+ObjC.m */; }; DAF28BC41A4DB8EC00A5D9BF /* FocusedTests+ObjC.m in Sources */ = {isa = PBXBuildFile; fileRef = DAF28BC21A4DB8EC00A5D9BF /* FocusedTests+ObjC.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 047655511949F4CB00B288BB /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = DAEB6B8D1943873100289F44; remoteInfo = Quick; }; 047655531949F4CB00B288BB /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = DAEB6B8D1943873100289F44; remoteInfo = Quick; }; 04765555194A327000B288BB /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = DAEB6B8D1943873100289F44; remoteInfo = Quick; }; 04DC97E4194B4A6000CE00B6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = DAEB6B8D1943873100289F44; remoteInfo = Quick; }; 04DC97E6194B4A6000CE00B6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = DAEB6B8D1943873100289F44; remoteInfo = Quick; }; 04DC97E8194B4B7E00CE00B6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = 5A5D117B19473F2100F6D13D; remoteInfo = "Quick-iOS"; }; 04DC97EA194B4B9B00CE00B6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = 5A5D117B19473F2100F6D13D; remoteInfo = "Quick-iOS"; }; 04DC97F0194B82DB00CE00B6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = DAEB6B8D1943873100289F44; remoteInfo = Quick; }; 04DC97F2194B82DE00CE00B6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = 5A5D117B19473F2100F6D13D; remoteInfo = "Quick-iOS"; }; 04DC97F6194B831200CE00B6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = 5A5D117B19473F2100F6D13D; remoteInfo = "Quick-iOS"; }; 04DC97F8194B834000CE00B6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = DAEB6B8D1943873100289F44; remoteInfo = Quick; }; 04DC97FA194B834100CE00B6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = 5A5D117B19473F2100F6D13D; remoteInfo = "Quick-iOS"; }; 04DC97FC194B834B00CE00B6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = DAEB6B8D1943873100289F44; remoteInfo = Quick; }; 04DC97FE194B835E00CE00B6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = 5A5D117B19473F2100F6D13D; remoteInfo = "Quick-iOS"; }; 04DC9800194B836100CE00B6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = DAEB6B8D1943873100289F44; remoteInfo = Quick; }; 04DC9802194B836300CE00B6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = 5A5D117B19473F2100F6D13D; remoteInfo = "Quick-iOS"; }; 04DC9804194B838400CE00B6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = DAEB6B8D1943873100289F44; remoteInfo = Quick; }; 04DC9806194B838700CE00B6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = 5A5D117B19473F2100F6D13D; remoteInfo = "Quick-iOS"; }; 04DC9808194B838B00CE00B6 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = DAEB6B8D1943873100289F44; remoteInfo = Quick; }; 1F118CE01BDCA4AB005013A2 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F118CD41BDCA4AB005013A2; remoteInfo = "Quick-tvOS"; }; 1F118CF61BDCA4BB005013A2 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = 1F118CD41BDCA4AB005013A2; remoteInfo = "Quick-tvOS"; }; 5A5D118819473F2100F6D13D /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = 5A5D117B19473F2100F6D13D; remoteInfo = "Quick-iOS"; }; 5A5D11EF194741B500F6D13D /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = 5A5D117B19473F2100F6D13D; remoteInfo = "Quick-iOS"; }; 5A5D11F1194741B500F6D13D /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = 5A5D117B19473F2100F6D13D; remoteInfo = "Quick-iOS"; }; 93625F381951DDC8006B1FE1 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = DAEB6B8D1943873100289F44; remoteInfo = Quick; }; DA5663EF1A4C8D8500193C88 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = DAEB6B8D1943873100289F44; remoteInfo = "Quick-OSX"; }; DA9876B91A4C70EB0004AA17 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = 5A5D117B19473F2100F6D13D; remoteInfo = "Quick-iOS"; }; DAEB6B9B1943873100289F44 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DAEB6B851943873100289F44 /* Project object */; proxyType = 1; remoteGlobalIDString = DAEB6B8D1943873100289F44; remoteInfo = Quick; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 1F118CD51BDCA4AB005013A2 /* Quick.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Quick.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1F118CDE1BDCA4AB005013A2 /* Quick-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Quick-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 1F118CF01BDCA4BB005013A2 /* QuickFocused-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "QuickFocused-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 1F118D341BDCA657005013A2 /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = "Externals/Nimble/build/Debug-appletvos/Nimble.framework"; sourceTree = ""; }; 1F118D361BDCA65C005013A2 /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = "Externals/Nimble/build/Debug-appletvos/Nimble.framework"; sourceTree = ""; }; 34F3759C19515CA700CE1B99 /* Callsite.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Callsite.swift; sourceTree = ""; }; 34F3759E19515CA700CE1B99 /* Example.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Example.swift; sourceTree = ""; }; 34F3759F19515CA700CE1B99 /* ExampleGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleGroup.swift; sourceTree = ""; }; 34F375A019515CA700CE1B99 /* NSString+QCKSelectorName.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+QCKSelectorName.h"; sourceTree = ""; }; 34F375A119515CA700CE1B99 /* NSString+QCKSelectorName.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+QCKSelectorName.m"; sourceTree = ""; }; 34F375A419515CA700CE1B99 /* QuickSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QuickSpec.h; sourceTree = ""; }; 34F375A519515CA700CE1B99 /* QuickSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QuickSpec.m; sourceTree = ""; }; 34F375A619515CA700CE1B99 /* World.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = World.swift; sourceTree = ""; }; 470D6EC91A43409600043E50 /* AfterEachTests+ObjC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "AfterEachTests+ObjC.m"; sourceTree = ""; }; 4715903F1A488F3F00FBA644 /* PendingTests+ObjC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "PendingTests+ObjC.m"; sourceTree = ""; }; 4728253A1A5EECCE008DC74F /* SharedExamplesTests+ObjC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SharedExamplesTests+ObjC.m"; sourceTree = ""; }; 4748E8931A6AEBB3009EC992 /* SharedExamples+BeforeEachTests+ObjC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SharedExamples+BeforeEachTests+ObjC.m"; sourceTree = ""; }; 477217391A59C1B00022013E /* AfterSuiteTests+ObjC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "AfterSuiteTests+ObjC.m"; sourceTree = ""; }; 47876F7B1A4999B0002575C7 /* BeforeSuiteTests+ObjC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "BeforeSuiteTests+ObjC.m"; sourceTree = ""; }; 479C31E11A36156E00DA8718 /* ItTests+ObjC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ItTests+ObjC.m"; sourceTree = ""; }; 47FAEA341A3F45ED005A1D2F /* BeforeEachTests+ObjC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "BeforeEachTests+ObjC.m"; sourceTree = ""; }; 5A5D117C19473F2100F6D13D /* Quick.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Quick.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 5A5D118619473F2100F6D13D /* Quick-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Quick-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; DA02C91819A8073100093156 /* ExampleMetadata.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleMetadata.swift; sourceTree = ""; }; DA05D60F19F73A3800771050 /* AfterEachTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AfterEachTests.swift; sourceTree = ""; }; DA169E4719FF5DF100619816 /* Configuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = ""; }; DA3124E219FCAEE8002858A7 /* DSL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DSL.swift; sourceTree = ""; }; DA3124E319FCAEE8002858A7 /* QCKDSL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QCKDSL.h; sourceTree = ""; }; DA3124E419FCAEE8002858A7 /* QCKDSL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QCKDSL.m; sourceTree = ""; }; DA3124E519FCAEE8002858A7 /* World+DSL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "World+DSL.swift"; sourceTree = ""; }; DA408BDF19FF5599005DF92A /* Closures.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Closures.swift; sourceTree = ""; }; DA408BE019FF5599005DF92A /* ExampleHooks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleHooks.swift; sourceTree = ""; }; DA408BE119FF5599005DF92A /* SuiteHooks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SuiteHooks.swift; sourceTree = ""; }; DA5663E81A4C8D8500193C88 /* QuickFocused-OSXTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "QuickFocused-OSXTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; DA6B30171A4DB0D500FFB148 /* Filter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Filter.swift; sourceTree = ""; }; DA7AE6F019FC493F000AFDCE /* ItTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItTests.swift; sourceTree = ""; }; DA87078219F48775008C04AC /* BeforeEachTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeforeEachTests.swift; sourceTree = ""; }; DA8940EF1B35B1FA00161061 /* FailureUsingXCTAssertTests+ObjC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "FailureUsingXCTAssertTests+ObjC.m"; sourceTree = ""; }; DA8C00201A01E4B900CE58A6 /* QuickConfigurationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QuickConfigurationTests.m; sourceTree = ""; }; DA8F919519F31680006F6675 /* QCKSpecRunner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QCKSpecRunner.h; sourceTree = ""; }; DA8F919619F31680006F6675 /* QCKSpecRunner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QCKSpecRunner.m; sourceTree = ""; }; DA8F919719F31680006F6675 /* QuickTestsBridgingHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QuickTestsBridgingHeader.h; sourceTree = ""; }; DA8F919819F31680006F6675 /* XCTestObservationCenter+QCKSuspendObservation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "XCTestObservationCenter+QCKSuspendObservation.h"; sourceTree = ""; }; DA8F919C19F31921006F6675 /* FailureTests+ObjC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "FailureTests+ObjC.m"; sourceTree = ""; }; DA8F91A419F3208B006F6675 /* BeforeSuiteTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeforeSuiteTests.swift; sourceTree = ""; }; DA8F91A719F32556006F6675 /* AfterSuiteTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AfterSuiteTests.swift; sourceTree = ""; }; DA8F91AA19F3299E006F6675 /* SharedExamplesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharedExamplesTests.swift; sourceTree = ""; }; DA8F91AD19F32CE2006F6675 /* FunctionalTests_SharedExamplesTests_SharedExamples.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FunctionalTests_SharedExamplesTests_SharedExamples.swift; sourceTree = ""; }; DA9876B21A4C70EB0004AA17 /* QuickFocused-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "QuickFocused-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; DA9876BF1A4C87200004AA17 /* FocusedTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FocusedTests.swift; sourceTree = ""; }; DA9876C01A4C87200004AA17 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DAA63EA219F7637300CD0A3B /* PendingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PendingTests.swift; sourceTree = ""; }; DAB0136E19FC4315006AFBEE /* SharedExamples+BeforeEachTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SharedExamples+BeforeEachTests.swift"; sourceTree = ""; }; DAE714EF19FF65D3005905B8 /* Configuration+BeforeEachTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Configuration+BeforeEachTests.swift"; sourceTree = ""; }; DAE714F219FF65E7005905B8 /* Configuration+BeforeEach.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Configuration+BeforeEach.swift"; sourceTree = ""; }; DAE714F619FF6812005905B8 /* Configuration+AfterEach.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Configuration+AfterEach.swift"; sourceTree = ""; }; DAE714F919FF682A005905B8 /* Configuration+AfterEachTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Configuration+AfterEachTests.swift"; sourceTree = ""; }; DAE714FC19FF6A62005905B8 /* QuickConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QuickConfiguration.h; sourceTree = ""; }; DAE714FD19FF6A62005905B8 /* QuickConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QuickConfiguration.m; sourceTree = ""; }; DAEB6B8E1943873100289F44 /* Quick.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Quick.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DAEB6B921943873100289F44 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DAEB6B931943873100289F44 /* Quick.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Quick.h; sourceTree = ""; }; DAEB6B991943873100289F44 /* Quick-OSXTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Quick-OSXTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; DAEB6B9F1943873100289F44 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DAED1EC21B1105BC006F61EC /* World.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = World.h; sourceTree = ""; }; DAED1EC81B110699006F61EC /* World+DSL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "World+DSL.h"; sourceTree = ""; }; DAF28BC21A4DB8EC00A5D9BF /* FocusedTests+ObjC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "FocusedTests+ObjC.m"; sourceTree = ""; }; F8100E901A1E4447007595ED /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Nimble.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 1F118CD11BDCA4AB005013A2 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F118CDB1BDCA4AB005013A2 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 1F118CDF1BDCA4AB005013A2 /* Quick.framework in Frameworks */, 1F118D351BDCA657005013A2 /* Nimble.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F118CED1BDCA4BB005013A2 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 1F118CF51BDCA4BB005013A2 /* Quick.framework in Frameworks */, 1F118D371BDCA65C005013A2 /* Nimble.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 5A5D117819473F2100F6D13D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 5A5D118319473F2100F6D13D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 5A5D118719473F2100F6D13D /* Quick.framework in Frameworks */, DA3E7A351A1E66CB00CCE408 /* Nimble.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; DA5663E51A4C8D8500193C88 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( DA5663EE1A4C8D8500193C88 /* Quick.framework in Frameworks */, 1FD0CFAD1AFA0B8C00874CC1 /* Nimble.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; DA9876AF1A4C70EB0004AA17 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( DA9876B81A4C70EB0004AA17 /* Quick.framework in Frameworks */, DAD297651AA8129D001D25CD /* Nimble.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; DAEB6B8A1943873100289F44 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; DAEB6B961943873100289F44 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( DA3E7A341A1E66C600CCE408 /* Nimble.framework in Frameworks */, DAEB6B9A1943873100289F44 /* Quick.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 1F118D331BDCA645005013A2 /* Frameworks */ = { isa = PBXGroup; children = ( 1F118D361BDCA65C005013A2 /* Nimble.framework */, 1F118D341BDCA657005013A2 /* Nimble.framework */, ); name = Frameworks; sourceTree = ""; }; DA169E4619FF5DF100619816 /* Configuration */ = { isa = PBXGroup; children = ( DAE714FC19FF6A62005905B8 /* QuickConfiguration.h */, DAE714FD19FF6A62005905B8 /* QuickConfiguration.m */, DA169E4719FF5DF100619816 /* Configuration.swift */, ); path = Configuration; sourceTree = ""; }; DA3124E119FCAEE8002858A7 /* DSL */ = { isa = PBXGroup; children = ( DA3124E519FCAEE8002858A7 /* World+DSL.swift */, DAED1EC81B110699006F61EC /* World+DSL.h */, DA3124E219FCAEE8002858A7 /* DSL.swift */, DA3124E319FCAEE8002858A7 /* QCKDSL.h */, DA3124E419FCAEE8002858A7 /* QCKDSL.m */, ); path = DSL; sourceTree = ""; }; DA408BDE19FF5599005DF92A /* Hooks */ = { isa = PBXGroup; children = ( DA408BDF19FF5599005DF92A /* Closures.swift */, DA408BE019FF5599005DF92A /* ExampleHooks.swift */, DA408BE119FF5599005DF92A /* SuiteHooks.swift */, ); path = Hooks; sourceTree = ""; }; DA8F919419F31680006F6675 /* Helpers */ = { isa = PBXGroup; children = ( DA8F919719F31680006F6675 /* QuickTestsBridgingHeader.h */, DA8F919519F31680006F6675 /* QCKSpecRunner.h */, DA8F919619F31680006F6675 /* QCKSpecRunner.m */, DA8F919819F31680006F6675 /* XCTestObservationCenter+QCKSuspendObservation.h */, ); path = Helpers; sourceTree = ""; }; DA8F919B19F3189D006F6675 /* FunctionalTests */ = { isa = PBXGroup; children = ( DAE714E919FF65A6005905B8 /* Configuration */, DA7AE6F019FC493F000AFDCE /* ItTests.swift */, 479C31E11A36156E00DA8718 /* ItTests+ObjC.m */, DA8F919C19F31921006F6675 /* FailureTests+ObjC.m */, DA8940EF1B35B1FA00161061 /* FailureUsingXCTAssertTests+ObjC.m */, DA87078219F48775008C04AC /* BeforeEachTests.swift */, 47FAEA341A3F45ED005A1D2F /* BeforeEachTests+ObjC.m */, DA05D60F19F73A3800771050 /* AfterEachTests.swift */, 470D6EC91A43409600043E50 /* AfterEachTests+ObjC.m */, DAA63EA219F7637300CD0A3B /* PendingTests.swift */, 4715903F1A488F3F00FBA644 /* PendingTests+ObjC.m */, DA8F91A419F3208B006F6675 /* BeforeSuiteTests.swift */, 47876F7B1A4999B0002575C7 /* BeforeSuiteTests+ObjC.m */, DA8F91A719F32556006F6675 /* AfterSuiteTests.swift */, 477217391A59C1B00022013E /* AfterSuiteTests+ObjC.m */, DA8F91AA19F3299E006F6675 /* SharedExamplesTests.swift */, 4728253A1A5EECCE008DC74F /* SharedExamplesTests+ObjC.m */, DAB0136E19FC4315006AFBEE /* SharedExamples+BeforeEachTests.swift */, 4748E8931A6AEBB3009EC992 /* SharedExamples+BeforeEachTests+ObjC.m */, ); path = FunctionalTests; sourceTree = ""; }; DA9876BE1A4C87200004AA17 /* QuickFocusedTests */ = { isa = PBXGroup; children = ( DA9876BF1A4C87200004AA17 /* FocusedTests.swift */, DAF28BC21A4DB8EC00A5D9BF /* FocusedTests+ObjC.m */, DA9876C31A4C87310004AA17 /* Supporting Files */, ); path = QuickFocusedTests; sourceTree = ""; }; DA9876C31A4C87310004AA17 /* Supporting Files */ = { isa = PBXGroup; children = ( DA9876C01A4C87200004AA17 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; DAE714E919FF65A6005905B8 /* Configuration */ = { isa = PBXGroup; children = ( DAE714F519FF67FF005905B8 /* AfterEach */, DAE714EA19FF65A6005905B8 /* BeforeEach */, ); path = Configuration; sourceTree = ""; }; DAE714EA19FF65A6005905B8 /* BeforeEach */ = { isa = PBXGroup; children = ( DAE714F219FF65E7005905B8 /* Configuration+BeforeEach.swift */, DAE714EF19FF65D3005905B8 /* Configuration+BeforeEachTests.swift */, ); path = BeforeEach; sourceTree = ""; }; DAE714F519FF67FF005905B8 /* AfterEach */ = { isa = PBXGroup; children = ( DAE714F619FF6812005905B8 /* Configuration+AfterEach.swift */, DAE714F919FF682A005905B8 /* Configuration+AfterEachTests.swift */, ); path = AfterEach; sourceTree = ""; }; DAEB6B841943873100289F44 = { isa = PBXGroup; children = ( DAEB6B901943873100289F44 /* Quick */, DAEB6B9D1943873100289F44 /* QuickTests */, DA9876BE1A4C87200004AA17 /* QuickFocusedTests */, DAEB6B8F1943873100289F44 /* Products */, 1F118D331BDCA645005013A2 /* Frameworks */, ); indentWidth = 4; sourceTree = ""; tabWidth = 4; }; DAEB6B8F1943873100289F44 /* Products */ = { isa = PBXGroup; children = ( DAEB6B8E1943873100289F44 /* Quick.framework */, DAEB6B991943873100289F44 /* Quick-OSXTests.xctest */, 5A5D117C19473F2100F6D13D /* Quick.framework */, 5A5D118619473F2100F6D13D /* Quick-iOSTests.xctest */, DA9876B21A4C70EB0004AA17 /* QuickFocused-iOSTests.xctest */, DA5663E81A4C8D8500193C88 /* QuickFocused-OSXTests.xctest */, 1F118CD51BDCA4AB005013A2 /* Quick.framework */, 1F118CDE1BDCA4AB005013A2 /* Quick-tvOSTests.xctest */, 1F118CF01BDCA4BB005013A2 /* QuickFocused-tvOSTests.xctest */, ); name = Products; sourceTree = ""; }; DAEB6B901943873100289F44 /* Quick */ = { isa = PBXGroup; children = ( DA169E4619FF5DF100619816 /* Configuration */, DA3124E119FCAEE8002858A7 /* DSL */, DA408BDE19FF5599005DF92A /* Hooks */, DAEB6B931943873100289F44 /* Quick.h */, 34F375A619515CA700CE1B99 /* World.swift */, DAED1EC21B1105BC006F61EC /* World.h */, 34F3759E19515CA700CE1B99 /* Example.swift */, DA02C91819A8073100093156 /* ExampleMetadata.swift */, 34F3759F19515CA700CE1B99 /* ExampleGroup.swift */, 34F3759C19515CA700CE1B99 /* Callsite.swift */, DA6B30171A4DB0D500FFB148 /* Filter.swift */, 34F375A419515CA700CE1B99 /* QuickSpec.h */, 34F375A519515CA700CE1B99 /* QuickSpec.m */, 34F375A019515CA700CE1B99 /* NSString+QCKSelectorName.h */, 34F375A119515CA700CE1B99 /* NSString+QCKSelectorName.m */, DAEB6B911943873100289F44 /* Supporting Files */, ); path = Quick; sourceTree = ""; }; DAEB6B911943873100289F44 /* Supporting Files */ = { isa = PBXGroup; children = ( DAEB6B921943873100289F44 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; DAEB6B9D1943873100289F44 /* QuickTests */ = { isa = PBXGroup; children = ( DA8C00201A01E4B900CE58A6 /* QuickConfigurationTests.m */, DA8F919419F31680006F6675 /* Helpers */, DAEB6BCD194387D700289F44 /* Fixtures */, DA8F919B19F3189D006F6675 /* FunctionalTests */, F8100E941A1E4469007595ED /* Frameworks */, DAEB6B9E1943873100289F44 /* Supporting Files */, ); path = QuickTests; sourceTree = ""; }; DAEB6B9E1943873100289F44 /* Supporting Files */ = { isa = PBXGroup; children = ( DAEB6B9F1943873100289F44 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; DAEB6BCD194387D700289F44 /* Fixtures */ = { isa = PBXGroup; children = ( DA8F91AD19F32CE2006F6675 /* FunctionalTests_SharedExamplesTests_SharedExamples.swift */, ); path = Fixtures; sourceTree = ""; }; F8100E941A1E4469007595ED /* Frameworks */ = { isa = PBXGroup; children = ( F8100E901A1E4447007595ED /* Nimble.framework */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 1F118CD21BDCA4AB005013A2 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 1F118D2B1BDCA5B6005013A2 /* Quick.h in Headers */, 1F118D261BDCA5AF005013A2 /* World+DSL.h in Headers */, 1F118D271BDCA5AF005013A2 /* World.h in Headers */, 1F118D2A1BDCA5B6005013A2 /* QCKDSL.h in Headers */, 1F118D2C1BDCA5B6005013A2 /* QuickSpec.h in Headers */, 1F118D281BDCA5AF005013A2 /* NSString+QCKSelectorName.h in Headers */, 1F118D291BDCA5B6005013A2 /* QuickConfiguration.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; 5A5D117919473F2100F6D13D /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 34F375B019515CA700CE1B99 /* NSString+QCKSelectorName.h in Headers */, DAE714FF19FF6A62005905B8 /* QuickConfiguration.h in Headers */, DA3124E919FCAEE8002858A7 /* QCKDSL.h in Headers */, DAED1ECB1B110699006F61EC /* World+DSL.h in Headers */, DAED1EC51B1105BC006F61EC /* World.h in Headers */, 34F375B819515CA700CE1B99 /* QuickSpec.h in Headers */, 5A5D11A7194740E000F6D13D /* Quick.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; DAEB6B8B1943873100289F44 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 34F375AF19515CA700CE1B99 /* NSString+QCKSelectorName.h in Headers */, DAE714FE19FF6A62005905B8 /* QuickConfiguration.h in Headers */, DA3124E819FCAEE8002858A7 /* QCKDSL.h in Headers */, DAED1ECA1B110699006F61EC /* World+DSL.h in Headers */, DAED1EC41B1105BC006F61EC /* World.h in Headers */, 34F375B719515CA700CE1B99 /* QuickSpec.h in Headers */, DAEB6B941943873100289F44 /* Quick.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 1F118CD41BDCA4AB005013A2 /* Quick-tvOS */ = { isa = PBXNativeTarget; buildConfigurationList = 1F118CE61BDCA4AB005013A2 /* Build configuration list for PBXNativeTarget "Quick-tvOS" */; buildPhases = ( 1F118CD01BDCA4AB005013A2 /* Sources */, 1F118CD11BDCA4AB005013A2 /* Frameworks */, 1F118CD21BDCA4AB005013A2 /* Headers */, 1F118CD31BDCA4AB005013A2 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Quick-tvOS"; productName = "Quick-tvOS"; productReference = 1F118CD51BDCA4AB005013A2 /* Quick.framework */; productType = "com.apple.product-type.framework"; }; 1F118CDD1BDCA4AB005013A2 /* Quick-tvOSTests */ = { isa = PBXNativeTarget; buildConfigurationList = 1F118CE91BDCA4AB005013A2 /* Build configuration list for PBXNativeTarget "Quick-tvOSTests" */; buildPhases = ( 1F118CDA1BDCA4AB005013A2 /* Sources */, 1F118CDB1BDCA4AB005013A2 /* Frameworks */, 1F118CDC1BDCA4AB005013A2 /* Resources */, ); buildRules = ( ); dependencies = ( 1F118CE11BDCA4AB005013A2 /* PBXTargetDependency */, ); name = "Quick-tvOSTests"; productName = "Quick-tvOSTests"; productReference = 1F118CDE1BDCA4AB005013A2 /* Quick-tvOSTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 1F118CEF1BDCA4BB005013A2 /* QuickFocused-tvOSTests */ = { isa = PBXNativeTarget; buildConfigurationList = 1F118CF81BDCA4BC005013A2 /* Build configuration list for PBXNativeTarget "QuickFocused-tvOSTests" */; buildPhases = ( 1F118CEC1BDCA4BB005013A2 /* Sources */, 1F118CED1BDCA4BB005013A2 /* Frameworks */, 1F118CEE1BDCA4BB005013A2 /* Resources */, ); buildRules = ( ); dependencies = ( 1F118CF71BDCA4BB005013A2 /* PBXTargetDependency */, ); name = "QuickFocused-tvOSTests"; productName = "QuickFocused-tvOSTests"; productReference = 1F118CF01BDCA4BB005013A2 /* QuickFocused-tvOSTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 5A5D117B19473F2100F6D13D /* Quick-iOS */ = { isa = PBXNativeTarget; buildConfigurationList = 5A5D119319473F2100F6D13D /* Build configuration list for PBXNativeTarget "Quick-iOS" */; buildPhases = ( 5A5D117719473F2100F6D13D /* Sources */, 5A5D117819473F2100F6D13D /* Frameworks */, 5A5D117919473F2100F6D13D /* Headers */, 5A5D117A19473F2100F6D13D /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Quick-iOS"; productName = "Quick-iOS"; productReference = 5A5D117C19473F2100F6D13D /* Quick.framework */; productType = "com.apple.product-type.framework"; }; 5A5D118519473F2100F6D13D /* Quick-iOSTests */ = { isa = PBXNativeTarget; buildConfigurationList = 5A5D119419473F2100F6D13D /* Build configuration list for PBXNativeTarget "Quick-iOSTests" */; buildPhases = ( 5A5D118219473F2100F6D13D /* Sources */, 5A5D118319473F2100F6D13D /* Frameworks */, 5A5D118419473F2100F6D13D /* Resources */, ); buildRules = ( ); dependencies = ( 5A5D118919473F2100F6D13D /* PBXTargetDependency */, 5A5D11F0194741B500F6D13D /* PBXTargetDependency */, 5A5D11F2194741B500F6D13D /* PBXTargetDependency */, 04DC97E9194B4B7E00CE00B6 /* PBXTargetDependency */, 04DC97EB194B4B9B00CE00B6 /* PBXTargetDependency */, 04DC97F3194B82DE00CE00B6 /* PBXTargetDependency */, 04DC97F7194B831200CE00B6 /* PBXTargetDependency */, 04DC97FB194B834100CE00B6 /* PBXTargetDependency */, 04DC97FF194B835E00CE00B6 /* PBXTargetDependency */, 04DC9803194B836300CE00B6 /* PBXTargetDependency */, 04DC9807194B838700CE00B6 /* PBXTargetDependency */, ); name = "Quick-iOSTests"; productName = "Quick-iOSTests"; productReference = 5A5D118619473F2100F6D13D /* Quick-iOSTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; DA5663E71A4C8D8500193C88 /* QuickFocused-OSXTests */ = { isa = PBXNativeTarget; buildConfigurationList = DA5663F31A4C8D8500193C88 /* Build configuration list for PBXNativeTarget "QuickFocused-OSXTests" */; buildPhases = ( DA5663E41A4C8D8500193C88 /* Sources */, DA5663E51A4C8D8500193C88 /* Frameworks */, DA5663E61A4C8D8500193C88 /* Resources */, ); buildRules = ( ); dependencies = ( DA5663F01A4C8D8500193C88 /* PBXTargetDependency */, ); name = "QuickFocused-OSXTests"; productName = "QuickFocused-OSXTests"; productReference = DA5663E81A4C8D8500193C88 /* QuickFocused-OSXTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; DA9876B11A4C70EB0004AA17 /* QuickFocused-iOSTests */ = { isa = PBXNativeTarget; buildConfigurationList = DA9876BD1A4C70EB0004AA17 /* Build configuration list for PBXNativeTarget "QuickFocused-iOSTests" */; buildPhases = ( DA9876AE1A4C70EB0004AA17 /* Sources */, DA9876AF1A4C70EB0004AA17 /* Frameworks */, DA9876B01A4C70EB0004AA17 /* Resources */, ); buildRules = ( ); dependencies = ( DA9876BA1A4C70EB0004AA17 /* PBXTargetDependency */, ); name = "QuickFocused-iOSTests"; productName = "QuickFocused-iOSTests"; productReference = DA9876B21A4C70EB0004AA17 /* QuickFocused-iOSTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; DAEB6B8D1943873100289F44 /* Quick-OSX */ = { isa = PBXNativeTarget; buildConfigurationList = DAEB6BA41943873200289F44 /* Build configuration list for PBXNativeTarget "Quick-OSX" */; buildPhases = ( DAEB6B891943873100289F44 /* Sources */, DAEB6B8A1943873100289F44 /* Frameworks */, DAEB6B8B1943873100289F44 /* Headers */, DAEB6B8C1943873100289F44 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Quick-OSX"; productName = Quick; productReference = DAEB6B8E1943873100289F44 /* Quick.framework */; productType = "com.apple.product-type.framework"; }; DAEB6B981943873100289F44 /* Quick-OSXTests */ = { isa = PBXNativeTarget; buildConfigurationList = DAEB6BA71943873200289F44 /* Build configuration list for PBXNativeTarget "Quick-OSXTests" */; buildPhases = ( DAEB6B951943873100289F44 /* Sources */, DAEB6B961943873100289F44 /* Frameworks */, DAEB6B971943873100289F44 /* Resources */, ); buildRules = ( ); dependencies = ( DAEB6B9C1943873100289F44 /* PBXTargetDependency */, 047655521949F4CB00B288BB /* PBXTargetDependency */, 047655541949F4CB00B288BB /* PBXTargetDependency */, 04765556194A327000B288BB /* PBXTargetDependency */, 04DC97E5194B4A6000CE00B6 /* PBXTargetDependency */, 04DC97E7194B4A6000CE00B6 /* PBXTargetDependency */, 04DC97F1194B82DB00CE00B6 /* PBXTargetDependency */, 04DC97F9194B834000CE00B6 /* PBXTargetDependency */, 04DC97FD194B834B00CE00B6 /* PBXTargetDependency */, 04DC9801194B836100CE00B6 /* PBXTargetDependency */, 04DC9805194B838400CE00B6 /* PBXTargetDependency */, 04DC9809194B838B00CE00B6 /* PBXTargetDependency */, 93625F391951DDC8006B1FE1 /* PBXTargetDependency */, ); name = "Quick-OSXTests"; productName = QuickTests; productReference = DAEB6B991943873100289F44 /* Quick-OSXTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ DAEB6B851943873100289F44 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0710; LastUpgradeCheck = 0700; ORGANIZATIONNAME = "Brian Ivan Gesiak"; TargetAttributes = { 1F118CD41BDCA4AB005013A2 = { CreatedOnToolsVersion = 7.1; }; 1F118CDD1BDCA4AB005013A2 = { CreatedOnToolsVersion = 7.1; }; 1F118CEF1BDCA4BB005013A2 = { CreatedOnToolsVersion = 7.1; }; 5A5D117B19473F2100F6D13D = { CreatedOnToolsVersion = 6.0; }; 5A5D118519473F2100F6D13D = { CreatedOnToolsVersion = 6.0; TestTargetID = 5A5D117B19473F2100F6D13D; }; DA5663E71A4C8D8500193C88 = { CreatedOnToolsVersion = 6.2; }; DA9876B11A4C70EB0004AA17 = { CreatedOnToolsVersion = 6.2; }; DAEB6B8D1943873100289F44 = { CreatedOnToolsVersion = 6.0; }; DAEB6B981943873100289F44 = { CreatedOnToolsVersion = 6.0; TestTargetID = DAEB6B8D1943873100289F44; }; }; }; buildConfigurationList = DAEB6B881943873100289F44 /* Build configuration list for PBXProject "Quick" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = DAEB6B841943873100289F44; productRefGroup = DAEB6B8F1943873100289F44 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( DAEB6B8D1943873100289F44 /* Quick-OSX */, DAEB6B981943873100289F44 /* Quick-OSXTests */, DA5663E71A4C8D8500193C88 /* QuickFocused-OSXTests */, 5A5D117B19473F2100F6D13D /* Quick-iOS */, 5A5D118519473F2100F6D13D /* Quick-iOSTests */, DA9876B11A4C70EB0004AA17 /* QuickFocused-iOSTests */, 1F118CD41BDCA4AB005013A2 /* Quick-tvOS */, 1F118CDD1BDCA4AB005013A2 /* Quick-tvOSTests */, 1F118CEF1BDCA4BB005013A2 /* QuickFocused-tvOSTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 1F118CD31BDCA4AB005013A2 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F118CDC1BDCA4AB005013A2 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 1F118CEE1BDCA4BB005013A2 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 5A5D117A19473F2100F6D13D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 5A5D118419473F2100F6D13D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; DA5663E61A4C8D8500193C88 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; DA9876B01A4C70EB0004AA17 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; DAEB6B8C1943873100289F44 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; DAEB6B971943873100289F44 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 1F118CD01BDCA4AB005013A2 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 1F118D031BDCA536005013A2 /* World.swift in Sources */, 1F118CFC1BDCA536005013A2 /* Configuration.swift in Sources */, 1F118D021BDCA536005013A2 /* SuiteHooks.swift in Sources */, 1F118CFB1BDCA536005013A2 /* QuickConfiguration.m in Sources */, 1F118D041BDCA536005013A2 /* Example.swift in Sources */, 1F118CFF1BDCA536005013A2 /* QCKDSL.m in Sources */, 1F118D071BDCA536005013A2 /* Callsite.swift in Sources */, 1F118D081BDCA536005013A2 /* Filter.swift in Sources */, 1F118CFD1BDCA536005013A2 /* World+DSL.swift in Sources */, 1F118D0A1BDCA536005013A2 /* NSString+QCKSelectorName.m in Sources */, 1F118CFE1BDCA536005013A2 /* DSL.swift in Sources */, 1F118D001BDCA536005013A2 /* Closures.swift in Sources */, 1F118D051BDCA536005013A2 /* ExampleMetadata.swift in Sources */, 1F118D061BDCA536005013A2 /* ExampleGroup.swift in Sources */, 1F118D091BDCA536005013A2 /* QuickSpec.m in Sources */, 1F118D011BDCA536005013A2 /* ExampleHooks.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F118CDA1BDCA4AB005013A2 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 1F118D381BDCA6E1005013A2 /* Configuration+BeforeEachTests.swift in Sources */, 1F118D121BDCA556005013A2 /* ItTests.swift in Sources */, 1F118D1C1BDCA556005013A2 /* BeforeSuiteTests.swift in Sources */, 1F118D1D1BDCA556005013A2 /* BeforeSuiteTests+ObjC.m in Sources */, 1F118D0E1BDCA547005013A2 /* QCKSpecRunner.m in Sources */, 1F118D141BDCA556005013A2 /* FailureTests+ObjC.m in Sources */, 1F118D0F1BDCA54B005013A2 /* FunctionalTests_SharedExamplesTests_SharedExamples.swift in Sources */, 1F118D101BDCA556005013A2 /* Configuration+AfterEach.swift in Sources */, 1F118D1F1BDCA556005013A2 /* AfterSuiteTests+ObjC.m in Sources */, 1F118D1A1BDCA556005013A2 /* PendingTests.swift in Sources */, 1F118D171BDCA556005013A2 /* BeforeEachTests+ObjC.m in Sources */, 1F118D231BDCA556005013A2 /* SharedExamples+BeforeEachTests+ObjC.m in Sources */, 1F118D151BDCA556005013A2 /* FailureUsingXCTAssertTests+ObjC.m in Sources */, 1F118D131BDCA556005013A2 /* ItTests+ObjC.m in Sources */, 1F118D191BDCA556005013A2 /* AfterEachTests+ObjC.m in Sources */, 1F118D221BDCA556005013A2 /* SharedExamples+BeforeEachTests.swift in Sources */, 1F118D211BDCA556005013A2 /* SharedExamplesTests+ObjC.m in Sources */, 1F118D201BDCA556005013A2 /* SharedExamplesTests.swift in Sources */, 1F118D0C1BDCA543005013A2 /* QuickConfigurationTests.m in Sources */, 1F118D391BDCA6E6005013A2 /* Configuration+BeforeEach.swift in Sources */, 1F118D181BDCA556005013A2 /* AfterEachTests.swift in Sources */, 1F118D1B1BDCA556005013A2 /* PendingTests+ObjC.m in Sources */, 1F118D1E1BDCA556005013A2 /* AfterSuiteTests.swift in Sources */, 1F118D111BDCA556005013A2 /* Configuration+AfterEachTests.swift in Sources */, 1F118D161BDCA556005013A2 /* BeforeEachTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 1F118CEC1BDCA4BB005013A2 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 1F118D0D1BDCA547005013A2 /* QCKSpecRunner.m in Sources */, 1F118D241BDCA561005013A2 /* FocusedTests.swift in Sources */, 1F118D251BDCA561005013A2 /* FocusedTests+ObjC.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 5A5D117719473F2100F6D13D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 34F375B219515CA700CE1B99 /* NSString+QCKSelectorName.m in Sources */, DA3124EB19FCAEE8002858A7 /* QCKDSL.m in Sources */, DA408BE319FF5599005DF92A /* Closures.swift in Sources */, DA02C91A19A8073100093156 /* ExampleMetadata.swift in Sources */, DA408BE719FF5599005DF92A /* SuiteHooks.swift in Sources */, 34F375BA19515CA700CE1B99 /* QuickSpec.m in Sources */, DAE7150119FF6A62005905B8 /* QuickConfiguration.m in Sources */, 34F375A819515CA700CE1B99 /* Callsite.swift in Sources */, 34F375AE19515CA700CE1B99 /* ExampleGroup.swift in Sources */, 34F375BC19515CA700CE1B99 /* World.swift in Sources */, DA169E4919FF5DF100619816 /* Configuration.swift in Sources */, DA3124ED19FCAEE8002858A7 /* World+DSL.swift in Sources */, DA408BE519FF5599005DF92A /* ExampleHooks.swift in Sources */, 34F375AC19515CA700CE1B99 /* Example.swift in Sources */, DA3124E719FCAEE8002858A7 /* DSL.swift in Sources */, DA6B30191A4DB0D500FFB148 /* Filter.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 5A5D118219473F2100F6D13D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( DAE714F819FF6812005905B8 /* Configuration+AfterEach.swift in Sources */, DAA7C0D719F777EB0093D1D9 /* BeforeEachTests.swift in Sources */, DA8F919A19F31680006F6675 /* QCKSpecRunner.m in Sources */, DA8940F11B35B1FA00161061 /* FailureUsingXCTAssertTests+ObjC.m in Sources */, 4728253C1A5EECCE008DC74F /* SharedExamplesTests+ObjC.m in Sources */, DAE714F119FF65D3005905B8 /* Configuration+BeforeEachTests.swift in Sources */, DA05D61119F73A3800771050 /* AfterEachTests.swift in Sources */, DAB0137019FC4315006AFBEE /* SharedExamples+BeforeEachTests.swift in Sources */, DA8F91A619F3208B006F6675 /* BeforeSuiteTests.swift in Sources */, DA8C00221A01E4B900CE58A6 /* QuickConfigurationTests.m in Sources */, DAA63EA419F7637300CD0A3B /* PendingTests.swift in Sources */, DA8F91AC19F3299E006F6675 /* SharedExamplesTests.swift in Sources */, DA7AE6F219FC493F000AFDCE /* ItTests.swift in Sources */, 4748E8951A6AEBB3009EC992 /* SharedExamples+BeforeEachTests+ObjC.m in Sources */, DA8F91AF19F32CE2006F6675 /* FunctionalTests_SharedExamplesTests_SharedExamples.swift in Sources */, DAE714FB19FF682A005905B8 /* Configuration+AfterEachTests.swift in Sources */, 471590411A488F3F00FBA644 /* PendingTests+ObjC.m in Sources */, DA8F919E19F31921006F6675 /* FailureTests+ObjC.m in Sources */, DAE714F419FF65E7005905B8 /* Configuration+BeforeEach.swift in Sources */, DA8F91A919F32556006F6675 /* AfterSuiteTests.swift in Sources */, 4772173B1A59C1B00022013E /* AfterSuiteTests+ObjC.m in Sources */, 479C31E41A36172700DA8718 /* ItTests+ObjC.m in Sources */, 47FAEA371A3F49EB005A1D2F /* BeforeEachTests+ObjC.m in Sources */, 470D6ECC1A43442900043E50 /* AfterEachTests+ObjC.m in Sources */, 47876F7E1A49AD71002575C7 /* BeforeSuiteTests+ObjC.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; DA5663E41A4C8D8500193C88 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( DA07722E1A4E5B7B0098839D /* QCKSpecRunner.m in Sources */, DA5663F41A4C8D9A00193C88 /* FocusedTests.swift in Sources */, DAF28BC31A4DB8EC00A5D9BF /* FocusedTests+ObjC.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; DA9876AE1A4C70EB0004AA17 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( DA07722F1A4E5B7C0098839D /* QCKSpecRunner.m in Sources */, DA9876C11A4C87200004AA17 /* FocusedTests.swift in Sources */, DAF28BC41A4DB8EC00A5D9BF /* FocusedTests+ObjC.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; DAEB6B891943873100289F44 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 34F375B119515CA700CE1B99 /* NSString+QCKSelectorName.m in Sources */, DA3124EA19FCAEE8002858A7 /* QCKDSL.m in Sources */, DA408BE219FF5599005DF92A /* Closures.swift in Sources */, DA02C91919A8073100093156 /* ExampleMetadata.swift in Sources */, DA408BE619FF5599005DF92A /* SuiteHooks.swift in Sources */, 34F375B919515CA700CE1B99 /* QuickSpec.m in Sources */, DAE7150019FF6A62005905B8 /* QuickConfiguration.m in Sources */, 34F375A719515CA700CE1B99 /* Callsite.swift in Sources */, 34F375AD19515CA700CE1B99 /* ExampleGroup.swift in Sources */, 34F375BB19515CA700CE1B99 /* World.swift in Sources */, DA169E4819FF5DF100619816 /* Configuration.swift in Sources */, DA3124EC19FCAEE8002858A7 /* World+DSL.swift in Sources */, DA408BE419FF5599005DF92A /* ExampleHooks.swift in Sources */, 34F375AB19515CA700CE1B99 /* Example.swift in Sources */, DA3124E619FCAEE8002858A7 /* DSL.swift in Sources */, DA6B30181A4DB0D500FFB148 /* Filter.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; DAEB6B951943873100289F44 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( DAE714F719FF6812005905B8 /* Configuration+AfterEach.swift in Sources */, DAB067E919F7801C00F970AC /* BeforeEachTests.swift in Sources */, DA8F919919F31680006F6675 /* QCKSpecRunner.m in Sources */, DA8940F01B35B1FA00161061 /* FailureUsingXCTAssertTests+ObjC.m in Sources */, 4728253B1A5EECCE008DC74F /* SharedExamplesTests+ObjC.m in Sources */, DAE714F019FF65D3005905B8 /* Configuration+BeforeEachTests.swift in Sources */, DA05D61019F73A3800771050 /* AfterEachTests.swift in Sources */, DAB0136F19FC4315006AFBEE /* SharedExamples+BeforeEachTests.swift in Sources */, DA8F91A519F3208B006F6675 /* BeforeSuiteTests.swift in Sources */, DA8C00211A01E4B900CE58A6 /* QuickConfigurationTests.m in Sources */, DAA63EA319F7637300CD0A3B /* PendingTests.swift in Sources */, DA8F91AB19F3299E006F6675 /* SharedExamplesTests.swift in Sources */, DA7AE6F119FC493F000AFDCE /* ItTests.swift in Sources */, 4748E8941A6AEBB3009EC992 /* SharedExamples+BeforeEachTests+ObjC.m in Sources */, DA8F91AE19F32CE2006F6675 /* FunctionalTests_SharedExamplesTests_SharedExamples.swift in Sources */, DAE714FA19FF682A005905B8 /* Configuration+AfterEachTests.swift in Sources */, 471590401A488F3F00FBA644 /* PendingTests+ObjC.m in Sources */, DA8F919D19F31921006F6675 /* FailureTests+ObjC.m in Sources */, DAE714F319FF65E7005905B8 /* Configuration+BeforeEach.swift in Sources */, DA8F91A819F32556006F6675 /* AfterSuiteTests.swift in Sources */, 4772173A1A59C1B00022013E /* AfterSuiteTests+ObjC.m in Sources */, 479C31E31A36171B00DA8718 /* ItTests+ObjC.m in Sources */, 47FAEA361A3F49E6005A1D2F /* BeforeEachTests+ObjC.m in Sources */, 470D6ECB1A43442400043E50 /* AfterEachTests+ObjC.m in Sources */, 47876F7D1A49AD63002575C7 /* BeforeSuiteTests+ObjC.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 047655521949F4CB00B288BB /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DAEB6B8D1943873100289F44 /* Quick-OSX */; targetProxy = 047655511949F4CB00B288BB /* PBXContainerItemProxy */; }; 047655541949F4CB00B288BB /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DAEB6B8D1943873100289F44 /* Quick-OSX */; targetProxy = 047655531949F4CB00B288BB /* PBXContainerItemProxy */; }; 04765556194A327000B288BB /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DAEB6B8D1943873100289F44 /* Quick-OSX */; targetProxy = 04765555194A327000B288BB /* PBXContainerItemProxy */; }; 04DC97E5194B4A6000CE00B6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DAEB6B8D1943873100289F44 /* Quick-OSX */; targetProxy = 04DC97E4194B4A6000CE00B6 /* PBXContainerItemProxy */; }; 04DC97E7194B4A6000CE00B6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DAEB6B8D1943873100289F44 /* Quick-OSX */; targetProxy = 04DC97E6194B4A6000CE00B6 /* PBXContainerItemProxy */; }; 04DC97E9194B4B7E00CE00B6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5A5D117B19473F2100F6D13D /* Quick-iOS */; targetProxy = 04DC97E8194B4B7E00CE00B6 /* PBXContainerItemProxy */; }; 04DC97EB194B4B9B00CE00B6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5A5D117B19473F2100F6D13D /* Quick-iOS */; targetProxy = 04DC97EA194B4B9B00CE00B6 /* PBXContainerItemProxy */; }; 04DC97F1194B82DB00CE00B6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DAEB6B8D1943873100289F44 /* Quick-OSX */; targetProxy = 04DC97F0194B82DB00CE00B6 /* PBXContainerItemProxy */; }; 04DC97F3194B82DE00CE00B6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5A5D117B19473F2100F6D13D /* Quick-iOS */; targetProxy = 04DC97F2194B82DE00CE00B6 /* PBXContainerItemProxy */; }; 04DC97F7194B831200CE00B6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5A5D117B19473F2100F6D13D /* Quick-iOS */; targetProxy = 04DC97F6194B831200CE00B6 /* PBXContainerItemProxy */; }; 04DC97F9194B834000CE00B6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DAEB6B8D1943873100289F44 /* Quick-OSX */; targetProxy = 04DC97F8194B834000CE00B6 /* PBXContainerItemProxy */; }; 04DC97FB194B834100CE00B6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5A5D117B19473F2100F6D13D /* Quick-iOS */; targetProxy = 04DC97FA194B834100CE00B6 /* PBXContainerItemProxy */; }; 04DC97FD194B834B00CE00B6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DAEB6B8D1943873100289F44 /* Quick-OSX */; targetProxy = 04DC97FC194B834B00CE00B6 /* PBXContainerItemProxy */; }; 04DC97FF194B835E00CE00B6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5A5D117B19473F2100F6D13D /* Quick-iOS */; targetProxy = 04DC97FE194B835E00CE00B6 /* PBXContainerItemProxy */; }; 04DC9801194B836100CE00B6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DAEB6B8D1943873100289F44 /* Quick-OSX */; targetProxy = 04DC9800194B836100CE00B6 /* PBXContainerItemProxy */; }; 04DC9803194B836300CE00B6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5A5D117B19473F2100F6D13D /* Quick-iOS */; targetProxy = 04DC9802194B836300CE00B6 /* PBXContainerItemProxy */; }; 04DC9805194B838400CE00B6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DAEB6B8D1943873100289F44 /* Quick-OSX */; targetProxy = 04DC9804194B838400CE00B6 /* PBXContainerItemProxy */; }; 04DC9807194B838700CE00B6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5A5D117B19473F2100F6D13D /* Quick-iOS */; targetProxy = 04DC9806194B838700CE00B6 /* PBXContainerItemProxy */; }; 04DC9809194B838B00CE00B6 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DAEB6B8D1943873100289F44 /* Quick-OSX */; targetProxy = 04DC9808194B838B00CE00B6 /* PBXContainerItemProxy */; }; 1F118CE11BDCA4AB005013A2 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F118CD41BDCA4AB005013A2 /* Quick-tvOS */; targetProxy = 1F118CE01BDCA4AB005013A2 /* PBXContainerItemProxy */; }; 1F118CF71BDCA4BB005013A2 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1F118CD41BDCA4AB005013A2 /* Quick-tvOS */; targetProxy = 1F118CF61BDCA4BB005013A2 /* PBXContainerItemProxy */; }; 5A5D118919473F2100F6D13D /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5A5D117B19473F2100F6D13D /* Quick-iOS */; targetProxy = 5A5D118819473F2100F6D13D /* PBXContainerItemProxy */; }; 5A5D11F0194741B500F6D13D /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5A5D117B19473F2100F6D13D /* Quick-iOS */; targetProxy = 5A5D11EF194741B500F6D13D /* PBXContainerItemProxy */; }; 5A5D11F2194741B500F6D13D /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5A5D117B19473F2100F6D13D /* Quick-iOS */; targetProxy = 5A5D11F1194741B500F6D13D /* PBXContainerItemProxy */; }; 93625F391951DDC8006B1FE1 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DAEB6B8D1943873100289F44 /* Quick-OSX */; targetProxy = 93625F381951DDC8006B1FE1 /* PBXContainerItemProxy */; }; DA5663F01A4C8D8500193C88 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DAEB6B8D1943873100289F44 /* Quick-OSX */; targetProxy = DA5663EF1A4C8D8500193C88 /* PBXContainerItemProxy */; }; DA9876BA1A4C70EB0004AA17 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5A5D117B19473F2100F6D13D /* Quick-iOS */; targetProxy = DA9876B91A4C70EB0004AA17 /* PBXContainerItemProxy */; }; DAEB6B9C1943873100289F44 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DAEB6B8D1943873100289F44 /* Quick-OSX */; targetProxy = DAEB6B9B1943873100289F44 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 1F118CE71BDCA4AB005013A2 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = Quick/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = Quick; SDKROOT = appletvos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; }; 1F118CE81BDCA4AB005013A2 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = Quick/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = Quick; SDKROOT = appletvos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; }; name = Release; }; 1F118CEA1BDCA4AB005013A2 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { DEBUG_INFORMATION_FORMAT = dwarf; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Externals/Nimble/build/Debug-appletvos", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = QuickTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_OBJC_BRIDGING_HEADER = QuickTests/Helpers/QuickTestsBridgingHeader.h; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; }; 1F118CEB1BDCA4AB005013A2 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Externals/Nimble/build/Debug-appletvos", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = QuickTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_OBJC_BRIDGING_HEADER = QuickTests/Helpers/QuickTestsBridgingHeader.h; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; }; name = Release; }; 1F118CF91BDCA4BC005013A2 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { DEBUG_INFORMATION_FORMAT = dwarf; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Externals/Nimble/build/Debug-appletvos", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = QuickFocusedTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_OBJC_BRIDGING_HEADER = QuickTests/Helpers/QuickTestsBridgingHeader.h; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; }; 1F118CFA1BDCA4BC005013A2 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Externals/Nimble/build/Debug-appletvos", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = QuickFocusedTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; SWIFT_OBJC_BRIDGING_HEADER = QuickTests/Helpers/QuickTestsBridgingHeader.h; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; }; name = Release; }; 5A5D118F19473F2100F6D13D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = Quick/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; METAL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_MODULE_NAME = Quick; PRODUCT_NAME = Quick; SDKROOT = iphoneos; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; }; 5A5D119019473F2100F6D13D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", ); INFOPLIST_FILE = Quick/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; METAL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_MODULE_NAME = Quick; PRODUCT_NAME = Quick; SDKROOT = iphoneos; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; TARGETED_DEVICE_FAMILY = "1,2,3"; TVOS_DEPLOYMENT_TARGET = 9.0; VALIDATE_PRODUCT = YES; }; name = Release; }; 5A5D119119473F2100F6D13D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = QuickTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; METAL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsos appletvsimulator"; SWIFT_OBJC_BRIDGING_HEADER = QuickTests/Helpers/QuickTestsBridgingHeader.h; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 5A5D119219473F2100F6D13D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); INFOPLIST_FILE = QuickTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; METAL_ENABLE_DEBUG_INFO = NO; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsos appletvsimulator"; SWIFT_OBJC_BRIDGING_HEADER = QuickTests/Helpers/QuickTestsBridgingHeader.h; VALIDATE_PRODUCT = YES; }; name = Release; }; DA5663F11A4C8D8500193C88 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = QuickFocusedTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = QuickTests/Helpers/QuickTestsBridgingHeader.h; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; DA5663F21A4C8D8500193C88 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); INFOPLIST_FILE = QuickFocusedTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.10; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = QuickTests/Helpers/QuickTestsBridgingHeader.h; }; name = Release; }; DA9876BB1A4C70EB0004AA17 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = QuickFocusedTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SWIFT_OBJC_BRIDGING_HEADER = QuickTests/Helpers/QuickTestsBridgingHeader.h; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; DA9876BC1A4C70EB0004AA17 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); INFOPLIST_FILE = QuickFocusedTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SWIFT_OBJC_BRIDGING_HEADER = QuickTests/Helpers/QuickTestsBridgingHeader.h; VALIDATE_PRODUCT = YES; }; name = Release; }; DAEB6BA21943873200289F44 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; 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; MACOSX_DEPLOYMENT_TARGET = 10.9; METAL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; DAEB6BA31943873200289F44 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; 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; MACOSX_DEPLOYMENT_TARGET = 10.9; METAL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Release; }; DAEB6BA51943873200289F44 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", ); FRAMEWORK_VERSION = A; INFOPLIST_FILE = Quick/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_MODULE_NAME = Quick; PRODUCT_NAME = Quick; SKIP_INSTALL = YES; VALID_ARCHS = x86_64; }; name = Debug; }; DAEB6BA61943873200289F44 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_SEARCH_PATHS = ( "$(PLATFORM_DIR)/Developer/Library/Frameworks", "$(inherited)", ); FRAMEWORK_VERSION = A; INFOPLIST_FILE = Quick/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_MODULE_NAME = Quick; PRODUCT_NAME = Quick; SKIP_INSTALL = YES; VALID_ARCHS = x86_64; }; name = Release; }; DAEB6BA81943873200289F44 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = QuickTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; METAL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = QuickTests/Helpers/QuickTestsBridgingHeader.h; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; DAEB6BA91943873200289F44 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); INFOPLIST_FILE = QuickTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; METAL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "io.quick.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = QuickTests/Helpers/QuickTestsBridgingHeader.h; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 1F118CE61BDCA4AB005013A2 /* Build configuration list for PBXNativeTarget "Quick-tvOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 1F118CE71BDCA4AB005013A2 /* Debug */, 1F118CE81BDCA4AB005013A2 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 1F118CE91BDCA4AB005013A2 /* Build configuration list for PBXNativeTarget "Quick-tvOSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 1F118CEA1BDCA4AB005013A2 /* Debug */, 1F118CEB1BDCA4AB005013A2 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 1F118CF81BDCA4BC005013A2 /* Build configuration list for PBXNativeTarget "QuickFocused-tvOSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 1F118CF91BDCA4BC005013A2 /* Debug */, 1F118CFA1BDCA4BC005013A2 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 5A5D119319473F2100F6D13D /* Build configuration list for PBXNativeTarget "Quick-iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 5A5D118F19473F2100F6D13D /* Debug */, 5A5D119019473F2100F6D13D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 5A5D119419473F2100F6D13D /* Build configuration list for PBXNativeTarget "Quick-iOSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 5A5D119119473F2100F6D13D /* Debug */, 5A5D119219473F2100F6D13D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; DA5663F31A4C8D8500193C88 /* Build configuration list for PBXNativeTarget "QuickFocused-OSXTests" */ = { isa = XCConfigurationList; buildConfigurations = ( DA5663F11A4C8D8500193C88 /* Debug */, DA5663F21A4C8D8500193C88 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; DA9876BD1A4C70EB0004AA17 /* Build configuration list for PBXNativeTarget "QuickFocused-iOSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( DA9876BB1A4C70EB0004AA17 /* Debug */, DA9876BC1A4C70EB0004AA17 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; DAEB6B881943873100289F44 /* Build configuration list for PBXProject "Quick" */ = { isa = XCConfigurationList; buildConfigurations = ( DAEB6BA21943873200289F44 /* Debug */, DAEB6BA31943873200289F44 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; DAEB6BA41943873200289F44 /* Build configuration list for PBXNativeTarget "Quick-OSX" */ = { isa = XCConfigurationList; buildConfigurations = ( DAEB6BA51943873200289F44 /* Debug */, DAEB6BA61943873200289F44 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; DAEB6BA71943873200289F44 /* Build configuration list for PBXNativeTarget "Quick-OSXTests" */ = { isa = XCConfigurationList; buildConfigurations = ( DAEB6BA81943873200289F44 /* Debug */, DAEB6BA91943873200289F44 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = DAEB6B851943873100289F44 /* Project object */; } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick.xcodeproj/xcshareddata/xcschemes/Quick-OSX.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick.xcodeproj/xcshareddata/xcschemes/Quick-iOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Quick.xcodeproj/xcshareddata/xcschemes/Quick-tvOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickFocusedTests/FocusedTests+ObjC.m ================================================ #import #import #import #import "QCKSpecRunner.h" QuickConfigurationBegin(FunctionalTests_SharedExamplesConfiguration_ObjC) + (void)configure:(Configuration *)configuration { sharedExamples(@"two passing shared examples (Objective-C)", ^(QCKDSLSharedExampleContext exampleContext) { it(@"has an example that passes (4)", ^{}); it(@"has another example that passes (5)", ^{}); }); } QuickConfigurationEnd QuickSpecBegin(FunctionalTests_FocusedSpec_Focused_ObjC) it(@"has an unfocused example that fails, but is never run", ^{ XCTFail(); }); fit(@"has a focused example that passes (1)", ^{}); fdescribe(@"a focused example group", ^{ it(@"has an example that is not focused, but will be run, and passes (2)", ^{}); fit(@"has a focused example that passes (3)", ^{}); }); fitBehavesLike(@"two passing shared examples (Objective-C)", ^NSDictionary *{ return @{}; }); QuickSpecEnd QuickSpecBegin(FunctionalTests_FocusedSpec_Unfocused_ObjC) it(@"has an unfocused example thay fails, but is never run", ^{ XCTFail(); }); describe(@"an unfocused example group that is never run", ^{ beforeEach(^{ [NSException raise:NSInternalInconsistencyException format:@""]; }); it(@"has an example that fails, but is never run", ^{ XCTFail(); }); }); QuickSpecEnd @interface FocusedTests_ObjC: XCTestCase @end @implementation FocusedTests_ObjC - (void)testOnlyFocusedExamplesAreExecuted { XCTestRun *result = qck_runSpecs(@[ [FunctionalTests_FocusedSpec_Focused_ObjC class], [FunctionalTests_FocusedSpec_Unfocused_ObjC class] ]); XCTAssertEqual(result.executionCount, 5); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickFocusedTests/FocusedTests.swift ================================================ import Quick import Nimble import XCTest class FunctionalTests_FocusedSpec_SharedExamplesConfiguration: QuickConfiguration { override class func configure(configuration: Configuration) { sharedExamples("two passing shared examples") { it("has an example that passes (4)") {} it("has another example that passes (5)") {} } } } class FunctionalTests_FocusedSpec_Focused: QuickSpec { override func spec() { it("has an unfocused example that fails, but is never run") { fail() } fit("has a focused example that passes (1)") {} fdescribe("a focused example group") { it("has an example that is not focused, but will be run, and passes (2)") {} fit("has a focused example that passes (3)") {} } // TODO: Port fitBehavesLike to Swift. itBehavesLike("two passing shared examples", flags: [Filter.focused: true]) } } class FunctionalTests_FocusedSpec_Unfocused: QuickSpec { override func spec() { it("has an unfocused example that fails, but is never run") { fail() } describe("an unfocused example group that is never run") { beforeEach { assert(false) } it("has an example that fails, but is never run") { fail() } } } } class FocusedTests: XCTestCase { func testOnlyFocusedExamplesAreExecuted() { let result = qck_runSpecs([ FunctionalTests_FocusedSpec_Focused.classForCoder(), FunctionalTests_FocusedSpec_Unfocused.classForCoder() ]) XCTAssertEqual(result.executionCount, 5 as UInt) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickFocusedTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/Fixtures/FunctionalTests_SharedExamplesTests_SharedExamples.swift ================================================ import Quick import Nimble class FunctionalTests_SharedExamplesTests_SharedExamples: QuickConfiguration { override class func configure(configuration: Configuration) { sharedExamples("a group of three shared examples") { it("passes once") { expect(true).to(beTruthy()) } it("passes twice") { expect(true).to(beTruthy()) } it("passes three times") { expect(true).to(beTruthy()) } } sharedExamples("shared examples that take a context") { (sharedExampleContext: SharedExampleContext) in it("is passed the correct parameters via the context") { let callsite = sharedExampleContext()["callsite"] as! String expect(callsite).to(equal("SharedExamplesSpec")) } } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/AfterEachTests+ObjC.m ================================================ #import #import #import #import "QCKSpecRunner.h" typedef NS_ENUM(NSUInteger, AfterEachType) { OuterOne, OuterTwo, OuterThree, InnerOne, InnerTwo, NoExamples, }; static NSMutableArray *afterEachOrder; QuickSpecBegin(FunctionalTests_AfterEachSpec_ObjC) afterEach(^{ [afterEachOrder addObject:@(OuterOne)]; }); afterEach(^{ [afterEachOrder addObject:@(OuterTwo)]; }); afterEach(^{ [afterEachOrder addObject:@(OuterThree)]; }); it(@"executes the outer afterEach closures once, but not before this closure [1]", ^{ expect(afterEachOrder).to(equal(@[])); }); it(@"executes the outer afterEach closures a second time, but not before this closure [2]", ^{ expect(afterEachOrder).to(equal(@[@(OuterOne), @(OuterTwo), @(OuterThree)])); }); context(@"when there are nested afterEach", ^{ afterEach(^{ [afterEachOrder addObject:@(InnerOne)]; }); afterEach(^{ [afterEachOrder addObject:@(InnerTwo)]; }); it(@"executes the outer and inner afterEach closures, but not before this closure [3]", ^{ // The afterEach for the previous two examples should have been run. // The list should contain the afterEach for those example, executed from top to bottom. expect(afterEachOrder).to(equal(@[ @(OuterOne), @(OuterTwo), @(OuterThree), @(OuterOne), @(OuterTwo), @(OuterThree), ])); }); }); context(@"when there are nested afterEach without examples", ^{ afterEach(^{ [afterEachOrder addObject:@(NoExamples)]; }); }); QuickSpecEnd @interface AfterEachTests_ObjC : XCTestCase; @end @implementation AfterEachTests_ObjC - (void)setUp { [super setUp]; afterEachOrder = [NSMutableArray array]; } - (void)tearDown { afterEachOrder = [NSMutableArray array]; [super tearDown]; } - (void)testAfterEachIsExecutedInTheCorrectOrder { qck_runSpec([FunctionalTests_AfterEachSpec_ObjC class]); NSArray *expectedOrder = @[ // [1] The outer afterEach closures are executed from top to bottom. @(OuterOne), @(OuterTwo), @(OuterThree), // [2] The outer afterEach closures are executed from top to bottom. @(OuterOne), @(OuterTwo), @(OuterThree), // [3] The outer afterEach closures are executed from top to bottom, // then the outer afterEach closures are executed from top to bottom. @(InnerOne), @(InnerTwo), @(OuterOne), @(OuterTwo), @(OuterThree), ]; XCTAssertEqualObjects(afterEachOrder, expectedOrder); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/AfterEachTests.swift ================================================ import XCTest import Quick import Nimble private enum AfterEachType { case OuterOne case OuterTwo case OuterThree case InnerOne case InnerTwo case NoExamples } private var afterEachOrder = [AfterEachType]() class FunctionalTests_AfterEachSpec: QuickSpec { override func spec() { afterEach { afterEachOrder.append(AfterEachType.OuterOne) } afterEach { afterEachOrder.append(AfterEachType.OuterTwo) } afterEach { afterEachOrder.append(AfterEachType.OuterThree) } it("executes the outer afterEach closures once, but not before this closure [1]") { // No examples have been run, so no afterEach will have been run either. // The list should be empty. expect(afterEachOrder).to(beEmpty()) } it("executes the outer afterEach closures a second time, but not before this closure [2]") { // The afterEach for the previous example should have been run. // The list should contain the afterEach for that example, executed from top to bottom. expect(afterEachOrder).to(equal([AfterEachType.OuterOne, AfterEachType.OuterTwo, AfterEachType.OuterThree])) } context("when there are nested afterEach") { afterEach { afterEachOrder.append(AfterEachType.InnerOne) } afterEach { afterEachOrder.append(AfterEachType.InnerTwo) } it("executes the outer and inner afterEach closures, but not before this closure [3]") { // The afterEach for the previous two examples should have been run. // The list should contain the afterEach for those example, executed from top to bottom. expect(afterEachOrder).to(equal([ AfterEachType.OuterOne, AfterEachType.OuterTwo, AfterEachType.OuterThree, AfterEachType.OuterOne, AfterEachType.OuterTwo, AfterEachType.OuterThree, ])) } } context("when there are nested afterEach without examples") { afterEach { afterEachOrder.append(AfterEachType.NoExamples) } } } } class AfterEachTests: XCTestCase { override func setUp() { super.setUp() afterEachOrder = [] } override func tearDown() { afterEachOrder = [] super.tearDown() } func testAfterEachIsExecutedInTheCorrectOrder() { qck_runSpec(FunctionalTests_AfterEachSpec.classForCoder()) let expectedOrder = [ // [1] The outer afterEach closures are executed from top to bottom. AfterEachType.OuterOne, AfterEachType.OuterTwo, AfterEachType.OuterThree, // [2] The outer afterEach closures are executed from top to bottom. AfterEachType.OuterOne, AfterEachType.OuterTwo, AfterEachType.OuterThree, // [3] The inner afterEach closures are executed from top to bottom, // then the outer afterEach closures are executed from top to bottom. AfterEachType.InnerOne, AfterEachType.InnerTwo, AfterEachType.OuterOne, AfterEachType.OuterTwo, AfterEachType.OuterThree, ] XCTAssertEqual(afterEachOrder, expectedOrder) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/AfterSuiteTests+ObjC.m ================================================ #import #import #import #import "QCKSpecRunner.h" static BOOL afterSuiteWasExecuted = NO; QuickSpecBegin(FunctionalTests_AfterSuite_AfterSuiteSpec_ObjC) afterSuite(^{ afterSuiteWasExecuted = YES; }); QuickSpecEnd QuickSpecBegin(FunctionalTests_AfterSuite_Spec_ObjC) it(@"is executed before afterSuite", ^{ expect(@(afterSuiteWasExecuted)).to(beFalsy()); }); QuickSpecEnd @interface AfterSuiteTests_ObjC : XCTestCase; @end @implementation AfterSuiteTests_ObjC - (void)testAfterSuiteIsNotExecutedBeforeAnyExamples { // Execute the spec with an assertion after the one with an afterSuite. NSArray *specs = @[ [FunctionalTests_AfterSuite_AfterSuiteSpec_ObjC class], [FunctionalTests_AfterSuite_Spec_ObjC class] ]; XCTestRun *result = qck_runSpecs(specs); // Although this ensures that afterSuite is not called before any // examples, it doesn't test that it's ever called in the first place. XCTAssert(result.hasSucceeded); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/AfterSuiteTests.swift ================================================ import XCTest import Quick import Nimble var afterSuiteWasExecuted = false class FunctionalTests_AfterSuite_AfterSuiteSpec: QuickSpec { override func spec() { afterSuite { afterSuiteWasExecuted = true } } } class FunctionalTests_AfterSuite_Spec: QuickSpec { override func spec() { it("is executed before afterSuite") { expect(afterSuiteWasExecuted).to(beFalsy()) } } } class AfterSuiteTests: XCTestCase { func testAfterSuiteIsNotExecutedBeforeAnyExamples() { // Execute the spec with an assertion after the one with an afterSuite. let specs = NSArray(objects: FunctionalTests_AfterSuite_AfterSuiteSpec.classForCoder(), FunctionalTests_AfterSuite_Spec.classForCoder()) let result = qck_runSpecs(specs as [AnyObject]) // Although this ensures that afterSuite is not called before any // examples, it doesn't test that it's ever called in the first place. XCTAssert(result.hasSucceeded) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/BeforeEachTests+ObjC.m ================================================ #import #import #import "QCKSpecRunner.h" typedef NS_ENUM(NSUInteger, BeforeEachType) { OuterOne, OuterTwo, InnerOne, InnerTwo, InnerThree, NoExamples, }; static NSMutableArray *beforeEachOrder; QuickSpecBegin(FunctionalTests_BeforeEachSpec_ObjC) beforeEach(^{ [beforeEachOrder addObject:@(OuterOne)]; }); beforeEach(^{ [beforeEachOrder addObject:@(OuterTwo)]; }); it(@"executes the outer beforeEach closures once [1]", ^{}); it(@"executes the outer beforeEach closures a second time [2]", ^{}); context(@"when there are nested beforeEach", ^{ beforeEach(^{ [beforeEachOrder addObject:@(InnerOne)]; }); beforeEach(^{ [beforeEachOrder addObject:@(InnerTwo)]; }); beforeEach(^{ [beforeEachOrder addObject:@(InnerThree)]; }); it(@"executes the outer and inner beforeEach closures [3]", ^{}); }); context(@"when there are nested beforeEach without examples", ^{ beforeEach(^{ [beforeEachOrder addObject:@(NoExamples)]; }); }); QuickSpecEnd @interface BeforeEachTests_ObjC : XCTestCase; @end @implementation BeforeEachTests_ObjC - (void)setUp { beforeEachOrder = [NSMutableArray array]; [super setUp]; } - (void)tearDown { beforeEachOrder = [NSMutableArray array]; [super tearDown]; } - (void)testBeforeEachIsExecutedInTheCorrectOrder { qck_runSpec([FunctionalTests_BeforeEachSpec_ObjC class]); NSArray *expectedOrder = @[ // [1] The outer beforeEach closures are executed from top to bottom. @(OuterOne), @(OuterTwo), // [2] The outer beforeEach closures are executed from top to bottom. @(OuterOne), @(OuterTwo), // [3] The outer beforeEach closures are executed from top to bottom, // then the inner beforeEach closures are executed from top to bottom. @(OuterOne), @(OuterTwo), @(InnerOne), @(InnerTwo), @(InnerThree), ]; XCTAssertEqualObjects(beforeEachOrder, expectedOrder); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/BeforeEachTests.swift ================================================ import XCTest import Quick import Nimble private enum BeforeEachType { case OuterOne case OuterTwo case InnerOne case InnerTwo case InnerThree case NoExamples } private var beforeEachOrder = [BeforeEachType]() class FunctionalTests_BeforeEachSpec: QuickSpec { override func spec() { beforeEach { beforeEachOrder.append(BeforeEachType.OuterOne) } beforeEach { beforeEachOrder.append(BeforeEachType.OuterTwo) } it("executes the outer beforeEach closures once [1]") {} it("executes the outer beforeEach closures a second time [2]") {} context("when there are nested beforeEach") { beforeEach { beforeEachOrder.append(BeforeEachType.InnerOne) } beforeEach { beforeEachOrder.append(BeforeEachType.InnerTwo) } beforeEach { beforeEachOrder.append(BeforeEachType.InnerThree) } it("executes the outer and inner beforeEach closures [3]") {} } context("when there are nested beforeEach without examples") { beforeEach { beforeEachOrder.append(BeforeEachType.NoExamples) } } } } class BeforeEachTests: XCTestCase { override func setUp() { super.setUp() beforeEachOrder = [] } override func tearDown() { beforeEachOrder = [] super.tearDown() } func testBeforeEachIsExecutedInTheCorrectOrder() { qck_runSpec(FunctionalTests_BeforeEachSpec.classForCoder()) let expectedOrder = [ // [1] The outer beforeEach closures are executed from top to bottom. BeforeEachType.OuterOne, BeforeEachType.OuterTwo, // [2] The outer beforeEach closures are executed from top to bottom. BeforeEachType.OuterOne, BeforeEachType.OuterTwo, // [3] The outer beforeEach closures are executed from top to bottom, // then the inner beforeEach closures are executed from top to bottom. BeforeEachType.OuterOne, BeforeEachType.OuterTwo, BeforeEachType.InnerOne, BeforeEachType.InnerTwo, BeforeEachType.InnerThree, ] XCTAssertEqual(beforeEachOrder, expectedOrder) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/BeforeSuiteTests+ObjC.m ================================================ #import #import #import #import "QCKSpecRunner.h" static BOOL beforeSuiteWasExecuted = NO; QuickSpecBegin(FunctionalTests_BeforeSuite_BeforeSuiteSpec_ObjC) beforeSuite(^{ beforeSuiteWasExecuted = YES; }); QuickSpecEnd QuickSpecBegin(FunctionalTests_BeforeSuite_Spec_ObjC) it(@"is executed after beforeSuite", ^{ expect(@(beforeSuiteWasExecuted)).to(beTruthy()); }); QuickSpecEnd @interface BeforeSuiteTests_ObjC : XCTestCase; @end @implementation BeforeSuiteTests_ObjC - (void)testBeforeSuiteIsExecutedBeforeAnyExamples { // Execute the spec with an assertion before the one with a beforeSuite NSArray *specs = @[ [FunctionalTests_BeforeSuite_Spec_ObjC class], [FunctionalTests_BeforeSuite_BeforeSuiteSpec_ObjC class] ]; XCTestRun *result = qck_runSpecs(specs); XCTAssert(result.hasSucceeded); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/BeforeSuiteTests.swift ================================================ import XCTest import Quick import Nimble var beforeSuiteWasExecuted = false class FunctionalTests_BeforeSuite_BeforeSuiteSpec: QuickSpec { override func spec() { beforeSuite { beforeSuiteWasExecuted = true } } } class FunctionalTests_BeforeSuite_Spec: QuickSpec { override func spec() { it("is executed after beforeSuite") { expect(beforeSuiteWasExecuted).to(beTruthy()) } } } class BeforeSuiteTests: XCTestCase { func testBeforeSuiteIsExecutedBeforeAnyExamples() { // Execute the spec with an assertion before the one with a beforeSuite let specs = NSArray(objects: FunctionalTests_BeforeSuite_Spec.classForCoder(), FunctionalTests_BeforeSuite_BeforeSuiteSpec.classForCoder()) let result = qck_runSpecs(specs as [AnyObject]) XCTAssert(result.hasSucceeded) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/Configuration/AfterEach/Configuration+AfterEach.swift ================================================ import Quick public var FunctionalTests_Configuration_AfterEachWasExecuted = false class FunctionalTests_Configuration_AfterEach: QuickConfiguration { override class func configure(configuration: Configuration) { configuration.afterEach { FunctionalTests_Configuration_AfterEachWasExecuted = true } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/Configuration/AfterEach/Configuration+AfterEachTests.swift ================================================ import XCTest import Quick import Nimble class Configuration_AfterEachSpec: QuickSpec { override func spec() { beforeEach { FunctionalTests_Configuration_AfterEachWasExecuted = false } it("is executed before the configuration afterEach") { expect(FunctionalTests_Configuration_AfterEachWasExecuted).to(beFalsy()) } } } class Configuration_AfterEachTests: XCTestCase { override func setUp() { super.setUp() FunctionalTests_Configuration_AfterEachWasExecuted = false } override func tearDown() { FunctionalTests_Configuration_AfterEachWasExecuted = false super.tearDown() } func testExampleIsRunAfterTheConfigurationBeforeEachIsExecuted() { qck_runSpec(Configuration_BeforeEachSpec.classForCoder()) XCTAssert(FunctionalTests_Configuration_AfterEachWasExecuted) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/Configuration/BeforeEach/Configuration+BeforeEach.swift ================================================ import Quick public var FunctionalTests_Configuration_BeforeEachWasExecuted = false class FunctionalTests_Configuration_BeforeEach: QuickConfiguration { override class func configure(configuration: Configuration) { configuration.beforeEach { FunctionalTests_Configuration_BeforeEachWasExecuted = true } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/Configuration/BeforeEach/Configuration+BeforeEachTests.swift ================================================ import XCTest import Quick import Nimble class Configuration_BeforeEachSpec: QuickSpec { override func spec() { it("is executed after the configuration beforeEach") { expect(FunctionalTests_Configuration_BeforeEachWasExecuted).to(beTruthy()) } } } class Configuration_BeforeEachTests: XCTestCase { override func setUp() { super.setUp() FunctionalTests_Configuration_BeforeEachWasExecuted = false } override func tearDown() { FunctionalTests_Configuration_BeforeEachWasExecuted = false super.tearDown() } func testExampleIsRunAfterTheConfigurationBeforeEachIsExecuted() { qck_runSpec(Configuration_BeforeEachSpec.classForCoder()) XCTAssert(FunctionalTests_Configuration_BeforeEachWasExecuted) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/FailureTests+ObjC.m ================================================ #import #import #import #import "QCKSpecRunner.h" static BOOL isRunningFunctionalTests = NO; #pragma mark - Spec QuickSpecBegin(FunctionalTests_FailureSpec_ObjC) describe(@"a group of failing examples", ^{ it(@"passes", ^{ expect(@YES).to(beTruthy()); }); it(@"fails (but only when running the functional tests)", ^{ expect(@(isRunningFunctionalTests)).to(beFalsy()); }); it(@"fails again (but only when running the functional tests)", ^{ expect(@(isRunningFunctionalTests)).to(beFalsy()); }); }); QuickSpecEnd #pragma mark - Tests @interface FailureTests_ObjC : XCTestCase; @end @implementation FailureTests_ObjC - (void)setUp { [super setUp]; isRunningFunctionalTests = YES; } - (void)tearDown { isRunningFunctionalTests = NO; [super tearDown]; } - (void)testFailureSpecHasSucceededIsFalse { XCTestRun *result = qck_runSpec([FunctionalTests_FailureSpec_ObjC class]); XCTAssertFalse(result.hasSucceeded); } - (void)testFailureSpecExecutedAllExamples { XCTestRun *result = qck_runSpec([FunctionalTests_FailureSpec_ObjC class]); XCTAssertEqual(result.executionCount, 3); } - (void)testFailureSpecFailureCountIsEqualToTheNumberOfFailingExamples { XCTestRun *result = qck_runSpec([FunctionalTests_FailureSpec_ObjC class]); XCTAssertEqual(result.failureCount, 2); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/FailureUsingXCTAssertTests+ObjC.m ================================================ #import #import #import "QCKSpecRunner.h" static BOOL isRunningFunctionalTests = NO; QuickSpecBegin(FunctionalTests_FailureUsingXCTAssertSpec_ObjC) it(@"fails using an XCTAssert (but only when running the functional tests)", ^{ XCTAssertFalse(isRunningFunctionalTests); }); it(@"fails again using an XCTAssert (but only when running the functional tests)", ^{ XCTAssertFalse(isRunningFunctionalTests); }); it(@"succeeds using an XCTAssert", ^{ XCTAssertTrue(YES); }); QuickSpecEnd #pragma mark - Tests @interface FailureUsingXCTAssertTests_ObjC : XCTestCase; @end @implementation FailureUsingXCTAssertTests_ObjC - (void)setUp { [super setUp]; isRunningFunctionalTests = YES; } - (void)tearDown { isRunningFunctionalTests = NO; [super tearDown]; } - (void)testFailureUsingXCTAssertSpecHasSucceededIsFalse { XCTestRun *result = qck_runSpec([FunctionalTests_FailureUsingXCTAssertSpec_ObjC class]); XCTAssertFalse(result.hasSucceeded); } - (void)testFailureUsingXCTAssertSpecExecutedAllExamples { XCTestRun *result = qck_runSpec([FunctionalTests_FailureUsingXCTAssertSpec_ObjC class]); XCTAssertEqual(result.executionCount, 3); } - (void)testFailureUsingXCTAssertSpecFailureCountIsEqualToTheNumberOfFailingExamples { XCTestRun *result = qck_runSpec([FunctionalTests_FailureUsingXCTAssertSpec_ObjC class]); XCTAssertEqual(result.failureCount, 2); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/ItTests+ObjC.m ================================================ #import #import #import #import "QCKSpecRunner.h" QuickSpecBegin(FunctionalTests_ItSpec_ObjC) __block ExampleMetadata *exampleMetadata = nil; beforeEachWithMetadata(^(ExampleMetadata *metadata) { exampleMetadata = metadata; }); it(@" ", ^{ expect(exampleMetadata.example.name).to(equal(@" ")); }); it(@"has a description with セレクター名に使えない文字が入っている 👊💥", ^{ NSString *name = @"has a description with セレクター名に使えない文字が入っている 👊💥"; expect(exampleMetadata.example.name).to(equal(name)); }); QuickSpecEnd @interface ItTests_ObjC : XCTestCase; @end @implementation ItTests_ObjC - (void)testAllExamplesAreExecuted { XCTestRun *result = qck_runSpec([FunctionalTests_ItSpec_ObjC class]); XCTAssertEqual(result.executionCount, 2); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/ItTests.swift ================================================ import XCTest import Quick import Nimble class FunctionalTests_ItSpec: QuickSpec { override func spec() { var exampleMetadata: ExampleMetadata? beforeEach { metadata in exampleMetadata = metadata } it("") { expect(exampleMetadata!.example.name).to(equal("")) } it("has a description with セレクター名に使えない文字が入っている 👊💥") { let name = "has a description with セレクター名に使えない文字が入っている 👊💥" expect(exampleMetadata!.example.name).to(equal(name)) } } } class ItTests: XCTestCase { func testAllExamplesAreExecuted() { let result = qck_runSpec(FunctionalTests_ItSpec.classForCoder()) XCTAssertEqual(result.executionCount, 2 as UInt) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/PendingTests+ObjC.m ================================================ #import #import #import #import "QCKSpecRunner.h" static NSUInteger oneExampleBeforeEachExecutedCount = 0; static NSUInteger onlyPendingExamplesBeforeEachExecutedCount = 0; QuickSpecBegin(FunctionalTests_PendingSpec_ObjC) pending(@"an example that will not run", ^{ expect(@YES).to(beFalsy()); }); describe(@"a describe block containing only one enabled example", ^{ beforeEach(^{ oneExampleBeforeEachExecutedCount += 1; }); it(@"an example that will run", ^{}); pending(@"an example that will not run", ^{}); }); describe(@"a describe block containing only pending examples", ^{ beforeEach(^{ onlyPendingExamplesBeforeEachExecutedCount += 1; }); pending(@"an example that will not run", ^{}); }); QuickSpecEnd @interface PendingTests_ObjC : XCTestCase; @end @implementation PendingTests_ObjC - (void)setUp { [super setUp]; oneExampleBeforeEachExecutedCount = 0; onlyPendingExamplesBeforeEachExecutedCount = 0; } - (void)tearDown { oneExampleBeforeEachExecutedCount = 0; onlyPendingExamplesBeforeEachExecutedCount = 0; [super tearDown]; } - (void)testAnOtherwiseFailingExampleWhenMarkedPendingDoesNotCauseTheSuiteToFail { XCTestRun *result = qck_runSpec([FunctionalTests_PendingSpec_ObjC class]); XCTAssert(result.hasSucceeded); } - (void)testBeforeEachOnlyRunForEnabledExamples { qck_runSpec([FunctionalTests_PendingSpec_ObjC class]); XCTAssertEqual(oneExampleBeforeEachExecutedCount, 1); } - (void)testBeforeEachDoesNotRunForContextsWithOnlyPendingExamples { qck_runSpec([FunctionalTests_PendingSpec_ObjC class]); XCTAssertEqual(onlyPendingExamplesBeforeEachExecutedCount, 0); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/PendingTests.swift ================================================ import XCTest import Quick import Nimble var oneExampleBeforeEachExecutedCount = 0 var onlyPendingExamplesBeforeEachExecutedCount = 0 class FunctionalTests_PendingSpec: QuickSpec { override func spec() { xit("an example that will not run") { expect(true).to(beFalsy()) } describe("a describe block containing only one enabled example") { beforeEach { oneExampleBeforeEachExecutedCount += 1 } it("an example that will run") {} pending("an example that will not run") {} } describe("a describe block containing only pending examples") { beforeEach { onlyPendingExamplesBeforeEachExecutedCount += 1 } pending("an example that will not run") {} } } } class PendingTests: XCTestCase { override func setUp() { super.setUp() oneExampleBeforeEachExecutedCount = 0 onlyPendingExamplesBeforeEachExecutedCount = 0 } override func tearDown() { oneExampleBeforeEachExecutedCount = 0 onlyPendingExamplesBeforeEachExecutedCount = 0 super.tearDown() } func testAnOtherwiseFailingExampleWhenMarkedPendingDoesNotCauseTheSuiteToFail() { let result = qck_runSpec(FunctionalTests_PendingSpec.classForCoder()) XCTAssert(result.hasSucceeded) } func testBeforeEachOnlyRunForEnabledExamples() { qck_runSpec(FunctionalTests_PendingSpec.classForCoder()) XCTAssertEqual(oneExampleBeforeEachExecutedCount, 1) } func testBeforeEachDoesNotRunForContextsWithOnlyPendingExamples() { qck_runSpec(FunctionalTests_PendingSpec.classForCoder()) XCTAssertEqual(onlyPendingExamplesBeforeEachExecutedCount, 0) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/SharedExamples+BeforeEachTests+ObjC.m ================================================ #import #import #import #import "QCKSpecRunner.h" static NSUInteger specBeforeEachExecutedCount = 0; static NSUInteger sharedExamplesBeforeEachExecutedCount = 0; QuickConfigurationBegin(FunctionalTests_SharedExamples_BeforeEachTests_SharedExamples_ObjC) + (void)configure:(Configuration *)configuration { sharedExamples(@"a group of three shared examples with a beforeEach in Obj-C", ^(QCKDSLSharedExampleContext context) { beforeEach(^{ sharedExamplesBeforeEachExecutedCount += 1; }); it(@"passes once", ^{}); it(@"passes twice", ^{}); it(@"passes three times", ^{}); }); } QuickConfigurationEnd QuickSpecBegin(FunctionalTests_SharedExamples_BeforeEachSpec_ObjC) beforeEach(^{ specBeforeEachExecutedCount += 1; }); it(@"executes the spec beforeEach once", ^{}); itBehavesLike(@"a group of three shared examples with a beforeEach in Obj-C", ^NSDictionary*{ return @{}; }); QuickSpecEnd @interface SharedExamples_BeforeEachTests_ObjC : XCTestCase; @end @implementation SharedExamples_BeforeEachTests_ObjC - (void)setUp { [super setUp]; specBeforeEachExecutedCount = 0; sharedExamplesBeforeEachExecutedCount = 0; } - (void)tearDown { specBeforeEachExecutedCount = 0; sharedExamplesBeforeEachExecutedCount = 0; [super tearDown]; } - (void)testBeforeEachOutsideOfSharedExamplesExecutedOnceBeforeEachExample { qck_runSpec([FunctionalTests_SharedExamples_BeforeEachSpec_ObjC class]); XCTAssertEqual(specBeforeEachExecutedCount, 4); } - (void)testBeforeEachInSharedExamplesExecutedOnceBeforeEachSharedExample { qck_runSpec([FunctionalTests_SharedExamples_BeforeEachSpec_ObjC class]); XCTAssertEqual(sharedExamplesBeforeEachExecutedCount, 3); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/SharedExamples+BeforeEachTests.swift ================================================ import XCTest import Quick import Nimble var specBeforeEachExecutedCount = 0 var sharedExamplesBeforeEachExecutedCount = 0 class FunctionalTests_SharedExamples_BeforeEachTests_SharedExamples: QuickConfiguration { override class func configure(configuration: Configuration) { sharedExamples("a group of three shared examples with a beforeEach") { beforeEach { sharedExamplesBeforeEachExecutedCount += 1 } it("passes once") {} it("passes twice") {} it("passes three times") {} } } } class FunctionalTests_SharedExamples_BeforeEachSpec: QuickSpec { override func spec() { beforeEach { specBeforeEachExecutedCount += 1 } it("executes the spec beforeEach once") {} itBehavesLike("a group of three shared examples with a beforeEach") } } class SharedExamples_BeforeEachTests: XCTestCase { override func setUp() { super.setUp() specBeforeEachExecutedCount = 0 sharedExamplesBeforeEachExecutedCount = 0 } override func tearDown() { specBeforeEachExecutedCount = 0 sharedExamplesBeforeEachExecutedCount = 0 super.tearDown() } func testBeforeEachOutsideOfSharedExamplesExecutedOnceBeforeEachExample() { qck_runSpec(FunctionalTests_SharedExamples_BeforeEachSpec.classForCoder()) XCTAssertEqual(specBeforeEachExecutedCount, 4) } func testBeforeEachInSharedExamplesExecutedOnceBeforeEachSharedExample() { qck_runSpec(FunctionalTests_SharedExamples_BeforeEachSpec.classForCoder()) XCTAssertEqual(sharedExamplesBeforeEachExecutedCount, 3) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/SharedExamplesTests+ObjC.m ================================================ #import #import #import #import "QCKSpecRunner.h" QuickSpecBegin(FunctionalTests_SharedExamples_Spec_ObjC) itBehavesLike(@"a group of three shared examples", ^NSDictionary*{ return @{}; }); QuickSpecEnd QuickSpecBegin(FunctionalTests_SharedExamples_ContextSpec_ObjC) itBehavesLike(@"shared examples that take a context", ^NSDictionary *{ return @{ @"callsite": @"SharedExamplesSpec" }; }); QuickSpecEnd QuickSpecBegin(FunctionalTests_SharedExamples_SameContextSpec_ObjC) __block NSInteger counter = 0; afterEach(^{ counter++; }); sharedExamples(@"gets called with a different context from within the same spec file", ^(QCKDSLSharedExampleContext exampleContext) { it(@"tracks correctly", ^{ NSString *payload = exampleContext()[@"payload"]; BOOL expected = [payload isEqualToString:[NSString stringWithFormat:@"%ld", (long)counter]]; expect(@(expected)).to(beTrue()); }); }); itBehavesLike(@"gets called with a different context from within the same spec file", ^{ return @{ @"payload" : @"0" }; }); itBehavesLike(@"gets called with a different context from within the same spec file", ^{ return @{ @"payload" : @"1" }; }); QuickSpecEnd @interface SharedExamplesTests_ObjC : XCTestCase; @end @implementation SharedExamplesTests_ObjC - (void)testAGroupOfThreeSharedExamplesExecutesThreeExamples { XCTestRun *result = qck_runSpec([FunctionalTests_SharedExamples_Spec_ObjC class]); XCTAssert(result.hasSucceeded); XCTAssertEqual(result.executionCount, 3); } - (void)testSharedExamplesWithContextPassContextToExamples { XCTestRun *result = qck_runSpec([FunctionalTests_SharedExamples_ContextSpec_ObjC class]); XCTAssert(result.hasSucceeded); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/FunctionalTests/SharedExamplesTests.swift ================================================ import XCTest import Quick import Nimble class FunctionalTests_SharedExamples_Spec: QuickSpec { override func spec() { itBehavesLike("a group of three shared examples") } } class FunctionalTests_SharedExamples_ContextSpec: QuickSpec { override func spec() { itBehavesLike("shared examples that take a context") { ["callsite": "SharedExamplesSpec"] } } } // Shared examples are defined in QuickTests/Fixtures class SharedExamplesTests: XCTestCase { func testAGroupOfThreeSharedExamplesExecutesThreeExamples() { let result = qck_runSpec(FunctionalTests_SharedExamples_Spec.classForCoder()) XCTAssert(result.hasSucceeded) XCTAssertEqual(result.executionCount, 3 as UInt) } func testSharedExamplesWithContextPassContextToExamples() { let result = qck_runSpec(FunctionalTests_SharedExamples_ContextSpec.classForCoder()) XCTAssert(result.hasSucceeded) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/Helpers/QCKSpecRunner.h ================================================ #import /** Runs an XCTestSuite instance containing only the given XCTestCase subclass. Use this to run QuickSpec subclasses from within a set of unit tests. Due to implicit dependencies in _XCTFailureHandler, this function raises an exception when used in Swift to run a failing test case. @param specClass The class of the spec to be run. @return An XCTestRun instance that contains information such as the number of failures, etc. */ extern XCTestRun *qck_runSpec(Class specClass); /** Runs an XCTestSuite instance containing the given XCTestCase subclasses, in the order provided. See the documentation for `qck_runSpec` for more details. @param specClasses An array of QuickSpec classes, in the order they should be run. @return An XCTestRun instance that contains information such as the number of failures, etc. */ extern XCTestRun *qck_runSpecs(NSArray *specClasses); ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/Helpers/QCKSpecRunner.m ================================================ #import "QCKSpecRunner.h" #import "XCTestObservationCenter+QCKSuspendObservation.h" #import "World.h" #import XCTestRun *qck_runSuite(XCTestSuite *suite) { [World sharedWorld].isRunningAdditionalSuites = YES; __block XCTestRun *result = nil; [[XCTestObservationCenter sharedTestObservationCenter] _suspendObservationForBlock:^{ if ([suite respondsToSelector:@selector(runTest)]) { [suite runTest]; result = suite.testRun; } else { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" result = [suite run]; #pragma clang diagnostic pop } }]; return result; } XCTestRun *qck_runSpec(Class specClass) { return qck_runSuite([XCTestSuite testSuiteForTestCaseClass:specClass]); } XCTestRun *qck_runSpecs(NSArray *specClasses) { XCTestSuite *suite = [XCTestSuite testSuiteWithName:@"MySpecs"]; for (Class specClass in specClasses) { [suite addTest:[XCTestSuite testSuiteForTestCaseClass:specClass]]; } return qck_runSuite(suite); } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/Helpers/QuickTestsBridgingHeader.h ================================================ #import "QCKSpecRunner.h" ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/Helpers/XCTestObservationCenter+QCKSuspendObservation.h ================================================ #import /** Expose internal XCTest class and methods in order to run isolated XCTestSuite instances while the QuickTests test suite is running. If an Xcode upgrade causes QuickTests to crash when executing, or for tests to fail with the message "Timed out waiting for IDE barrier message to complete", it is likely that this internal interface has been changed. */ @interface XCTestObservationCenter (QCKSuspendObservation) /** Suspends test suite observation for the duration that the block is executing. Any test suites that are executed within the block do not generate any log output. Failures are still reported. Use this method to run XCTestSuite objects while another XCTestSuite is running. Without this method, tests fail with the message: "Timed out waiting for IDE barrier message to complete". */ - (void)_suspendObservationForBlock:(void (^)(void))block; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/QuickTests/QuickConfigurationTests.m ================================================ #import #import @interface QuickConfigurationTests : XCTestCase; @end @implementation QuickConfigurationTests - (void)testInitThrows { XCTAssertThrowsSpecificNamed([QuickConfiguration new], NSException, NSInternalInconsistencyException); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/README.md ================================================ ![](http://f.cl.ly/items/0r1E192C1R0b2g2Q3h2w/QuickLogo_Color.png) Quick is a behavior-driven development framework for Swift and Objective-C. Inspired by [RSpec](https://github.com/rspec/rspec), [Specta](https://github.com/specta/specta), and [Ginkgo](https://github.com/onsi/ginkgo). ![](https://raw.githubusercontent.com/Quick/Assets/master/Screenshots/QuickSpec%20screenshot.png) ```swift // Swift import Quick import Nimble class TableOfContentsSpec: QuickSpec { override func spec() { describe("the 'Documentation' directory") { it("has everything you need to get started") { let sections = Directory("Documentation").sections expect(sections).to(contain("Organized Tests with Quick Examples and Example Groups")) expect(sections).to(contain("Installing Quick")) } context("if it doesn't have what you're looking for") { it("needs to be updated") { let you = You(awesome: true) expect{you.submittedAnIssue}.toEventually(beTruthy()) } } } } } ``` #### Nimble Quick comes together with [Nimble](https://github.com/Quick/Nimble) — a matcher framework for your tests. You can learn why `XCTAssert()` statements make your expectations unclear and how to fix that using Nimble assertions [here](./Documentation/NimbleAssertions.md). ## Documentation All documentation can be found in the [Documentation folder](./Documentation), including [detailed installation instructions](./Documentation/InstallingQuick.md) for CocoaPods, Carthage, Git submodules, and more. For example, you can install Quick and [Nimble](https://github.com/Quick/Nimble) using CocoaPods by adding the following to your Podfile: ```rb # Podfile use_frameworks! def testing_pods # If you're using Xcode 7 / Swift 2 pod 'Quick', '~> 0.6.0' pod 'Nimble', '2.0.0-rc.3' # If you're using Xcode 6 / Swift 1.2 pod 'Quick', '~> 0.3.0' pod 'Nimble', '~> 1.0.0' end target 'MyTests' do testing_pods end target 'MyUITests' do testing_pods end ``` ## License Apache 2.0 license. See the `LICENSE` file for details. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/Rakefile ================================================ def run(command) system(command) or raise "RAKE TASK FAILED: #{command}" end namespace "test" do desc "Run unit tests for all iOS targets" task :ios do |t| run "xcodebuild -workspace Quick.xcworkspace -scheme Quick-iOS -destination 'platform=iOS Simulator,name=iPhone 6' clean test" end desc "Run unit tests for all OS X targets" task :osx do |t| run "xcodebuild -workspace Quick.xcworkspace -scheme Quick-OSX clean test" end end namespace "templates" do install_dir = File.expand_path("~/Library/Developer/Xcode/Templates/File Templates/Quick") src_dir = File.expand_path("../Quick Templates", __FILE__) desc "Install Quick templates" task :install do if File.exists? install_dir raise "RAKE TASK FAILED: Quick templates are already installed at #{install_dir}" else mkdir_p install_dir cp_r src_dir, install_dir end end desc "Uninstall Quick templates" task :uninstall do rm_rf install_dir end end task default: ["test:ios", "test:osx"] ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/circle.yml ================================================ machine: xcode: version: "7.0" checkout: post: - git submodule update --init --recursive # despite what circle ci says, xctool 0.2.3 cannot run # ios simulator tests on iOS frameworks for whatever reason. # # See: https://github.com/facebook/xctool/issues/415 test: override: - rake test:ios - rake test:osx ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Quick/script/release ================================================ #!/usr/bin/env sh REMOTE_BRANCH=master POD_NAME=Quick PODSPEC=Quick.podspec GITHUB_TAGS_URL=https://github.com/Quick/Quick/tags CARTHAGE_FRAMEWORK_NAME=Quick CARTHAGE=${CARTHAGE:-carthage} POD=${COCOAPODS:-pod} function help { echo "Usage: release VERSION RELEASE_NOTES [-f]" echo echo "VERSION should be the version to release, should not include the 'v' prefix" echo "RELEASE_NOTES should be a file that lists all the release notes for this version" echo " if file does not exist, creates a git-style commit with a diff as a comment" echo echo "FLAGS" echo " -f Forces override of tag" echo echo " Example: ./release 1.0.0-rc.2 ./release-notes.txt" echo echo "HINT: use 'git diff ...HEAD' to build the release notes" echo exit 2 } function die { echo "[ERROR] $@" echo exit 1 } if [ $# -lt 2 ]; then help fi VERSION=$1 RELEASE_NOTES=$2 FORCE_TAG=$3 VERSION_TAG="v$VERSION" echo "-> Verifying Local Directory for Release" if [ -z "`which $CARTHAGE`" ]; then die "Carthage is required to produce a release. Aborting." fi echo " > Carthage is installed" if [ -z "`which $POD`" ]; then die "Cocoapods is required to produce a release. Aborting." fi echo " > Cocoapods is installed" echo " > Is this a reasonable tag?" echo $VERSION_TAG | grep -q "^vv" if [ $? -eq 0 ]; then die "This tag ($VERSION) is an incorrect format. You should remove the 'v' prefix." fi echo $VERSION_TAG | grep -q -E "^v\d+\.\d+\.\d+(-\w+(\.\d)?)?\$" if [ $? -ne 0 ]; then die "This tag ($VERSION) is an incorrect format. It should be in 'v{MAJOR}.{MINOR}.{PATCH}(-{PRERELEASE_NAME}.{PRERELEASE_VERSION})' form." fi echo " > Is this version ($VERSION) unique?" git describe --exact-match "$VERSION_TAG" > /dev/null 2>&1 if [ $? -eq 0 ]; then if [ -z "$FORCE_TAG" ]; then die "This tag ($VERSION) already exists. Aborting. Append '-f' to override" else echo " > NO, but force was specified." fi else echo " > Yes, tag is unique" fi if [ ! -f "$RELEASE_NOTES" ]; then echo " > Failed to find $RELEASE_NOTES. Prompting editor" RELEASE_NOTES=.release-changes LATEST_TAG=`git for-each-ref refs/tags --sort=-refname --format="%(refname:short)" | grep -E "^v\d+\.\d+\.\d+(-\w+(\.\d)?)?\$" | ruby -e 'puts STDIN.read.split("\n").sort { |a,b| Gem::Version.new(a.gsub(/^v/, "")) <=> Gem::Version.new(b.gsub(/^v/, "")) }.last'` echo " > Latest tag ${LATEST_TAG}" echo "${POD_NAME} v$VERSION" > $RELEASE_NOTES echo "================" >> $RELEASE_NOTES echo >> $RELEASE_NOTES echo "# Changelog from ${LATEST_TAG}..HEAD" >> $RELEASE_NOTES git log ${LATEST_TAG}..HEAD | sed -e 's/^/# /' >> $RELEASE_NOTES $EDITOR $RELEASE_NOTES diff -q $RELEASE_NOTES ${RELEASE_NOTES}.backup > /dev/null 2>&1 STATUS=$? rm ${RELEASE_NOTES}.backup if [ $STATUS -eq 0 ]; then rm $RELEASE_NOTES die "No changes in release notes file. Aborting." fi fi echo " > Release notes: $RELEASE_NOTES" if [ ! -f "$PODSPEC" ]; then die "Cannot find podspec: $PODSPEC. Aborting." fi echo " > Podspec exists" git config --get user.signingkey > /dev/null || { echo "[ERROR] No PGP found to sign tag. Aborting." echo echo " Creating a release requires signing the tag for security purposes. This allows users to verify the git cloned tree is from a trusted source." echo " From a security perspective, it is not considered safe to trust the commits (including Author & Signed-off fields). It is easy for any" echo " intermediate between you and the end-users to modify the git repository." echo echo " While not all users may choose to verify the PGP key for tagged releases. It is a good measure to ensure 'this is an official release'" echo " from the official maintainers." echo echo " If you're creating your PGP key for the first time, use RSA with at least 4096 bits." echo echo "Related resources:" echo " - Configuring your system for PGP: https://git-scm.com/book/tr/v2/Git-Tools-Signing-Your-Work" echo " - Why: http://programmers.stackexchange.com/questions/212192/what-are-the-advantages-and-disadvantages-of-cryptographically-signing-commits-a" echo exit 2 } echo " > Found PGP key for git" # Verify cocoapods trunk ownership pod trunk me | grep -q "$POD_NAME" || die "You do not have access to pod repository $POD_NAME. Aborting." echo " > Verified ownership to $POD_NAME pod" echo "--- Releasing version $VERSION (tag: $VERSION_TAG)..." function restore_podspec { if [ -f "${PODSPEC}.backup" ]; then mv -f ${PODSPEC}{.backup,} fi } echo "-> Ensuring no differences to origin/$REMOTE_BRANCH" git fetch origin || die "Failed to fetch origin" git diff --quiet HEAD "origin/$REMOTE_BRANCH" || die "HEAD is not aligned to origin/$REMOTE_BRANCH. Cannot update version safely" echo "-> Building Carthage release" $CARTHAGE build --no-skip-current || die "Failed to build framework for carthage" echo "-> Setting podspec version" cat "$PODSPEC" | grep 's.version' | grep -q "\"$VERSION\"" SET_PODSPEC_VERSION=$? if [ $SET_PODSPEC_VERSION -eq 0 ]; then echo " > Podspec already set to $VERSION. Skipping." else sed -i.backup "s/s.version *= *\".*\"/s.version = \"$VERSION\"/g" "$PODSPEC" || { restore_podspec die "Failed to update version in podspec" } git add ${PODSPEC} || { restore_podspec; die "Failed to add ${PODSPEC} to INDEX"; } git commit -m "Bumping version to $VERSION" || { restore_podspec; die "Failed to push updated version: $VERSION"; } fi if [ -z "$FORCE_TAG" ]; then echo "-> Tagging version" git tag -s "$VERSION_TAG" -F "$RELEASE_NOTES" || die "Failed to tag version" echo "-> Pushing tag to origin" git push origin "$VERSION_TAG" || die "Failed to push tag '$VERSION_TAG' to origin" else echo "-> Tagging version (force)" git tag -f -s "$VERSION_TAG" -F "$RELEASE_NOTES" || die "Failed to tag version" echo "-> Pushing tag to origin (force)" git push origin "$VERSION_TAG" -f || die "Failed to push tag '$VERSION_TAG' to origin" fi if [ $SET_PODSPEC_VERSION -ne 0 ]; then rm $RELEASE_NOTES git push origin "$REMOTE_BRANCH" || die "Failed to push to origin" echo " > Pushed version to origin" fi echo echo "---------------- Released as $VERSION_TAG ----------------" echo echo "Archiving carthage release..." $CARTHAGE archive "$CARTHAGE_FRAMEWORK_NAME" || die "Failed to archive framework for carthage" echo echo "Pushing to pod trunk..." $POD trunk push "$PODSPEC" echo echo "================ Finalizing the Release ================" echo echo " - Go to $GITHUB_TAGS_URL and mark this as a release." echo " - Paste the contents of $RELEASE_NOTES into the release notes. Tweak for Github styling." echo " - Attach ${CARTHAGE_FRAMEWORK_NAME}.framework.zip to it." echo " - Announce!" rm ${PODSPEC}.backup ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/.gitignore ================================================ .DS_Store xcuserdata *.xcuserdatad *.xccheckout *.mode* *.pbxuser Carthage/Build .build ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/.travis.yml ================================================ language: objective-c osx_image: xcode7.1 script: - xcodebuild test -scheme Result-Mac - xcodebuild test -scheme Result-iOS -sdk iphonesimulator - xcodebuild test -scheme Result-tvOS -sdk appletvsimulator - xcodebuild build -scheme Result-watchOS -sdk watchsimulator - pod lib lint notifications: email: false ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/CONTRIBUTING.md ================================================ We love that you're interested in contributing to this project! To make the process as painless as possible, we have just a couple of guidelines that should make life easier for everyone involved. ## Prefer Pull Requests If you know exactly how to implement the feature being suggested or fix the bug being reported, please open a pull request instead of an issue. Pull requests are easier than patches or inline code blocks for discussing and merging the changes. If you can't make the change yourself, please open an issue after making sure that one isn't already logged. ## Contributing Code Fork this repository, make it awesomer (preferably in a branch named for the topic), send a pull request! All code contributions should match our [coding conventions](https://github.com/github/swift-style-guide). Thanks for contributing! :boom::camel: ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Rob Rix 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. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/Package.swift ================================================ import PackageDescription let package = Package( name: "Result", targets: [ Target( name: "Result" ) ] ) ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/README.md ================================================ # Result [![Build Status](https://travis-ci.org/antitypical/Result.svg?branch=master)](https://travis-ci.org/antitypical/Result) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![CocoaPods](https://img.shields.io/cocoapods/v/Result.svg)](https://cocoapods.org/) [![Reference Status](https://www.versioneye.com/objective-c/result/reference_badge.svg?style=flat)](https://www.versioneye.com/objective-c/result/references) This is a Swift µframework providing `Result`. `Result` values are either successful (wrapping `Value`) or failed (wrapping `Error`). This is similar to Swift’s native `Optional` type: `Success` is like `Some`, and `Failure` is like `None` except with an associated `ErrorType` value. The addition of an associated `ErrorType` allows errors to be passed along for logging or displaying to the user. Using this µframework instead of rolling your own `Result` type allows you to easily interface with other frameworks that also use `Result`. ## Use Use `Result` whenever an operation has the possibility of failure. Consider the following example of a function that tries to extract a `String` for a given key from a JSON `Dictionary`. ```swift typealias JSONObject = [String:AnyObject] enum JSONError : ErrorType { case NoSuchKey(String) case TypeMismatch } func stringForKey(json: JSONObject, key: String) -> Result { guard let value = json[key] else { return .Failure(.NoSuchKey(key)) } if let value = value as? String { return .Success(value) } else { return .Failure(.TypeMismatch) } } ``` This function provides a more robust wrapper around the default subscripting provided by `Dictionary`. Rather than return `AnyObject?`, it returns a `Result` that either contains the `String` value for the given key, or an `ErrorType` detailing what went wrong. One simple way to handle a `Result` is to deconstruct it using a `switch` statement. ```swift switch stringForKey(json, key: "email") { case let .Success(email): print("The email is \(email)") case let .Failure(JSONError.NoSuchKey(key)): print("\(key) is not a valid key") case .Failure(JSONError.TypeMismatch): print("Didn't have the right type") } ``` Using a `switch` statement allows powerful pattern matching, and ensures all possible results are covered. Swift 2.0 offers new ways to deconstruct enums like the `if-case` statement, but be wary as such methods do not ensure errors are handled. Other methods available for processing `Result` are detailed in the [API documentation](http://cocoadocs.org/docsets/Result/). ## Result vs. Throws Swift 2.0 introduces error handling via throwing and catching `ErrorType`. `Result` accomplishes the same goal by encapsulating the result instead of hijacking control flow. The `Result` abstraction allows enables powerful functionality such as `map` and `flatMap`, making `Result` more composable than `throw`. Since dealing with APIs that throw is common, you can convert functions such functions into a `Result` by using the `materialize` method. Conversely, a `Result` can be used to throw an error by calling `dematerialize`. [Note: due to compiler issues, `materialize` is not currently available] ## Higher Order Functions `map` and `flatMap` operate the same as `Optional.map` and `Optional.flatMap` except they apply to `Result`. `map` transforms a `Result` into a `Result` of a new type. It does this by taking a function that transforms the `Value` type into a new value. This transformation is only applied in the case of a `Success`. In the case of a `Failure`, the associated error is re-wrapped in the new `Result`. ```swift // transforms a Result to a Result let idResult = intForKey(json, key:"id").map { id in String(id) } ``` Here, the final result is either the id as a `String`, or carries over the `.Failure` from the previous result. `flatMap` is similar to `map` in that in transforms the `Result` into another `Result`. However, the function passed into `flatMap` must return a `Result`. An in depth discussion of `map` and `flatMap` is beyond the scope of this documentation. If you would like a deeper understanding, read about functors and monads. This article is a good place to [start](http://www.javiersoto.me/post/106875422394). ## Integration 1. Add this repository as a submodule and/or [add it to your Cartfile](https://github.com/Carthage/Carthage/blob/master/Documentation/Artifacts.md#cartfile) if you’re using [carthage](https://github.com/Carthage/Carthage/) to manage your dependencies. 2. Drag `Result.xcodeproj` into your project or workspace. 3. Link your target against `Result.framework`. 4. Application targets should ensure that the framework gets copied into their application bundle. (Framework targets should instead require the application linking them to include Result.) ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/Result/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0.2 CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright Copyright © 2015 Rob Rix. All rights reserved. NSPrincipalClass ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/Result/Result.h ================================================ // Copyright (c) 2015 Rob Rix. All rights reserved. /// Project version number for Result. extern double ResultVersionNumber; /// Project version string for Result. extern const unsigned char ResultVersionString[]; ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/Result/Result.swift ================================================ // Copyright (c) 2015 Rob Rix. All rights reserved. /// An enum representing either a failure with an explanatory error, or a success with a result value. public enum Result: ResultType, CustomStringConvertible, CustomDebugStringConvertible { case Success(T) case Failure(Error) // MARK: Constructors /// Constructs a success wrapping a `value`. public init(value: T) { self = .Success(value) } /// Constructs a failure wrapping an `error`. public init(error: Error) { self = .Failure(error) } /// Constructs a result from an Optional, failing with `Error` if `nil`. public init(_ value: T?, @autoclosure failWith: () -> Error) { self = value.map(Result.Success) ?? .Failure(failWith()) } /// Constructs a result from a function that uses `throw`, failing with `Error` if throws. public init(@autoclosure _ f: () throws -> T) { self.init(attempt: f) } /// Constructs a result from a function that uses `throw`, failing with `Error` if throws. public init(@noescape attempt f: () throws -> T) { do { self = .Success(try f()) } catch { self = .Failure(error as! Error) } } // MARK: Deconstruction /// Returns the value from `Success` Results or `throw`s the error. public func dematerialize() throws -> T { switch self { case let .Success(value): return value case let .Failure(error): throw error } } /// Case analysis for Result. /// /// Returns the value produced by applying `ifFailure` to `Failure` Results, or `ifSuccess` to `Success` Results. public func analysis(@noescape ifSuccess ifSuccess: T -> Result, @noescape ifFailure: Error -> Result) -> Result { switch self { case let .Success(value): return ifSuccess(value) case let .Failure(value): return ifFailure(value) } } // MARK: Higher-order functions /// Returns `self.value` if this result is a .Success, or the given value otherwise. Equivalent with `??` public func recover(@autoclosure value: () -> T) -> T { return self.value ?? value() } /// Returns this result if it is a .Success, or the given result otherwise. Equivalent with `??` public func recoverWith(@autoclosure result: () -> Result) -> Result { return analysis( ifSuccess: { _ in self }, ifFailure: { _ in result() }) } // MARK: Errors /// The domain for errors constructed by Result. public static var errorDomain: String { return "com.antitypical.Result" } /// The userInfo key for source functions in errors constructed by Result. public static var functionKey: String { return "\(errorDomain).function" } /// The userInfo key for source file paths in errors constructed by Result. public static var fileKey: String { return "\(errorDomain).file" } /// The userInfo key for source file line numbers in errors constructed by Result. public static var lineKey: String { return "\(errorDomain).line" } /// Constructs an error. public static func error(message: String? = nil, function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__) -> NSError { var userInfo: [String: AnyObject] = [ functionKey: function, fileKey: file, lineKey: line, ] if let message = message { userInfo[NSLocalizedDescriptionKey] = message } return NSError(domain: errorDomain, code: 0, userInfo: userInfo) } // MARK: CustomStringConvertible public var description: String { return analysis( ifSuccess: { ".Success(\($0))" }, ifFailure: { ".Failure(\($0))" }) } // MARK: CustomDebugStringConvertible public var debugDescription: String { return description } } /// Returns `true` if `left` and `right` are both `Success`es and their values are equal, or if `left` and `right` are both `Failure`s and their errors are equal. public func == (left: Result, right: Result) -> Bool { if let left = left.value, right = right.value { return left == right } else if let left = left.error, right = right.error { return left == right } return false } /// Returns `true` if `left` and `right` represent different cases, or if they represent the same case but different values. public func != (left: Result, right: Result) -> Bool { return !(left == right) } /// Returns the value of `left` if it is a `Success`, or `right` otherwise. Short-circuits. public func ?? (left: Result, @autoclosure right: () -> T) -> T { return left.recover(right()) } /// Returns `left` if it is a `Success`es, or `right` otherwise. Short-circuits. public func ?? (left: Result, @autoclosure right: () -> Result) -> Result { return left.recoverWith(right()) } // MARK: - Derive result from failable closure public func materialize(@noescape f: () throws -> T) -> Result { return materialize(try f()) } public func materialize(@autoclosure f: () throws -> T) -> Result { do { return .Success(try f()) } catch { return .Failure(error as NSError) } } // MARK: - Cocoa API conveniences /// Constructs a Result with the result of calling `try` with an error pointer. /// /// This is convenient for wrapping Cocoa API which returns an object or `nil` + an error, by reference. e.g.: /// /// Result.try { NSData(contentsOfURL: URL, options: .DataReadingMapped, error: $0) } public func `try`(function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__, `try`: NSErrorPointer -> T?) -> Result { var error: NSError? return `try`(&error).map(Result.Success) ?? .Failure(error ?? Result.error(function: function, file: file, line: line)) } /// Constructs a Result with the result of calling `try` with an error pointer. /// /// This is convenient for wrapping Cocoa API which returns a `Bool` + an error, by reference. e.g.: /// /// Result.try { NSFileManager.defaultManager().removeItemAtURL(URL, error: $0) } public func `try`(function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__, `try`: NSErrorPointer -> Bool) -> Result<(), NSError> { var error: NSError? return `try`(&error) ? .Success(()) : .Failure(error ?? Result<(), NSError>.error(function: function, file: file, line: line)) } // MARK: - Operators infix operator >>- { // Left-associativity so that chaining works like you’d expect, and for consistency with Haskell, Runes, swiftz, etc. associativity left // Higher precedence than function application, but lower than function composition. precedence 100 } /// Returns the result of applying `transform` to `Success`es’ values, or re-wrapping `Failure`’s errors. /// /// This is a synonym for `flatMap`. public func >>- (result: Result, @noescape transform: T -> Result) -> Result { return result.flatMap(transform) } // MARK: - ErrorTypeConvertible conformance /// Make NSError conform to ErrorTypeConvertible extension NSError: ErrorTypeConvertible { public static func errorFromErrorType(error: ErrorType) -> NSError { return error as NSError } } // MARK: - /// An “error” that is impossible to construct. /// /// This can be used to describe `Result`s where failures will never /// be generated. For example, `Result` describes a result that /// contains an `Int`eger and is guaranteed never to be a `Failure`. public enum NoError: ErrorType { } import Foundation ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/Result/ResultType.swift ================================================ // Copyright (c) 2015 Rob Rix. All rights reserved. /// A type that can represent either failure with an error or success with a result value. public protocol ResultType { typealias Value typealias Error: ErrorType /// Constructs a successful result wrapping a `value`. init(value: Value) /// Constructs a failed result wrapping an `error`. init(error: Error) /// Case analysis for ResultType. /// /// Returns the value produced by appliying `ifFailure` to the error if self represents a failure, or `ifSuccess` to the result value if self represents a success. func analysis(@noescape ifSuccess ifSuccess: Value -> U, @noescape ifFailure: Error -> U) -> U /// Returns the value if self represents a success, `nil` otherwise. /// /// A default implementation is provided by a protocol extension. Conforming types may specialize it. var value: Value? { get } /// Returns the error if self represents a failure, `nil` otherwise. /// /// A default implementation is provided by a protocol extension. Conforming types may specialize it. var error: Error? { get } } public extension ResultType { /// Returns the value if self represents a success, `nil` otherwise. public var value: Value? { return analysis(ifSuccess: { $0 }, ifFailure: { _ in nil }) } /// Returns the error if self represents a failure, `nil` otherwise. public var error: Error? { return analysis(ifSuccess: { _ in nil }, ifFailure: { $0 }) } /// Returns a new Result by mapping `Success`es’ values using `transform`, or re-wrapping `Failure`s’ errors. public func map(@noescape transform: Value -> U) -> Result { return flatMap { .Success(transform($0)) } } /// Returns the result of applying `transform` to `Success`es’ values, or re-wrapping `Failure`’s errors. public func flatMap(@noescape transform: Value -> Result) -> Result { return analysis( ifSuccess: transform, ifFailure: Result.Failure) } /// Returns a new Result by mapping `Failure`'s values using `transform`, or re-wrapping `Success`es’ values. public func mapError(@noescape transform: Error -> Error2) -> Result { return flatMapError { .Failure(transform($0)) } } /// Returns the result of applying `transform` to `Failure`’s errors, or re-wrapping `Success`es’ values. public func flatMapError(@noescape transform: Error -> Result) -> Result { return analysis( ifSuccess: Result.Success, ifFailure: transform) } } /// Protocol used to constrain `tryMap` to `Result`s with compatible `Error`s. public protocol ErrorTypeConvertible: ErrorType { typealias ConvertibleType = Self static func errorFromErrorType(error: ErrorType) -> ConvertibleType } public extension ResultType where Error: ErrorTypeConvertible { /// Returns the result of applying `transform` to `Success`es’ values, or wrapping thrown errors. public func tryMap(@noescape transform: Value throws -> U) -> Result { return flatMap { value in do { return .Success(try transform(value)) } catch { let convertedError = Error.errorFromErrorType(error) as! Error // Revisit this in a future version of Swift. https://twitter.com/jckarter/status/672931114944696321 return .Failure(convertedError) } } } } // MARK: - Operators infix operator &&& { /// Same associativity as &&. associativity left /// Same precedence as &&. precedence 120 } /// Returns a Result with a tuple of `left` and `right` values if both are `Success`es, or re-wrapping the error of the earlier `Failure`. public func &&& (left: L, @autoclosure right: () -> R) -> Result<(L.Value, R.Value), L.Error> { return left.flatMap { left in right().map { right in (left, right) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/Result.podspec ================================================ Pod::Spec.new do |s| s.name = 'Result' s.version = '1.0.2' s.summary = 'Swift type modelling the success/failure of arbitrary operations' s.homepage = 'https://github.com/antitypical/Result' s.license = { :type => 'MIT', :file => 'LICENSE' } s.author = { 'Rob Rix' => 'rob.rix@github.com' } s.source = { :git => 'https://github.com/antitypical/Result.git', :tag => s.version } s.source_files = 'Result/*.swift' s.requires_arc = true s.ios.deployment_target = '8.0' s.osx.deployment_target = '10.9' s.watchos.deployment_target = '2.0' s.tvos.deployment_target = '9.0' end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/Result.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 45AE89E61B3A6564007B99D7 /* ResultType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93621451B35596200948F2A /* ResultType.swift */; }; 57FCDE3E1BA280DC00130C48 /* ResultType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93621451B35596200948F2A /* ResultType.swift */; }; 57FCDE3F1BA280DC00130C48 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = D45480961A957465009D7229 /* Result.swift */; }; 57FCDE421BA280DC00130C48 /* Result.h in Headers */ = {isa = PBXBuildFile; fileRef = D454805C1A9572F5009D7229 /* Result.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57FCDE4D1BA280E000130C48 /* ResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D454806E1A9572F5009D7229 /* ResultTests.swift */; }; 57FCDE561BA2814300130C48 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57FCDE471BA280DC00130C48 /* Result.framework */; }; D035799B1B2B788F005D26AE /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = D45480961A957465009D7229 /* Result.swift */; }; D035799E1B2B788F005D26AE /* Result.h in Headers */ = {isa = PBXBuildFile; fileRef = D454805C1A9572F5009D7229 /* Result.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03579A91B2B78A1005D26AE /* ResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D454806E1A9572F5009D7229 /* ResultTests.swift */; }; D03579B41B2B78C4005D26AE /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03579A31B2B788F005D26AE /* Result.framework */; }; D454805D1A9572F5009D7229 /* Result.h in Headers */ = {isa = PBXBuildFile; fileRef = D454805C1A9572F5009D7229 /* Result.h */; settings = {ATTRIBUTES = (Public, ); }; }; D45480681A9572F5009D7229 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D45480571A9572F5009D7229 /* Result.framework */; }; D454806F1A9572F5009D7229 /* ResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D454806E1A9572F5009D7229 /* ResultTests.swift */; }; D45480881A957362009D7229 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D454807D1A957361009D7229 /* Result.framework */; }; D45480971A957465009D7229 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = D45480961A957465009D7229 /* Result.swift */; }; D45480981A957465009D7229 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = D45480961A957465009D7229 /* Result.swift */; }; D45480991A9574B8009D7229 /* ResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D454806E1A9572F5009D7229 /* ResultTests.swift */; }; D454809A1A9574BB009D7229 /* Result.h in Headers */ = {isa = PBXBuildFile; fileRef = D454805C1A9572F5009D7229 /* Result.h */; settings = {ATTRIBUTES = (Public, ); }; }; E93621461B35596200948F2A /* ResultType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93621451B35596200948F2A /* ResultType.swift */; }; E93621471B35596200948F2A /* ResultType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93621451B35596200948F2A /* ResultType.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 57FCDE571BA2814A00130C48 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D454804E1A9572F5009D7229 /* Project object */; proxyType = 1; remoteGlobalIDString = 57FCDE3C1BA280DC00130C48; remoteInfo = "Result-tvOS"; }; D03579B21B2B78BB005D26AE /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D454804E1A9572F5009D7229 /* Project object */; proxyType = 1; remoteGlobalIDString = D03579991B2B788F005D26AE; remoteInfo = "Result-watchOS"; }; D45480691A9572F5009D7229 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D454804E1A9572F5009D7229 /* Project object */; proxyType = 1; remoteGlobalIDString = D45480561A9572F5009D7229; remoteInfo = Result; }; D45480891A957362009D7229 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D454804E1A9572F5009D7229 /* Project object */; proxyType = 1; remoteGlobalIDString = D454807C1A957361009D7229; remoteInfo = "Result-iOS"; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 57FCDE471BA280DC00130C48 /* Result.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Result.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 57FCDE541BA280E000130C48 /* Result-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Result-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; D03579A31B2B788F005D26AE /* Result.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Result.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D03579B01B2B78A1005D26AE /* Result-watchOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Result-watchOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; D45480571A9572F5009D7229 /* Result.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Result.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D454805B1A9572F5009D7229 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D454805C1A9572F5009D7229 /* Result.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Result.h; sourceTree = ""; }; D45480671A9572F5009D7229 /* Result-MacTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Result-MacTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; D454806D1A9572F5009D7229 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D454806E1A9572F5009D7229 /* ResultTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultTests.swift; sourceTree = ""; }; D454807D1A957361009D7229 /* Result.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Result.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D45480871A957362009D7229 /* Result-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Result-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; D45480961A957465009D7229 /* Result.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = ""; }; E93621451B35596200948F2A /* ResultType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultType.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 57FCDE401BA280DC00130C48 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 57FCDE4E1BA280E000130C48 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 57FCDE561BA2814300130C48 /* Result.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; D035799C1B2B788F005D26AE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D03579AA1B2B78A1005D26AE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( D03579B41B2B78C4005D26AE /* Result.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; D45480531A9572F5009D7229 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D45480641A9572F5009D7229 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( D45480681A9572F5009D7229 /* Result.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; D45480791A957361009D7229 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D45480841A957362009D7229 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( D45480881A957362009D7229 /* Result.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ D454804D1A9572F5009D7229 = { isa = PBXGroup; children = ( D45480591A9572F5009D7229 /* Result */, D454806B1A9572F5009D7229 /* ResultTests */, D45480581A9572F5009D7229 /* Products */, ); sourceTree = ""; usesTabs = 1; }; D45480581A9572F5009D7229 /* Products */ = { isa = PBXGroup; children = ( D45480571A9572F5009D7229 /* Result.framework */, D45480671A9572F5009D7229 /* Result-MacTests.xctest */, D454807D1A957361009D7229 /* Result.framework */, D45480871A957362009D7229 /* Result-iOSTests.xctest */, D03579A31B2B788F005D26AE /* Result.framework */, D03579B01B2B78A1005D26AE /* Result-watchOSTests.xctest */, 57FCDE471BA280DC00130C48 /* Result.framework */, 57FCDE541BA280E000130C48 /* Result-tvOSTests.xctest */, ); name = Products; sourceTree = ""; }; D45480591A9572F5009D7229 /* Result */ = { isa = PBXGroup; children = ( D454805C1A9572F5009D7229 /* Result.h */, D45480961A957465009D7229 /* Result.swift */, E93621451B35596200948F2A /* ResultType.swift */, D454805A1A9572F5009D7229 /* Supporting Files */, ); path = Result; sourceTree = ""; }; D454805A1A9572F5009D7229 /* Supporting Files */ = { isa = PBXGroup; children = ( D454805B1A9572F5009D7229 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; D454806B1A9572F5009D7229 /* ResultTests */ = { isa = PBXGroup; children = ( D454806E1A9572F5009D7229 /* ResultTests.swift */, D454806C1A9572F5009D7229 /* Supporting Files */, ); name = ResultTests; path = Tests; sourceTree = ""; }; D454806C1A9572F5009D7229 /* Supporting Files */ = { isa = PBXGroup; children = ( D454806D1A9572F5009D7229 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 57FCDE411BA280DC00130C48 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 57FCDE421BA280DC00130C48 /* Result.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; D035799D1B2B788F005D26AE /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( D035799E1B2B788F005D26AE /* Result.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; D45480541A9572F5009D7229 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( D454805D1A9572F5009D7229 /* Result.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; D454807A1A957361009D7229 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( D454809A1A9574BB009D7229 /* Result.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 57FCDE3C1BA280DC00130C48 /* Result-tvOS */ = { isa = PBXNativeTarget; buildConfigurationList = 57FCDE441BA280DC00130C48 /* Build configuration list for PBXNativeTarget "Result-tvOS" */; buildPhases = ( 57FCDE3D1BA280DC00130C48 /* Sources */, 57FCDE401BA280DC00130C48 /* Frameworks */, 57FCDE411BA280DC00130C48 /* Headers */, 57FCDE431BA280DC00130C48 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Result-tvOS"; productName = "Result-iOS"; productReference = 57FCDE471BA280DC00130C48 /* Result.framework */; productType = "com.apple.product-type.framework"; }; 57FCDE491BA280E000130C48 /* Result-tvOSTests */ = { isa = PBXNativeTarget; buildConfigurationList = 57FCDE511BA280E000130C48 /* Build configuration list for PBXNativeTarget "Result-tvOSTests" */; buildPhases = ( 57FCDE4C1BA280E000130C48 /* Sources */, 57FCDE4E1BA280E000130C48 /* Frameworks */, 57FCDE501BA280E000130C48 /* Resources */, ); buildRules = ( ); dependencies = ( 57FCDE581BA2814A00130C48 /* PBXTargetDependency */, ); name = "Result-tvOSTests"; productName = "Result-iOSTests"; productReference = 57FCDE541BA280E000130C48 /* Result-tvOSTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; D03579991B2B788F005D26AE /* Result-watchOS */ = { isa = PBXNativeTarget; buildConfigurationList = D03579A01B2B788F005D26AE /* Build configuration list for PBXNativeTarget "Result-watchOS" */; buildPhases = ( D035799A1B2B788F005D26AE /* Sources */, D035799C1B2B788F005D26AE /* Frameworks */, D035799D1B2B788F005D26AE /* Headers */, D035799F1B2B788F005D26AE /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Result-watchOS"; productName = Result; productReference = D03579A31B2B788F005D26AE /* Result.framework */; productType = "com.apple.product-type.framework"; }; D03579A51B2B78A1005D26AE /* Result-watchOSTests */ = { isa = PBXNativeTarget; buildConfigurationList = D03579AD1B2B78A1005D26AE /* Build configuration list for PBXNativeTarget "Result-watchOSTests" */; buildPhases = ( D03579A81B2B78A1005D26AE /* Sources */, D03579AA1B2B78A1005D26AE /* Frameworks */, D03579AC1B2B78A1005D26AE /* Resources */, ); buildRules = ( ); dependencies = ( D03579B31B2B78BB005D26AE /* PBXTargetDependency */, ); name = "Result-watchOSTests"; productName = ResultTests; productReference = D03579B01B2B78A1005D26AE /* Result-watchOSTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; D45480561A9572F5009D7229 /* Result-Mac */ = { isa = PBXNativeTarget; buildConfigurationList = D45480721A9572F5009D7229 /* Build configuration list for PBXNativeTarget "Result-Mac" */; buildPhases = ( D45480521A9572F5009D7229 /* Sources */, D45480531A9572F5009D7229 /* Frameworks */, D45480541A9572F5009D7229 /* Headers */, D45480551A9572F5009D7229 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Result-Mac"; productName = Result; productReference = D45480571A9572F5009D7229 /* Result.framework */; productType = "com.apple.product-type.framework"; }; D45480661A9572F5009D7229 /* Result-MacTests */ = { isa = PBXNativeTarget; buildConfigurationList = D45480751A9572F5009D7229 /* Build configuration list for PBXNativeTarget "Result-MacTests" */; buildPhases = ( D45480631A9572F5009D7229 /* Sources */, D45480641A9572F5009D7229 /* Frameworks */, D45480651A9572F5009D7229 /* Resources */, ); buildRules = ( ); dependencies = ( D454806A1A9572F5009D7229 /* PBXTargetDependency */, ); name = "Result-MacTests"; productName = ResultTests; productReference = D45480671A9572F5009D7229 /* Result-MacTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; D454807C1A957361009D7229 /* Result-iOS */ = { isa = PBXNativeTarget; buildConfigurationList = D45480941A957362009D7229 /* Build configuration list for PBXNativeTarget "Result-iOS" */; buildPhases = ( D45480781A957361009D7229 /* Sources */, D45480791A957361009D7229 /* Frameworks */, D454807A1A957361009D7229 /* Headers */, D454807B1A957361009D7229 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Result-iOS"; productName = "Result-iOS"; productReference = D454807D1A957361009D7229 /* Result.framework */; productType = "com.apple.product-type.framework"; }; D45480861A957362009D7229 /* Result-iOSTests */ = { isa = PBXNativeTarget; buildConfigurationList = D45480951A957362009D7229 /* Build configuration list for PBXNativeTarget "Result-iOSTests" */; buildPhases = ( D45480831A957362009D7229 /* Sources */, D45480841A957362009D7229 /* Frameworks */, D45480851A957362009D7229 /* Resources */, ); buildRules = ( ); dependencies = ( D454808A1A957362009D7229 /* PBXTargetDependency */, ); name = "Result-iOSTests"; productName = "Result-iOSTests"; productReference = D45480871A957362009D7229 /* Result-iOSTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ D454804E1A9572F5009D7229 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0700; LastUpgradeCheck = 0700; ORGANIZATIONNAME = "Rob Rix"; TargetAttributes = { D45480561A9572F5009D7229 = { CreatedOnToolsVersion = 6.3; }; D45480661A9572F5009D7229 = { CreatedOnToolsVersion = 6.3; }; D454807C1A957361009D7229 = { CreatedOnToolsVersion = 6.3; }; D45480861A957362009D7229 = { CreatedOnToolsVersion = 6.3; }; }; }; buildConfigurationList = D45480511A9572F5009D7229 /* Build configuration list for PBXProject "Result" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = D454804D1A9572F5009D7229; productRefGroup = D45480581A9572F5009D7229 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( D45480561A9572F5009D7229 /* Result-Mac */, D45480661A9572F5009D7229 /* Result-MacTests */, D454807C1A957361009D7229 /* Result-iOS */, D45480861A957362009D7229 /* Result-iOSTests */, 57FCDE3C1BA280DC00130C48 /* Result-tvOS */, 57FCDE491BA280E000130C48 /* Result-tvOSTests */, D03579991B2B788F005D26AE /* Result-watchOS */, D03579A51B2B78A1005D26AE /* Result-watchOSTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 57FCDE431BA280DC00130C48 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 57FCDE501BA280E000130C48 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D035799F1B2B788F005D26AE /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D03579AC1B2B78A1005D26AE /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D45480551A9572F5009D7229 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D45480651A9572F5009D7229 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D454807B1A957361009D7229 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D45480851A957362009D7229 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 57FCDE3D1BA280DC00130C48 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 57FCDE3E1BA280DC00130C48 /* ResultType.swift in Sources */, 57FCDE3F1BA280DC00130C48 /* Result.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 57FCDE4C1BA280E000130C48 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 57FCDE4D1BA280E000130C48 /* ResultTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D035799A1B2B788F005D26AE /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 45AE89E61B3A6564007B99D7 /* ResultType.swift in Sources */, D035799B1B2B788F005D26AE /* Result.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D03579A81B2B78A1005D26AE /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D03579A91B2B78A1005D26AE /* ResultTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D45480521A9572F5009D7229 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E93621461B35596200948F2A /* ResultType.swift in Sources */, D45480971A957465009D7229 /* Result.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D45480631A9572F5009D7229 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D454806F1A9572F5009D7229 /* ResultTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D45480781A957361009D7229 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E93621471B35596200948F2A /* ResultType.swift in Sources */, D45480981A957465009D7229 /* Result.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D45480831A957362009D7229 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D45480991A9574B8009D7229 /* ResultTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 57FCDE581BA2814A00130C48 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 57FCDE3C1BA280DC00130C48 /* Result-tvOS */; targetProxy = 57FCDE571BA2814A00130C48 /* PBXContainerItemProxy */; }; D03579B31B2B78BB005D26AE /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D03579991B2B788F005D26AE /* Result-watchOS */; targetProxy = D03579B21B2B78BB005D26AE /* PBXContainerItemProxy */; }; D454806A1A9572F5009D7229 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D45480561A9572F5009D7229 /* Result-Mac */; targetProxy = D45480691A9572F5009D7229 /* PBXContainerItemProxy */; }; D454808A1A957362009D7229 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D454807C1A957361009D7229 /* Result-iOS */; targetProxy = D45480891A957362009D7229 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 57FCDE451BA280DC00130C48 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BITCODE_GENERATION_MODE = bitcode; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=appletvsimulator*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = Result/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Result; SDKROOT = appletvos; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TARGETED_DEVICE_FAMILY = 3; }; name = Debug; }; 57FCDE461BA280DC00130C48 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BITCODE_GENERATION_MODE = bitcode; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=appletvsimulator*]" = ""; COPY_PHASE_STRIP = NO; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Result/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Result; SDKROOT = appletvos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = 3; VALIDATE_PRODUCT = YES; }; name = Release; }; 57FCDE521BA280E000130C48 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; CODE_SIGN_IDENTITY = "iPhone Developer"; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; }; name = Debug; }; 57FCDE531BA280E000130C48 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; VALIDATE_PRODUCT = YES; }; name = Release; }; D03579A11B2B788F005D26AE /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BITCODE_GENERATION_MODE = bitcode; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=watchsimulator*]" = ""; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; INFOPLIST_FILE = Result/Info.plist; INSTALL_PATH = "@rpath"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Result; SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; D03579A21B2B788F005D26AE /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BITCODE_GENERATION_MODE = bitcode; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=watchsimulator*]" = ""; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; INFOPLIST_FILE = Result/Info.plist; INSTALL_PATH = "@rpath"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Result; SDKROOT = watchos; SKIP_INSTALL = YES; }; name = Release; }; D03579AE1B2B78A1005D26AE /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; }; name = Debug; }; D03579AF1B2B78A1005D26AE /* Release */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; }; name = Release; }; D45480701A9572F5009D7229 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; APPLICATION_EXTENSION_API_ONLY = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; 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; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.antitypical.$(PRODUCT_NAME:rfc1034identifier)"; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TVOS_DEPLOYMENT_TARGET = 9.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Debug; }; D45480711A9572F5009D7229 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; APPLICATION_EXTENSION_API_ONLY = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; 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; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.antitypical.$(PRODUCT_NAME:rfc1034identifier)"; SDKROOT = macosx; TVOS_DEPLOYMENT_TARGET = 9.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Release; }; D45480731A9572F5009D7229 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; INFOPLIST_FILE = Result/Info.plist; INSTALL_PATH = "@rpath"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Result; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; VALID_ARCHS = x86_64; }; name = Debug; }; D45480741A9572F5009D7229 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; INFOPLIST_FILE = Result/Info.plist; INSTALL_PATH = "@rpath"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Result; SKIP_INSTALL = YES; VALID_ARCHS = x86_64; }; name = Release; }; D45480761A9572F5009D7229 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; D45480771A9572F5009D7229 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; D45480901A957362009D7229 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BITCODE_GENERATION_MODE = bitcode; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphonesimulator*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = Result/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Result; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; D45480911A957362009D7229 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BITCODE_GENERATION_MODE = bitcode; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphonesimulator*]" = ""; COPY_PHASE_STRIP = NO; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = YES; INFOPLIST_FILE = Result/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Result; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; D45480921A957362009D7229 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; CODE_SIGN_IDENTITY = "iPhone Developer"; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; }; name = Debug; }; D45480931A957362009D7229 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 57FCDE441BA280DC00130C48 /* Build configuration list for PBXNativeTarget "Result-tvOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 57FCDE451BA280DC00130C48 /* Debug */, 57FCDE461BA280DC00130C48 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 57FCDE511BA280E000130C48 /* Build configuration list for PBXNativeTarget "Result-tvOSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 57FCDE521BA280E000130C48 /* Debug */, 57FCDE531BA280E000130C48 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D03579A01B2B788F005D26AE /* Build configuration list for PBXNativeTarget "Result-watchOS" */ = { isa = XCConfigurationList; buildConfigurations = ( D03579A11B2B788F005D26AE /* Debug */, D03579A21B2B788F005D26AE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D03579AD1B2B78A1005D26AE /* Build configuration list for PBXNativeTarget "Result-watchOSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( D03579AE1B2B78A1005D26AE /* Debug */, D03579AF1B2B78A1005D26AE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D45480511A9572F5009D7229 /* Build configuration list for PBXProject "Result" */ = { isa = XCConfigurationList; buildConfigurations = ( D45480701A9572F5009D7229 /* Debug */, D45480711A9572F5009D7229 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D45480721A9572F5009D7229 /* Build configuration list for PBXNativeTarget "Result-Mac" */ = { isa = XCConfigurationList; buildConfigurations = ( D45480731A9572F5009D7229 /* Debug */, D45480741A9572F5009D7229 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D45480751A9572F5009D7229 /* Build configuration list for PBXNativeTarget "Result-MacTests" */ = { isa = XCConfigurationList; buildConfigurations = ( D45480761A9572F5009D7229 /* Debug */, D45480771A9572F5009D7229 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D45480941A957362009D7229 /* Build configuration list for PBXNativeTarget "Result-iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( D45480901A957362009D7229 /* Debug */, D45480911A957362009D7229 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D45480951A957362009D7229 /* Build configuration list for PBXNativeTarget "Result-iOSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( D45480921A957362009D7229 /* Debug */, D45480931A957362009D7229 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = D454804E1A9572F5009D7229 /* Project object */; } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/Result.xcodeproj/xcshareddata/xcschemes/Result-Mac.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/Result.xcodeproj/xcshareddata/xcschemes/Result-iOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/Result.xcodeproj/xcshareddata/xcschemes/Result-tvOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/Result.xcodeproj/xcshareddata/xcschemes/Result-watchOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/Tests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/Result/Tests/ResultTests.swift ================================================ // Copyright (c) 2015 Rob Rix. All rights reserved. final class ResultTests: XCTestCase { func testMapTransformsSuccesses() { XCTAssertEqual(success.map { $0.characters.count } ?? 0, 7) } func testMapRewrapsFailures() { XCTAssertEqual(failure.map { $0.characters.count } ?? 0, 0) } func testInitOptionalSuccess() { XCTAssert(Result("success" as String?, failWith: error) == success) } func testInitOptionalFailure() { XCTAssert(Result(nil, failWith: error) == failure) } // MARK: Errors func testErrorsIncludeTheSourceFile() { let file = __FILE__ XCTAssert(Result<(), NSError>.error().file == file) } func testErrorsIncludeTheSourceLine() { let (line, error) = (__LINE__, Result<(), NSError>.error()) XCTAssertEqual(error.line ?? -1, line) } func testErrorsIncludeTheCallingFunction() { let function = __FUNCTION__ XCTAssert(Result<(), NSError>.error().function == function) } // MARK: Try - Catch func testTryCatchProducesSuccesses() { let result: Result = Result(try tryIsSuccess("success")) XCTAssert(result == success) } func testTryCatchProducesFailures() { let result: Result = Result(try tryIsSuccess(nil)) XCTAssert(result.error == error) } func testTryCatchWithFunctionProducesSuccesses() { let function = { try tryIsSuccess("success") } let result: Result = Result(attempt: function) XCTAssert(result == success) } func testTryCatchWithFunctionCatchProducesFailures() { let function = { try tryIsSuccess(nil) } let result: Result = Result(attempt: function) XCTAssert(result.error == error) } func testMaterializeProducesSuccesses() { let result1 = materialize(try tryIsSuccess("success")) XCTAssert(result1 == success) let result2 = materialize { try tryIsSuccess("success") } XCTAssert(result2 == success) } func testMaterializeProducesFailures() { let result1 = materialize(try tryIsSuccess(nil)) XCTAssert(result1.error == error) let result2 = materialize { try tryIsSuccess(nil) } XCTAssert(result2.error == error) } // MARK: Cocoa API idioms func testTryProducesFailuresForBooleanAPIWithErrorReturnedByReference() { let result = `try` { attempt(true, succeed: false, error: $0) } XCTAssertFalse(result ?? false) XCTAssertNotNil(result.error) } func testTryProducesFailuresForOptionalWithErrorReturnedByReference() { let result = `try` { attempt(1, succeed: false, error: $0) } XCTAssertEqual(result ?? 0, 0) XCTAssertNotNil(result.error) } func testTryProducesSuccessesForBooleanAPI() { let result = `try` { attempt(true, succeed: true, error: $0) } XCTAssertTrue(result ?? false) XCTAssertNil(result.error) } func testTryProducesSuccessesForOptionalAPI() { let result = `try` { attempt(1, succeed: true, error: $0) } XCTAssertEqual(result ?? 0, 1) XCTAssertNil(result.error) } func testTryMapProducesSuccess() { let result = success.tryMap(tryIsSuccess) XCTAssert(result == success) } func testTryMapProducesFailure() { let result = Result.Success("fail").tryMap(tryIsSuccess) XCTAssert(result == failure) } // MARK: Operators func testConjunctionOperator() { let resultSuccess = success &&& success if let (x, y) = resultSuccess.value { XCTAssertTrue(x == "success" && y == "success") } else { XCTFail() } let resultFailureBoth = failure &&& failure2 XCTAssert(resultFailureBoth.error == error) let resultFailureLeft = failure &&& success XCTAssert(resultFailureLeft.error == error) let resultFailureRight = success &&& failure2 XCTAssert(resultFailureRight.error == error2) } } // MARK: - Fixtures let success = Result.Success("success") let error = NSError(domain: "com.antitypical.Result", code: 1, userInfo: nil) let error2 = NSError(domain: "com.antitypical.Result", code: 2, userInfo: nil) let failure = Result.Failure(error) let failure2 = Result.Failure(error2) // MARK: - Helpers func attempt(value: T, succeed: Bool, error: NSErrorPointer) -> T? { if succeed { return value } else { error.memory = Result<(), NSError>.error() return nil } } func tryIsSuccess(text: String?) throws -> String { guard let text = text where text == "success" else { throw error } return text } extension NSError { var function: String? { return userInfo[Result<(), NSError>.functionKey as NSString] as? String } var file: String? { return userInfo[Result<(), NSError>.fileKey as NSString] as? String } var line: Int? { return userInfo[Result<(), NSError>.lineKey as NSString] as? Int } } import Result import XCTest ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/.gitignore ================================================ Carthage/Build ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/Base/Common.xcconfig ================================================ // // This file defines common settings that should be enabled for every new // project. Typically, you want to use Debug, Release, or a similar variant // instead. // // Disable legacy-compatible header searching ALWAYS_SEARCH_USER_PATHS = NO // Architectures to build ARCHS = $(ARCHS_STANDARD) // Whether to warn when a floating-point value is used as a loop counter CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES // Whether to warn about use of rand() and random() being used instead of arc4random() CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES // Whether to warn about strcpy() and strcat() CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES // Whether to enable module imports CLANG_ENABLE_MODULES = YES // Enable ARC CLANG_ENABLE_OBJC_ARC = YES // Warn about implicit conversions to boolean values that are suspicious. // For example, writing 'if (foo)' with 'foo' being the name a function will trigger a warning. CLANG_WARN_BOOL_CONVERSION = YES // Warn about implicit conversions of constant values that cause the constant value to change, // either through a loss of precision, or entirely in its meaning. CLANG_WARN_CONSTANT_CONVERSION = YES // Whether to warn when overriding deprecated methods CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES // Warn about direct accesses to the Objective-C 'isa' pointer instead of using a runtime API. CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR // Warn about declaring the same method more than once within the same @interface. CLANG_WARN__DUPLICATE_METHOD_MATCH = YES // Warn about loop bodies that are suspiciously empty. CLANG_WARN_EMPTY_BODY = YES // Warn about implicit conversions between different kinds of enum values. // For example, this can catch issues when using the wrong enum flag as an argument to a function or method. CLANG_WARN_ENUM_CONVERSION = YES // Whether to warn on implicit conversions between signed/unsigned types CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO // Warn about implicit conversions between pointers and integers. // For example, this can catch issues when one incorrectly intermixes using NSNumbers and raw integers. CLANG_WARN_INT_CONVERSION = YES // Don't warn about repeatedly using a weak reference without assigning the weak reference to a strong reference. Too many false positives. CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = NO // Warn about classes that unintentionally do not subclass a root class (such as NSObject). CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR // Whether to warn on suspicious implicit conversions CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES // Warn about potentially unreachable code CLANG_WARN_UNREACHABLE_CODE = YES // The format of debugging symbols DEBUG_INFORMATION_FORMAT = dwarf-with-dsym // Whether to compile assertions in ENABLE_NS_ASSERTIONS = YES // Whether to require objc_msgSend to be cast before invocation ENABLE_STRICT_OBJC_MSGSEND = YES // Which C variant to use GCC_C_LANGUAGE_STANDARD = gnu99 // Whether to enable exceptions for Objective-C GCC_ENABLE_OBJC_EXCEPTIONS = YES // Whether to generate debugging symbols GCC_GENERATE_DEBUGGING_SYMBOLS = YES // Whether to precompile the prefix header (if one is specified) GCC_PRECOMPILE_PREFIX_HEADER = YES // Whether to enable strict aliasing, meaning that two pointers of different // types (other than void * or any id type) cannot point to the same memory // location GCC_STRICT_ALIASING = YES // Whether symbols not explicitly exported are hidden by default (this primarily // only affects C++ code) GCC_SYMBOLS_PRIVATE_EXTERN = NO // Whether static variables are thread-safe by default GCC_THREADSAFE_STATICS = NO // Which compiler to use GCC_VERSION = com.apple.compilers.llvm.clang.1_0 // Whether warnings are treated as errors GCC_TREAT_WARNINGS_AS_ERRORS = YES // Whether to warn about 64-bit values being implicitly shortened to 32 bits GCC_WARN_64_TO_32_BIT_CONVERSION = YES // Whether to warn about fields missing from structure initializers (only if // designated initializers aren't used) GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES // Whether to warn about missing function prototypes GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO // Whether to warn about implicit conversions in the signedness of the type // a pointer is pointing to (e.g., 'int *' getting converted to 'unsigned int *') GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES // Whether to warn when the value returned from a function/method/block does not // match its return type GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR // Whether to warn on a class not implementing all the required methods of // a protocol it declares conformance to GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = YES // Whether to warn when switching on an enum value, and all possibilities are // not accounted for GCC_WARN_CHECK_SWITCH_STATEMENTS = YES // Whether to warn about the use of four-character constants GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES // Whether to warn about an aggregate data type's initializer not being fully // bracketed (e.g., array initializer syntax) GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES // Whether to warn about missing braces or parentheses that make the meaning of // the code ambiguous GCC_WARN_MISSING_PARENTHESES = YES // Whether to warn about unsafe comparisons between values of different // signedness GCC_WARN_SIGN_COMPARE = YES // Whether to warn about the arguments to printf-style functions not matching // the format specifiers GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES // Warn if a "@selector(...)" expression referring to an undeclared selector is found GCC_WARN_UNDECLARED_SELECTOR = YES // Warn if a variable might be clobbered by a setjmp call or if an automatic variable is used without prior initialization. GCC_WARN_UNINITIALIZED_AUTOS = YES // Whether to warn about static functions that are unused GCC_WARN_UNUSED_FUNCTION = YES // Whether to warn about labels that are unused GCC_WARN_UNUSED_LABEL = YES // Whether to warn about variables that are never used GCC_WARN_UNUSED_VARIABLE = YES // Whether to run the static analyzer with every build RUN_CLANG_STATIC_ANALYZER = YES // Don't treat unknown warnings as errors, and disable GCC compatibility warnings and unused static const variable warnings WARNING_CFLAGS = -Wno-error=unknown-warning-option -Wno-gcc-compat -Wno-unused-const-variable -Wno-nullability-completeness ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/Base/Configurations/Debug.xcconfig ================================================ // // This file defines the base configuration for a Debug build of any project. // This should be set at the project level for the Debug configuration. // #include "../Common.xcconfig" // Whether to strip debugging symbols when copying resources (like included // binaries) COPY_PHASE_STRIP = NO // The optimization level (0, 1, 2, 3, s) for the produced binary GCC_OPTIMIZATION_LEVEL = 0 // Preproccessor definitions to apply to each file compiled GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1 // Whether to enable link-time optimizations (such as inlining across translation // units) LLVM_LTO = NO // Whether to only build the active architecture ONLY_ACTIVE_ARCH = YES // Other compiler flags // // These settings catch some errors in integer arithmetic OTHER_CFLAGS = -ftrapv // Other flags to pass to the Swift compiler // // This enables conditional compilation with #if DEBUG OTHER_SWIFT_FLAGS = -D DEBUG // Whether to strip debugging symbols when copying the built product to its // final installation location STRIP_INSTALLED_PRODUCT = NO // The optimization level (-Onone, -O, -Ofast) for the produced Swift binary SWIFT_OPTIMIZATION_LEVEL = -Onone // Disable Developer ID timestamping OTHER_CODE_SIGN_FLAGS = --timestamp=none ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/Base/Configurations/Profile.xcconfig ================================================ // // This file defines the base configuration for an optional profiling-specific // build of any project. To use these settings, create a Profile configuration // in your project, and use this file at the project level for the new // configuration. // // based on the Release configuration, with some stuff related to debugging // symbols re-enabled #include "Release.xcconfig" // Whether to strip debugging symbols when copying resources (like included // binaries) COPY_PHASE_STRIP = NO // Whether to only build the active architecture ONLY_ACTIVE_ARCH = YES // Whether to strip debugging symbols when copying the built product to its // final installation location STRIP_INSTALLED_PRODUCT = NO // Whether to perform App Store validation checks VALIDATE_PRODUCT = NO // Disable Developer ID timestamping OTHER_CODE_SIGN_FLAGS = --timestamp=none ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/Base/Configurations/Release.xcconfig ================================================ // // This file defines the base configuration for a Release build of any project. // This should be set at the project level for the Release configuration. // #include "../Common.xcconfig" // Whether to strip debugging symbols when copying resources (like included // binaries) COPY_PHASE_STRIP = YES // The optimization level (0, 1, 2, 3, s) for the produced binary GCC_OPTIMIZATION_LEVEL = s // Preproccessor definitions to apply to each file compiled GCC_PREPROCESSOR_DEFINITIONS = NDEBUG=1 // Whether to enable link-time optimizations (such as inlining across translation // units) LLVM_LTO = NO // Whether to only build the active architecture ONLY_ACTIVE_ARCH = NO // Whether to strip debugging symbols when copying the built product to its // final installation location STRIP_INSTALLED_PRODUCT = YES // The optimization level (-Onone, -O, -Owholemodule) for the produced Swift binary SWIFT_OPTIMIZATION_LEVEL = -Owholemodule // Whether to perform App Store validation checks VALIDATE_PRODUCT = YES ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/Base/Configurations/Test.xcconfig ================================================ // // This file defines the base configuration for a Test build of any project. // This should be set at the project level for the Test configuration. // #include "Debug.xcconfig" // Sandboxed apps can't be unit tested since they can't load some random // external bundle. So we disable sandboxing for testing. CODE_SIGN_ENTITLEMENTS = ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/Base/Targets/Application.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for an application. Typically, you want to use a platform-specific variant // instead. // // Whether to strip out code that isn't called from anywhere DEAD_CODE_STRIPPING = NO // Sets the @rpath for the application such that it can include frameworks in // the application bundle (inside the "Frameworks" folder) LD_RUNPATH_SEARCH_PATHS = @executable_path/../Frameworks @loader_path/../Frameworks @executable_path/Frameworks ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/Base/Targets/Framework.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for a framework. Typically, you want to use a platform-specific variant // instead. // // Whether to strip out code that isn't called from anywhere DEAD_CODE_STRIPPING = NO // Whether this framework should define an LLVM module DEFINES_MODULE = YES // Whether function calls should be position-dependent (should always be // disabled for library code) GCC_DYNAMIC_NO_PIC = NO // Default frameworks to the name of the project, instead of any // platform-specific target PRODUCT_NAME = $(PROJECT_NAME) // Enables the framework to be included from any location as long as the // loader’s runpath search paths includes it. For example from an application // bundle (inside the "Frameworks" folder) or shared folder INSTALL_PATH = @rpath LD_DYLIB_INSTALL_NAME = @rpath/$(PRODUCT_NAME).$(WRAPPER_EXTENSION)/$(PRODUCT_NAME) SKIP_INSTALL = YES // Disallows use of APIs that are not available // to app extensions and linking to frameworks // that have not been built with this setting enabled. APPLICATION_EXTENSION_API_ONLY = YES ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/Base/Targets/StaticLibrary.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for a static library. Typically, you want to use a platform-specific variant // instead. // // Whether to strip out code that isn't called from anywhere DEAD_CODE_STRIPPING = NO // Whether to strip debugging symbols when copying resources (like included // binaries). // // Overrides Release.xcconfig when used at the target level. COPY_PHASE_STRIP = NO // Whether function calls should be position-dependent (should always be // disabled for library code) GCC_DYNAMIC_NO_PIC = NO // Copy headers to "include/LibraryName" in the build folder by default. This // lets consumers use #import syntax even for static // libraries PUBLIC_HEADERS_FOLDER_PATH = include/$PRODUCT_NAME // Don't include in an xcarchive SKIP_INSTALL = YES // Disallows use of APIs that are not available // to app extensions and linking to frameworks // that have not been built with this setting enabled. APPLICATION_EXTENSION_API_ONLY = YES ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/Mac OS X/Mac-Application.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for an application on Mac OS X. This should be set at the target level for // each project configuration. // // Import base application settings #include "../Base/Targets/Application.xcconfig" // Apply common settings specific to Mac OS X #include "Mac-Base.xcconfig" // Whether function calls should be position-dependent (should always be // disabled for library code) GCC_DYNAMIC_NO_PIC = YES ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/Mac OS X/Mac-Base.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for Mac OS X. This file is not standalone -- it is meant to be included into // a configuration file for a specific type of target. // // Whether to combine multiple image resolutions into a multirepresentational // TIFF COMBINE_HIDPI_IMAGES = YES // Where to find embedded frameworks LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../Frameworks @loader_path/../Frameworks // The base SDK to use (if no version is specified, the latest version is // assumed) SDKROOT = macosx // Supported build architectures VALID_ARCHS = x86_64 ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/Mac OS X/Mac-DynamicLibrary.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for a dynamic library on Mac OS X. This should be set at the target level // for each project configuration. // // Import common settings specific to Mac OS X #include "Mac-Base.xcconfig" // Whether to strip out code that isn't called from anywhere DEAD_CODE_STRIPPING = NO // Whether function calls should be position-dependent (should always be // disabled for library code) GCC_DYNAMIC_NO_PIC = NO // Don't include in an xcarchive SKIP_INSTALL = YES ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/Mac OS X/Mac-Framework.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for a framework on OS X. This should be set at the target level for each // project configuration. // // Import base framework settings #include "../Base/Targets/Framework.xcconfig" // Import common settings specific to Mac OS X #include "Mac-Base.xcconfig" ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/Mac OS X/Mac-StaticLibrary.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for a static library on Mac OS X. This should be set at the target level for // each project configuration. // // Import base static library settings #include "../Base/Targets/StaticLibrary.xcconfig" // Apply common settings specific to Mac OS X #include "Mac-Base.xcconfig" ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/README.md ================================================ This project intends to aggregate common or universal Xcode configuration settings, keeping them in hierarchial Xcode configuration files for easy modification and reuse. ## License This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. 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 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. For more information, please refer to [unlicense.org](http://unlicense.org). ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/iOS/iOS-Application.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for an application on iOS. This should be set at the target level for each // project configuration. // // Import base application settings #include "../Base/Targets/Application.xcconfig" // Apply common settings specific to iOS #include "iOS-Base.xcconfig" ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/iOS/iOS-Base.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for iOS. This file is not standalone -- it is meant to be included into // a configuration file for a specific type of target. // // Xcode needs this to find archived headers if SKIP_INSTALL is set HEADER_SEARCH_PATHS = $(OBJROOT)/UninstalledProducts/include // Where to find embedded frameworks LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks // The base SDK to use (if no version is specified, the latest version is // assumed) SDKROOT = iphoneos ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/iOS/iOS-Framework.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for a framework on iOS. This should be set at the target level for each // project configuration. // // Import base framework settings #include "../Base/Targets/Framework.xcconfig" // Import common settings specific to iOS #include "iOS-Base.xcconfig" ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/iOS/iOS-StaticLibrary.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for a static library on iOS. This should be set at the target level for each // project configuration. // // Import base static library settings #include "../Base/Targets/StaticLibrary.xcconfig" // Apply common settings specific to iOS #include "iOS-Base.xcconfig" // Supported device families (1 is iPhone, 2 is iPad) TARGETED_DEVICE_FAMILY = 1,2 ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/tvOS/tvOS-Application.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for an application on watchOS. This should be set at the target level for // each project configuration. // // Import base application settings #include "../Base/Targets/Application.xcconfig" // Apply common settings specific to watchOS #include "tvOS-Base.xcconfig" ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/tvOS/tvOS-Base.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for watchOS. This file is not standalone -- it is meant to be included into // a configuration file for a specific type of target. // // Where to find embedded frameworks LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks // The base SDK to use (if no version is specified, the latest version is // assumed) SDKROOT = appletvos ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/tvOS/tvOS-Framework.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for a framework on watchOS. This should be set at the target level for each // project configuration. // // Import base framework settings #include "../Base/Targets/Framework.xcconfig" // Import common settings specific to iOS #include "tvOS-Base.xcconfig" ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/tvOS/tvOS-StaticLibrary.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for a static library on watchOS. This should be set at the target level for // each project configuration. // // Import base static library settings #include "../Base/Targets/StaticLibrary.xcconfig" // Apply common settings specific to watchOS #include "tvOS-Base.xcconfig" // Supported device families TARGETED_DEVICE_FAMILY = 3 ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/watchOS/watchOS-Application.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for an application on watchOS. This should be set at the target level for // each project configuration. // // Import base application settings #include "../Base/Targets/Application.xcconfig" // Apply common settings specific to watchOS #include "watchOS-Base.xcconfig" ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/watchOS/watchOS-Base.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for watchOS. This file is not standalone -- it is meant to be included into // a configuration file for a specific type of target. // // Where to find embedded frameworks LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks // The base SDK to use (if no version is specified, the latest version is // assumed) SDKROOT = watchos ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/watchOS/watchOS-Framework.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for a framework on watchOS. This should be set at the target level for each // project configuration. // // Import base framework settings #include "../Base/Targets/Framework.xcconfig" // Import common settings specific to iOS #include "watchOS-Base.xcconfig" ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Carthage/Checkouts/xcconfigs/watchOS/watchOS-StaticLibrary.xcconfig ================================================ // // This file defines additional configuration options that are appropriate only // for a static library on watchOS. This should be set at the target level for // each project configuration. // // Import base static library settings #include "../Base/Targets/StaticLibrary.xcconfig" // Apply common settings specific to watchOS #include "watchOS-Base.xcconfig" // Supported device families TARGETED_DEVICE_FAMILY = 4 ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Documentation/BasicOperators.md ================================================ # Basic Operators This document explains some of the most common operators used in ReactiveCocoa, and includes examples demonstrating their use. Note that “operators”, in this context, refers to functions that transform [signals][] and [signal producers][], _not_ custom Swift operators. In other words, these are composable primitives provided by ReactiveCocoa for working with event streams. This document will use the term “event stream” when dealing with concepts that apply to both `Signal` and `SignalProducer`. When the distinction matters, the types will be referred to by name. **[Performing side effects with event streams](#performing-side-effects-with-event-streams)** 1. [Observation](#observation) 1. [Injecting effects](#injecting-effects) **[Operator composition](#operator-composition)** 1. [Lifting](#lifting) **[Transforming event streams](#transforming-event-streams)** 1. [Mapping](#mapping) 1. [Filtering](#filtering) 1. [Aggregating](#aggregating) **[Combining event streams](#combining-event-streams)** 1. [Combining latest values](#combining-latest-values) 1. [Zipping](#zipping) **[Flattening producers](#flattening-producers)** 1. [Concatenating](#concatenating) 1. [Merging](#merging) 1. [Switching to the latest](#switching-to-the-latest) **[Handling failures](#handling-failures)** 1. [Catching failures](#catch) 1. [Mapping errors](#mapping-errors) 1. [Retrying](#retrying) ## Performing side effects with event streams ### Observation `Signal`s can be observed with the `observe` function. It takes an `Observer` as argument to which any future events are sent. ```Swift signal.observe(Signal.Observer { event in switch event { case let .Next(next): print("Next: \(next)") case let .Failed(error): print("Failed: \(error)") case .Completed: print("Completed") case .Interrupted: print("Interrupted") } }) ``` Alternatively, callbacks for the `Next`, `Failed`, `Completed` and `Interrupted` events can be provided which will be called when a corresponding event occurs. ```Swift signal.observeNext { next in print("Next: \(next)") } signal.observeFailed { error in print("Failed: \(error)") } signal.observeCompleted { print("Completed") } signal.observeInterrupted { print("Interrupted") } ``` Note that it is not necessary to observe all four types of event - all of them are optional, you only need to provide callbacks for the events you care about. ### Injecting effects Side effects can be injected on a `SignalProducer` with the `on` operator without actually subscribing to it. ```Swift let producer = signalProducer .on(started: { print("Started") }, event: { event in print("Event: \(event)") }, failed: { error in print("Failed: \(error)") }, completed: { print("Completed") }, interrupted: { print("Interrupted") }, terminated: { print("Terminated") }, disposed: { print("Disposed") }, next: { value in print("Next: \(value)") }) ``` Similar to `observe`, all the parameters are optional and you only need to provide callbacks for the events you care about. Note that nothing will be printed until `producer` is started (possibly somewhere else). ## Operator composition ### Lifting `Signal` operators can be _lifted_ to operate upon `SignalProducer`s using the `lift` method. This will create a new `SignalProducer` which will apply the given operator to _every_ `Signal` created, just as if the operator had been applied to each produced `Signal` individually. ## Transforming event streams These operators transform an event stream into a new stream. ### Mapping The `map` operator is used to transform the values in a event stream, creating a new stream with the results. ```Swift let (signal, observer) = Signal.pipe() signal .map { string in string.uppercaseString } .observeNext { next in print(next) } observer.sendNext("a") // Prints A observer.sendNext("b") // Prints B observer.sendNext("c") // Prints C ``` [Interactive visualisation of the `map` operator.](http://neilpa.me/rac-marbles/#map) ### Filtering The `filter` operator is used to only include values in an event stream that satisfy a predicate. ```Swift let (signal, observer) = Signal.pipe() signal .filter { number in number % 2 == 0 } .observeNext { next in print(next) } observer.sendNext(1) // Not printed observer.sendNext(2) // Prints 2 observer.sendNext(3) // Not printed observer.sendNext(4) // prints 4 ``` [Interactive visualisation of the `filter` operator.](http://neilpa.me/rac-marbles/#filter) ### Aggregating The `reduce` operator is used to aggregate a event stream’s values into a single combined value. Note that the final value is only sent after the input stream completes. ```Swift let (signal, observer) = Signal.pipe() signal .reduce(1) { $0 * $1 } .observeNext { next in print(next) } observer.sendNext(1) // nothing printed observer.sendNext(2) // nothing printed observer.sendNext(3) // nothing printed observer.sendCompleted() // prints 6 ``` The `collect` operator is used to aggregate a event stream’s values into a single array value. Note that the final value is only sent after the input stream completes. ```Swift let (signal, observer) = Signal.pipe() signal .collect() .observeNext { next in print(next) } observer.sendNext(1) // nothing printed observer.sendNext(2) // nothing printed observer.sendNext(3) // nothing printed observer.sendCompleted() // prints [1, 2, 3] ``` [Interactive visualisation of the `reduce` operator.](http://neilpa.me/rac-marbles/#reduce) ## Combining event streams These operators combine values from multiple event streams into a new, unified stream. ### Combining latest values The `combineLatest` function combines the latest values of two (or more) event streams. The resulting stream will only send its first value after each input has sent at least one value. After that, new values on any of the inputs will result in a new value on the output. ```Swift let (numbersSignal, numbersObserver) = Signal.pipe() let (lettersSignal, lettersObserver) = Signal.pipe() let signal = combineLatest(numbersSignal, lettersSignal) signal.observeNext { next in print("Next: \(next)") } signal.observeCompleted { print("Completed") } numbersObserver.sendNext(0) // nothing printed numbersObserver.sendNext(1) // nothing printed lettersObserver.sendNext("A") // prints (1, A) numbersObserver.sendNext(2) // prints (2, A) numbersObserver.sendCompleted() // nothing printed lettersObserver.sendNext("B") // prints (2, B) lettersObserver.sendNext("C") // prints (2, C) lettersObserver.sendCompleted() // prints "Completed" ``` The `combineLatestWith` operator works in the same way, but as an operator. [Interactive visualisation of the `combineLatest` operator.](http://neilpa.me/rac-marbles/#combineLatest) ### Zipping The `zip` function joins values of two (or more) event streams pair-wise. The elements of any Nth tuple correspond to the Nth elements of the input streams. That means the Nth value of the output stream cannot be sent until each input has sent at least N values. ```Swift let (numbersSignal, numbersObserver) = Signal.pipe() let (lettersSignal, lettersObserver) = Signal.pipe() let signal = zip(numbersSignal, lettersSignal) signal.observeNext { next in print("Next: \(next)") } signal.observeCompleted { print("Completed") } numbersObserver.sendNext(0) // nothing printed numbersObserver.sendNext(1) // nothing printed lettersObserver.sendNext("A") // prints (0, A) numbersObserver.sendNext(2) // nothing printed numbersObserver.sendCompleted() // nothing printed lettersObserver.sendNext("B") // prints (1, B) lettersObserver.sendNext("C") // prints (2, C) & "Completed" ``` The `zipWith` operator works in the same way, but as an operator. [Interactive visualisation of the `zip` operator.](http://neilpa.me/rac-marbles/#zip) ## Flattening producers The `flatten` operator transforms a `SignalProducer`-of-`SignalProducer`s into a single `SignalProducer` whose values are forwarded from the inner producer in accordance with the provided `FlattenStrategy`. To understand, why there are different strategies and how they compare to each other, take a look at this example and imagine the column offsets as time: ```Swift let values = [ // imagine column offset as time [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8 ], ] let merge = [ 1, 4, 2, 7,5, 3,8,6 ] let concat = [ 1, 2, 3,4, 5, 6,7, 8] let latest = [ 1, 4, 7, 8 ] ``` Note, how the values interleave and which values are even included in the resulting array. ### Merging The `.Merge` strategy immediately forwards every value of the inner `SignalProducer`s to the outer `SignalProducer`. Any failure sent on the outer producer or any inner producer is immediately sent on the flattened producer and terminates it. ```Swift let (producerA, lettersObserver) = SignalProducer.buffer(5) let (producerB, numbersObserver) = SignalProducer.buffer(5) let (signal, observer) = SignalProducer, NoError>.buffer(5) signal.flatten(.Merge).startWithNext { next in print(next) } observer.sendNext(producerA) observer.sendNext(producerB) observer.sendCompleted() lettersObserver.sendNext("a") // prints "a" numbersObserver.sendNext("1") // prints "1" lettersObserver.sendNext("b") // prints "b" numbersObserver.sendNext("2") // prints "2" lettersObserver.sendNext("c") // prints "c" numbersObserver.sendNext("3") // prints "3" ``` [Interactive visualisation of the `flatten(.Merge)` operator.](http://neilpa.me/rac-marbles/#merge) ### Concatenating The `.Concat` strategy is used to serialize work of the inner `SignalProducer`s. The outer producer is started immediately. Each subsequent producer is not started until the preceeding one has completed. Failures are immediately forwarded to the flattened producer. ```Swift let (producerA, lettersObserver) = SignalProducer.buffer(5) let (producerB, numbersObserver) = SignalProducer.buffer(5) let (signal, observer) = SignalProducer, NoError>.buffer(5) signal.flatten(.Concat).startWithNext { next in print(next) } observer.sendNext(producerA) observer.sendNext(producerB) observer.sendCompleted() numbersObserver.sendNext("1") // nothing printed lettersObserver.sendNext("a") // prints "a" lettersObserver.sendNext("b") // prints "b" numbersObserver.sendNext("2") // nothing printed lettersObserver.sendNext("c") // prints "c" lettersObserver.sendCompleted() // prints "1", "2" numbersObserver.sendNext("3") // prints "3" numbersObserver.sendCompleted() ``` [Interactive visualisation of the `flatten(.Concat)` operator.](http://neilpa.me/rac-marbles/#concat) ### Switching to the latest The `.Latest` strategy forwards only values from the latest input `SignalProducer`. ```Swift let (producerA, observerA) = SignalProducer.buffer(5) let (producerB, observerB) = SignalProducer.buffer(5) let (producerC, observerC) = SignalProducer.buffer(5) let (signal, observer) = SignalProducer, NoError>.buffer(5) signal.flatten(.Latest).startWithNext { next in print(next) } observer.sendNext(producerA) // nothing printed observerC.sendNext("X") // nothing printed observerA.sendNext("a") // prints "a" observerB.sendNext("1") // nothing printed observer.sendNext(producerB) // prints "1" observerA.sendNext("b") // nothing printed observerB.sendNext("2") // prints "2" observerC.sendNext("Y") // nothing printed observerA.sendNext("c") // nothing printed observer.sendNext(producerC) // prints "X", "Y" observerB.sendNext("3") // nothing printed observerC.sendNext("Z") // prints "Z" ``` ## Handling failures These operators are used to handle failures that might occur on an event stream. ### Catching failures The `flatMapError` operator catches any failure that may occur on the input `SignalProducer`, then starts a new `SignalProducer` in its place. ```Swift let (producer, observer) = SignalProducer.buffer(5) let error = NSError(domain: "domain", code: 0, userInfo: nil) producer .flatMapError { _ in SignalProducer(value: "Default") } .startWithNext { next in print(next) } observer.sendNext("First") // prints "First" observer.sendNext("Second") // prints "Second" observer.sendFailed(error) // prints "Default" ``` ### Retrying The `retry` operator will restart the original `SignalProducer` on failure up to `count` times. ```Swift var tries = 0 let limit = 2 let error = NSError(domain: "domain", code: 0, userInfo: nil) let producer = SignalProducer { (observer, _) in if tries++ < limit { observer.sendFailed(error) } else { observer.sendNext("Success") observer.sendCompleted() } } producer .on(failed: {e in print("Failure")}) // prints "Failure" twice .retry(2) .start { event in switch event { case let .Next(next): print(next) // prints "Success" case let .Failed(error): print("Failed: \(error)") case .Completed: print("Completed") case .Interrupted: print("Interrupted") } } ``` If the `SignalProducer` does not succeed after `count` tries, the resulting `SignalProducer` will fail. E.g., if `retry(1)` is used in the example above instead of `retry(2)`, `"Signal Failure"` will be printed instead of `"Success"`. ### Mapping errors The `mapError` operator transforms the error of any failure in an event stream into a new error. ```Swift enum CustomError: String, ErrorType { case Foo = "Foo" case Bar = "Bar" case Other = "Other" var nsError: NSError { return NSError(domain: "CustomError.\(rawValue)", code: 0, userInfo: nil) } var description: String { return "\(rawValue) Error" } } let (signal, observer) = Signal.pipe() signal .mapError { (error: NSError) -> CustomError in switch error.domain { case "com.example.foo": return .Foo case "com.example.bar": return .Bar default: return .Other } } .observeFailed { error in print(error) } observer.sendFailed(NSError(domain: "com.example.foo", code: 42, userInfo: nil)) // prints "Foo Error" ``` ### Promote The `promoteErrors` operator promotes an event stream that does not generate failures into one that can. ```Swift let (numbersSignal, numbersObserver) = Signal.pipe() let (lettersSignal, lettersObserver) = Signal.pipe() numbersSignal .promoteErrors(NSError) .combineLatestWith(lettersSignal) ``` The given stream will still not _actually_ generate failures, but this is useful because some operators to [combine streams](#combining-event-streams) require the inputs to have matching error types. [Signals]: FrameworkOverview.md#signals [Signal Producers]: FrameworkOverview.md#signal-producers [Observation]: FrameworkOverview.md#observation ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Documentation/DebuggingTechniques.md ================================================ # Debugging Techniques This document lists debugging techniques and infrastructure helpful for debugging ReactiveCocoa applications. #### Unscrambling Swift compiler errors Type inferrence can be a source of hard-to-debug compiler errors. There are two potential places to be wrong when type inferrence used: 1. Definition of type inferred variable 2. Consumption of type inferred variable In both cases errors are related to incorrect assumptions about type. Such issues are common for ReactiveCocoa applications as it is all about operations over data and related types. The current state of the Swift compiler can cause misleading type errors, especially when error happens in the middle of a signal chain. Below is an example of type-error scenario: ``` SignalProducer(value:42) .on(next: { answer in return _ }) .startWithCompleted { print("Completed.") } ``` The code above will not compile with the following error on a `print` call `error: ambiguous reference to member 'print' print("Completed.")` To find the actual source of errors signal chains need to be broken apart. Add explicit definitions of closure types on each of the steps: ``` let initialProducer = SignalProducer.init(value:42) let sideEffectProducer = initialProducer.on(next: { (answer: Int) in return _ }) let disposable = sideEffectProducer.startWithCompleted { print("Completed.") } ``` The code above will not compile too, but with the error `error: cannot convert value of type '(_) -> _' to expected argument type '(Int -> ())?'` on definition of `on` closure. This gives enough of information to locate unexpected `return _` since `on` closure should not have any return value. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Documentation/DesignGuidelines.md ================================================ # Design Guidelines This document contains guidelines for projects that want to make use of ReactiveCocoa. The content here is heavily inspired by the [Rx Design Guidelines](http://blogs.msdn.com/b/rxteam/archive/2010/10/28/rx-design-guidelines.aspx). This document assumes basic familiarity with the features of ReactiveCocoa. The [Framework Overview][] is a better resource for getting up to speed on the main types and concepts provided by RAC. **[The `Event` contract](#the-event-contract)** 1. [`Next`s provide values or indicate the occurrence of events](#nexts-provide-values-or-indicate-the-occurrence-of-events) 1. [Failures behave like exceptions and propagate immediately](#failures-behave-like-exceptions-and-propagate-immediately) 1. [Completion indicates success](#completion-indicates-success) 1. [Interruption cancels outstanding work and usually propagates immediately](#interruption-cancels-outstanding-work-and-usually-propagates-immediately) 1. [Events are serial](#events-are-serial) 1. [Events cannot be sent recursively](#events-cannot-be-sent-recursively) 1. [Events are sent synchronously by default](#events-are-sent-synchronously-by-default) **[The `Signal` contract](#the-signal-contract)** 1. [Signals start work when instantiated](#signals-start-work-when-instantiated) 1. [Observing a signal does not have side effects](#observing-a-signal-does-not-have-side-effects) 1. [All observers of a signal see the same events in the same order](#all-observers-of-a-signal-see-the-same-events-in-the-same-order) 1. [A signal is retained until the underlying observer is released](#a-signal-is-retained-until-the-underlying-observer-is-released) 1. [Terminating events dispose of signal resources](#terminating-events-dispose-of-signal-resources) **[The `SignalProducer` contract](#the-signalproducer-contract)** 1. [Signal producers start work on demand by creating signals](#signal-producers-start-work-on-demand-by-creating-signals) 1. [Each produced signal may send different events at different times](#each-produced-signal-may-send-different-events-at-different-times) 1. [Signal operators can be lifted to apply to signal producers](#signal-operators-can-be-lifted-to-apply-to-signal-producers) 1. [Disposing of a produced signal will interrupt it](#disposing-of-a-produced-signal-will-interrupt-it) **[Best practices](#best-practices)** 1. [Process only as many values as needed](#process-only-as-many-values-as-needed) 1. [Observe events on a known scheduler](#observe-events-on-a-known-scheduler) 1. [Switch schedulers in as few places as possible](#switch-schedulers-in-as-few-places-as-possible) 1. [Capture side effects within signal producers](#capture-side-effects-within-signal-producers) 1. [Share the side effects of a signal producer by sharing one produced signal](#share-the-side-effects-of-a-signal-producer-by-sharing-one-produced-signal) 1. [Prefer managing lifetime with operators over explicit disposal](#prefer-managing-lifetime-with-operators-over-explicit-disposal) **[Implementing new operators](#implementing-new-operators)** 1. [Prefer writing operators that apply to both signals and producers](#prefer-writing-operators-that-apply-to-both-signals-and-producers) 1. [Compose existing operators when possible](#compose-existing-operators-when-possible) 1. [Forward failure and interruption events as soon as possible](#forward-failure-and-interruption-events-as-soon-as-possible) 1. [Switch over `Event` values](#switch-over-event-values) 1. [Avoid introducing concurrency](#avoid-introducing-concurrency) 1. [Avoid blocking in operators](#avoid-blocking-in-operators) ## The `Event` contract [Events][] are fundamental to ReactiveCocoa. [Signals][] and [signal producers][] both send events, and may be collectively called “event streams.” Event streams must conform to the following grammar: ``` Next* (Interrupted | Failed | Completed)? ``` This states that an event stream consists of: 1. Any number of `Next` events 1. Optionally followed by one terminating event, which is any of `Interrupted`, `Failed`, or `Completed` After a terminating event, no other events will be received. #### `Next`s provide values or indicate the occurrence of events `Next` events contain a payload known as the “value.” Only `Next` events are said to have a value. Since an event stream can contain any number of `Next`s, there are few restrictions on what those values can mean or be used for, except that they must be of the same type. As an example, the value might represent an element from a collection, or a progress update about some long-running operation. The value of a `Next` event might even represent nothing at all—for example, it’s common to use a value type of `()` to indicate that something happened, without being more specific about what that something was. Most of the event stream [operators][] act upon `Next` events, as they represent the “meaningful data” of a signal or producer. #### Failures behave like exceptions and propagate immediately `Failed` events indicate that something went wrong, and contain a concrete error that indicates what happened. Failures are fatal, and propagate as quickly as possible to the consumer for handling. Failures also behave like exceptions, in that they “skip” operators, terminating them along the way. In other words, most [operators][] immediately stop doing work when a failure is received, and then propagate the failure onward. This even applies to time-shifted operators, like [`delay`][delay]—which, despite its name, will forward any failures immediately. Consequently, failures should only be used to represent “abnormal” termination. If it is important to let operators (or consumers) finish their work, a `Next` event describing the result might be more appropriate. If an event stream can _never_ fail, it should be parameterized with the special [`NoError`][NoError] type, which statically guarantees that a `Failed` event cannot be sent upon the stream. #### Completion indicates success An event stream sends `Completed` when the operation has completed successfully, or to indicate that the stream has terminated normally. Many operators manipulate the `Completed` event to shorten or extend the lifetime of an event stream. For example, [`take`][take] will complete after the specified number of values have been received, thereby terminating the stream early. On the other hand, most operators that accept multiple signals or producers will wait until _all_ of them have completed before forwarding a `Completed` event, since a successful outcome will usually depend on all the inputs. #### Interruption cancels outstanding work and usually propagates immediately An `Interrupted` event is sent when an event stream should cancel processing. Interruption is somewhere between [success](#completion-indicates-success) and [failure](#failures-behave-like-exceptions-and-propagate-immediately)—the operation was not successful, because it did not get to finish, but it didn’t necessarily “fail” either. Most [operators][] will propagate interruption immediately, but there are some exceptions. For example, the [flattening operators][flatten] will ignore `Interrupted` events that occur on the _inner_ producers, since the cancellation of an inner operation should not necessarily cancel the larger unit of work. RAC will automatically send an `Interrupted` event upon [disposal][Disposables], but it can also be sent manually if necessary. Additionally, [custom operators](#implementing-new-operators) must make sure to forward interruption events to the observer. #### Events are serial RAC guarantees that all events upon a stream will arrive serially. In other words, it’s impossible for the observer of a signal or producer to receive multiple `Event`s concurrently, even if the events are sent on multiple threads simultaneously. This simplifies [operator][Operators] implementations and [observers][]. #### Events cannot be sent recursively Just like RAC guarantees that [events will not be received concurrently](#events-are-serial), it also guarantees that they won’t be received recursively. As a consequence, [operators][] and [observers][] _do not_ need to be reentrant. If an event is sent upon a signal from a thread that is _already processing_ a previous event from that signal, deadlock will result. This is because recursive signals are usually programmer error, and the determinacy of a deadlock is preferable to nondeterministic race conditions. When a recursive signal is explicitly desired, the recursive event should be time-shifted, with an operator like [`delay`][delay], to ensure that it isn’t sent from an already-running event handler. #### Events are sent synchronously by default RAC does not implicitly introduce concurrency or asynchrony. [Operators][] that accept a [scheduler][Schedulers] may, but they must be explicitly invoked by the consumer of the framework. A “vanilla” signal or producer will send all of its events synchronously by default, meaning that the [observer][Observers] will be synchronously invoked for each event as it is sent, and that the underlying work will not resume until the event handler finishes. This is similar to how `NSNotificationCenter` or `UIControl` events are distributed. ## The `Signal` contract A [signal][Signals] is an “always on” stream that obeys [the `Event` contract](#the-event-contract). `Signal` is a reference type, because each signal has identity—in other words, each signal has its own lifetime, and may eventually terminate. Once terminated, a signal cannot be restarted. #### Signals start work when instantiated [`Signal.init`][Signal.init] immediately executes the generator closure that is passed to it. This means that side effects may occur even before the initializer returns. It is also possible to send [events][] before the initializer returns. However, since it is impossible for any [observers][] to be attached at this point, any events sent this way cannot be received. #### Observing a signal does not have side effects The work associated with a `Signal` does not start or stop when [observers][] are added or removed, so the [`observe`][observe] method (or the cancellation thereof) never has side effects. A signal’s side effects can only be stopped through [a terminating event](#signals-are-retained-until-a-terminating-event-occurs). #### All observers of a signal see the same events in the same order Because [observation does not have side effects](#observing-a-signal-does-not-have-side-effects), a `Signal` never customizes events for different [observers][]. When an event is sent upon a signal, it will be [synchronously](#events-are-sent-synchronously-by-default) distributed to all observers that are attached at that time, much like how `NSNotificationCenter` sends notifications. In other words, there are not different event “timelines” per observer. All observers effectively see the same stream of events. There is one exception to this rule: adding an observer to a signal _after_ it has already terminated will result in exactly one [`Interrupted`](#interruption-cancels-outstanding-work-and-usually-propagates-immediately) event sent to that specific observer. #### A signal is retained until the underlying observer is released Even if the caller does not maintain a reference to the `Signal`: - A signal created with [`Signal.init`][Signal.init] is kept alive until the generator closure releases the [observer][Observers] argument. - A signal created with [`Signal.pipe`][Signal.pipe] is kept alive until the returned observer is released. This ensures that signals associated with long-running work do not deallocate prematurely. Note that it is possible to release a signal before a terminating [event][Events] has been sent upon it. This should usually be avoided, as it can result in resource leaks, but is sometimes useful to disable termination. #### Terminating events dispose of signal resources When a terminating [event][Events] is sent along a `Signal`, all [observers][] will be released, and any resources being used to generate events should be disposed of. The easiest way to ensure proper resource cleanup is to return a [disposable][Disposables] from the generator closure, which will be disposed of when termination occurs. The disposable should be responsible for releasing memory, closing file handles, canceling network requests, or anything else that may have been associated with the work being performed. ## The `SignalProducer` contract A [signal producer][Signal Producers] is like a “recipe” for creating [signals][]. Signal producers do not do anything by themselves—[work begins only when a signal is produced](#signal-producers-start-work-on-demand-by-creating-signals). Since a signal producer is just a declaration of _how_ to create signals, it is a value type, and has no memory management to speak of. #### Signal producers start work on demand by creating signals The [`start`][start] and [`startWithSignal`][startWithSignal] methods each produce a `Signal` (implicitly and explicitly, respectively). After instantiating the signal, the closure that was passed to [`SignalProducer.init`][SignalProducer.init] will be executed, to start the flow of [events][] after any observers have been attached. Although the producer itself is not _really_ responsible for the execution of work, it’s common to speak of “starting” and “canceling” a producer. These terms refer to producing a `Signal` that will start work, and [disposing of that signal](#disposing-of-a-produced-signal-will-interrupt-it) to stop work. A producer can be started any number of times (including zero), and the work associated with it will execute exactly that many times as well. #### Each produced signal may send different events at different times Because signal producers [start work on demand](#signal-producers-start-work-on-demand-by-creating-signals), there may be different [observers][] associated with each execution, and those observers may see completely different [event][Events] timelines. In other words, events are generated from scratch for each time the producer is started, and can be completely different (or in a completely different order) from other times the producer is started. Nonetheless, each execution of a signal producer will follow [the `Event` contract](#the-event-contract). #### Signal operators can be lifted to apply to signal producers Due to the relationship between signals and signal producers, it is possible to automatically promote any [operators][] over one or more `Signal`s to apply to the same number of `SignalProducer`s instead, using the [`lift`][lift] method. `lift` will apply the behavior of the specified operator to each `Signal` that is [created when the signal producer is started](#signal-producers-start-work-on-demand-by-creating-signals). #### Disposing of a produced signal will interrupt it When a producer is started using the [`start`][start] or [`startWithSignal`][startWithSignal] methods, a [`Disposable`][Disposables] is automatically created and passed back. Disposing of this object will [interrupt](#interruption-cancels-outstanding-work-and-usually-propagates-immediately) the produced `Signal`, thereby canceling outstanding work and sending an `Interrupted` [event][Events] to all [observers][], and will also dispose of everything added to the [`CompositeDisposable`][CompositeDisposable] in [SignalProducer.init]. Note that disposing of one produced `Signal` will not affect other signals created by the same `SignalProducer`. ## Best practices The following recommendations are intended to help keep RAC-based code predictable, understandable, and performant. They are, however, only guidelines. Use best judgement when determining whether to apply the recommendations here to a given piece of code. #### Process only as many values as needed Keeping an event stream alive longer than necessary can waste CPU and memory, as unnecessary work is performed for results that will never be used. If only a certain number of values or certain number of time is required from a [signal][Signals] or [producer][Signal Producers], operators like [`take`][take] or [`takeUntil`][takeUntil] can be used to automatically complete the stream once a certain condition is fulfilled. The benefit is exponential, too, as this will terminate dependent operators sooner, potentially saving a significant amount of work. #### Observe events on a known scheduler When receiving a [signal][Signals] or [producer][Signal Producers] from unknown code, it can be difficult to know which thread [events][] will arrive upon. Although events are [guaranteed to be serial](#events-are-serial), sometimes stronger guarantees are needed, like when performing UI updates (which must occur on the main thread). Whenever such a guarantee is important, the [`observeOn`][observeOn] [operator][Operators] should be used to force events to be received upon a specific [scheduler][Schedulers]. #### Switch schedulers in as few places as possible Notwithstanding the [above](#observe-events-on-a-known-scheduler), [events][] should only be delivered to a specific [scheduler][Schedulers] when absolutely necessary. Switching schedulers can introduce unnecessary delays and cause an increase in CPU load. Generally, [`observeOn`][observeOn] should only be used right before observing the [signal][Signals], starting the [producer][Signal Producers], or binding to a [property][Properties]. This ensures that events arrive on the expected scheduler, without introducing multiple thread hops before their arrival. #### Capture side effects within signal producers Because [signal producers start work on demand](#signal-producers-start-work-on-demand-by-creating-signals), any functions or methods that return a [signal producer][Signal Producers] should make sure that side effects are captured _within_ the producer itself, instead of being part of the function or method call. For example, a function like this: ```swift func search(text: String) -> SignalProducer ``` … should _not_ immediately start a search. Instead, the returned producer should execute the search once for every time that it is started. This also means that if the producer is never started, a search will never have to be performed either. #### Share the side effects of a signal producer by sharing one produced signal If multiple [observers][] are interested in the results of a [signal producer][Signal Producers], calling [`start`][start] once for each observer means that the work associated with the producer will [execute that many times](#signal-producers-start-work-on-demand-by-creating-signals) and [may not generate the same results](#each-produced-signal-may-send-different-events-at-different-times). If: 1. the observers need to receive the exact same results 1. the observers know about each other, or 1. the code starting the producer knows about each observer … it may be more appropriate to start the producer _just once_, and share the results of that one [signal][Signals] to all observers, by attaching them within the closure passed to the [`startWithSignal`][startWithSignal] method. #### Prefer managing lifetime with operators over explicit disposal Although the [disposable][Disposables] returned from [`start`][start] makes canceling a [signal producer][Signal Producers] really easy, explicit use of disposables can quickly lead to a rat's nest of resource management and cleanup code. There are almost always higher-level [operators][] that can be used instead of manual disposal: * [`take`][take] can be used to automatically terminate a stream once a certain number of values have been received. * [`takeUntil`][takeUntil] can be used to automatically terminate a [signal][Signals] or producer when an event occurs (for example, when a “Cancel” button is pressed in the UI). * [Properties][] and the `<~` operator can be used to “bind” the result of a signal or producer, until termination or until the property is deallocated. This can replace a manual observation that sets a value somewhere. ## Implementing new operators RAC provides a long list of built-in [operators][] that should cover most use cases; however, RAC is not a closed system. It's entirely valid to implement additional operators for specialized uses, or for consideration in ReactiveCocoa itself. Implementing a new operator requires a careful attention to detail and a focus on simplicity, to avoid introducing bugs into the calling code. These guidelines cover some of the common pitfalls and help preserve the expected API contracts. It may also help to look at the implementations of existing `Signal` and `SignalProducer` operators for reference points. #### Prefer writing operators that apply to both signals and producers Since any [signal operator can apply to signal producers](#signal-operators-can-be-lifted-to-apply-to-signal-producers), writing custom operators in terms of [`Signal`][Signals] means that [`SignalProducer`][Signal Producers] will get it “for free.” Even if the caller only needs to apply the new operator to signal producers at first, this generality can save time and effort in the future. Of course, some capabilities _require_ producers (for example, any retrying or repeating), so it may not always be possible to write a signal-based version instead. #### Compose existing operators when possible Considerable thought has been put into the operators provided by RAC, and they have been validated through automated tests and through their real world use in other projects. An operator that has been written from scratch may not be as robust, or might not handle a special case that the built-in operators are aware of. To minimize duplication and possible bugs, use the provided operators as much as possible in a custom operator implementation. Generally, there should be very little code written from scratch. #### Forward failure and interruption events as soon as possible Unless an operator is specifically built to handle [failures](#failures-behave-like-exceptions-and-propagate-immediately) and [interruption](#interruption-cancels-outstanding-work-and-usually-propagates-immedaitely) in a custom way, it should propagate those events to the observer as soon as possible, to ensure that their semantics are honored. #### Switch over `Event` values Instead of using [`start(failed:completed:interrupted:next:)`][start] or [`observe(failed:completed:interrupted:next:)`][observe], create your own [observer][Observers] to process raw [`Event`][Events] values, and use a `switch` statement to determine the event type. For example: ```swift producer.start { event in switch event { case let .Next(value): println("Next event: \(value)") case let .Failed(error): println("Failed event: \(error)") case .Completed: println("Completed event") case .Interrupted: println("Interrupted event") } } ``` Since the compiler will generate a warning if the `switch` is missing any case, this prevents mistakes in a custom operator’s event handling. #### Avoid introducing concurrency Concurrency is an extremely common source of bugs in programming. To minimize the potential for deadlocks and race conditions, operators should not concurrently perform their work. Callers always have the ability to [observe events on a specific scheduler](#observe-events-on-a-known-scheduler), and RAC offers built-in ways to parallelize work, so custom operators don’t need to be concerned with it. #### Avoid blocking in operators Signal or producer operators should return a new signal or producer (respectively) as quickly as possible. Any work that the operator needs to perform should be part of the event handling logic, _not_ part of the operator invocation itself. This guideline can be safely ignored when the purpose of an operator is to synchronously retrieve one or more values from a stream, like `single()` or `wait()`. [CompositeDisposable]: ../ReactiveCocoa/Swift/Disposable.swift [Disposables]: FrameworkOverview.md#disposables [Events]: FrameworkOverview.md#events [Framework Overview]: FrameworkOverview.md [NoError]: ../ReactiveCocoa/Swift/Errors.swift [Observers]: FrameworkOverview.md#observers [Operators]: BasicOperators.md [Properties]: FrameworkOverview.md#properties [Schedulers]: FrameworkOverview.md#schedulers [Signal Producers]: FrameworkOverview.md#signal-producers [Signal.init]: ../ReactiveCocoa/Swift/Signal.swift [Signal.pipe]: ../ReactiveCocoa/Swift/Signal.swift [SignalProducer.init]: ../ReactiveCocoa/Swift/SignalProducer.swift [Signals]: FrameworkOverview.md#signals [delay]: ../ReactiveCocoa/Swift/Signal.swift [flatten]: BasicOperators.md#flattening-producers [lift]: ../ReactiveCocoa/Swift/SignalProducer.swift [observe]: ../ReactiveCocoa/Swift/Signal.swift [observeOn]: ../ReactiveCocoa/Swift/Signal.swift [start]: ../ReactiveCocoa/Swift/SignalProducer.swift [startWithSignal]: ../ReactiveCocoa/Swift/SignalProducer.swift [take]: ../ReactiveCocoa/Swift/Signal.swift [takeUntil]: ../ReactiveCocoa/Swift/Signal.swift ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Documentation/FrameworkOverview.md ================================================ # Framework Overview This document contains a high-level description of the different components within the ReactiveCocoa framework, and an attempt to explain how they work together and divide responsibilities. This is meant to be a starting point for learning about new modules and finding more specific documentation. For examples and help understanding how to use RAC, see the [README][] or the [Design Guidelines][]. ## Events An **event**, represented by the [`Event`][Event] type, is the formalized representation of the fact that _something has happened_. In ReactiveCocoa, events are the centerpiece of communication. An event might represent the press of a button, a piece of information received from an API, the occurrence of an error, or the completion of a long-running operation. In any case, something generates the events and sends them over a [signal](#signals) to any number of [observers](#observers). `Event` is an enumerated type representing either a value or one of three terminal events: * The `Next` event provides a new value from the source. * The `Failed` event indicates that an error occurred before the signal could finish. Events are parameterized by an `ErrorType`, which determines the kind of failure that’s permitted to appear in the event. If a failure is not permitted, the event can use type `NoError` to prevent any from being provided. * The `Completed` event indicates that the signal finished successfully, and that no more values will be sent by the source. * The `Interrupted` event indicates that the signal has terminated due to cancellation, meaning that the operation was neither successful nor unsuccessful. ## Signals A **signal**, represented by the [`Signal`][Signal] type, is any series of [events](#events) over time that can be observed. Signals are generally used to represent event streams that are already “in progress”, like notifications, user input, etc. As work is performed or data is received, events are _sent_ on the signal, which pushes them out to any observers. All observers see the events at the same time. Users must [observe](#observers) a signal in order to access its events. Observing a signal does not trigger any side effects. In other words, signals are entirely producer-driven and push-based, and consumers (observers) cannot have any effect on their lifetime. While observing a signal, the user can only evaluate the events in the same order as they are sent on the signal. There is no random access to values of a signal. Signals can be manipulated by applying [primitives][BasicOperators] to them. Typical primitives to manipulate a single signal like `filter`, `map` and `reduce` are available, as well as primitives to manipulate multiple signals at once (`zip`). Primitives operate only on the `Next` events of a signal. The lifetime of a signal consists of any number of `Next` events, followed by one terminating event, which may be any one of `Failed`, `Completed`, or `Interrupted` (but not a combination). Terminating events are not included in the signal’s values—they must be handled specially. ### Pipes A **pipe**, created by `Signal.pipe()`, is a [signal](#signals) that can be manually controlled. The method returns a [signal](#signals) and an [observer](#observers). The signal can be controlled by sending events to the observer. This can be extremely useful for bridging non-RAC code into the world of signals. For example, instead of handling application logic in block callbacks, the blocks can simply send events to the observer. Meanwhile, the signal can be returned, hiding the implementation detail of the callbacks. ## Signal Producers A **signal producer**, represented by the [`SignalProducer`][SignalProducer] type, creates [signals](#signals) and performs side effects. They can be used to represent operations or tasks, like network requests, where each invocation of `start()` will create a new underlying operation, and allow the caller to observe the result(s). The `startWithSignal()` variant gives access to the produced signal, allowing it to be observed multiple times if desired. Because of the behavior of `start()`, each signal created from the same producer may see a different ordering or version of events, or the stream might even be completely different! Unlike a plain signal, no work is started (and thus no events are generated) until an observer is attached, and the work is restarted anew for each additional observer. Starting a signal producer returns a [disposable](#disposables) that can be used to interrupt/cancel the work associated with the produced signal. Just like signals, signal producers can also be manipulated via primitives like `map`, `filter`, etc. Every signal primitive can be “lifted” to operate upon signal producers instead, using the `lift` method. Furthermore, there are additional primitives that control _when_ and _how_ work is started—for example, `times`. ### Buffers A **buffer**, created by `SignalProducer.buffer()`, is a (optionally bounded) queue for [events](#events) that replays those events when new [signals](#signals) are created from the producer. Similar to a [pipe](#pipes), the method returns an [observer](#observers). Events sent to this observer will be added to the queue. If the buffer is already at capacity when a new value arrives, the earliest (oldest) value will be dropped to make room for it. ## Observers An **observer** is anything that is waiting or capable of waiting for [events](#events) from a [signal](#signals). Within RAC, an observer is represented as an [`Observer`][Observer] that accepts [`Event`][Event] values. Observers can be implicitly created by using the callback-based versions of the `Signal.observe` or `SignalProducer.start` methods. ## Actions An **action**, represented by the [`Action`][Action] type, will do some work when executed with an input. While executing, zero or more output values and/or a failure may be generated. Actions are useful for performing side-effecting work upon user interaction, like when a button is clicked. Actions can also be automatically disabled based on a [property](#properties), and this disabled state can be represented in a UI by disabling any controls associated with the action. For interaction with `NSControl` or `UIControl`, RAC provides the [`CocoaAction`][CocoaAction] type for bridging actions to Objective-C. ## Properties A **property**, represented by the [`PropertyType`][Property] protocol, stores a value and notifies observers about future changes to that value. The current value of a property can be obtained from the `value` getter. The `producer` getter returns a [signal producer](#signal-producers) that will send the property’s current value, followed by all changes over time. The `<~` operator can be used to bind properties in different ways. Note that in all cases, the target has to be a [`MutablePropertyType`][Property]. * `property <~ signal` binds a [signal](#signals) to the property, updating the property’s value to the latest value sent by the signal. * `property <~ producer` starts the given [signal producer](#signal-producers), and binds the property’s value to the latest value sent on the started signal. * `property <~ otherProperty` binds one property to another, so that the destination property’s value is updated whenever the source property is updated. The [`DynamicProperty`][Property] type can be used to bridge to Objective-C APIs that require Key-Value Coding (KVC) or Key-Value Observing (KVO), like `NSOperation`. Note that most AppKit and UIKit properties do _not_ support KVO, so their changes should be observed through other mechanisms. [`MutableProperty`][Property] should be preferred over dynamic properties whenever possible! ## Disposables A **disposable**, represented by the [`Disposable`][Disposable] protocol, is a mechanism for memory management and cancellation. When starting a [signal producer](#signal-producers), a disposable will be returned. This disposable can be used by the caller to cancel the work that has been started (e.g. background processing, network requests, etc.), clean up all temporary resources, then send a final `Interrupted` event upon the particular [signal](#signals) that was created. Observing a [signal](#signals) may also return a disposable. Disposing it will prevent the observer from receiving any future events from that signal, but it will not have any effect on the signal itself. For more information about cancellation, see the RAC [Design Guidelines][]. ## Schedulers A **scheduler**, represented by the [`SchedulerType`][Scheduler] protocol, is a serial execution queue to perform work or deliver results upon. [Signals](#signals) and [signal producers](#signal-producers) can be ordered to deliver events on a specific scheduler. [Signal producers](#signal-producers) can additionally be ordered to start their work on a specific scheduler. Schedulers are similar to Grand Central Dispatch queues, but schedulers support cancellation (via [disposables](#disposables)), and always execute serially. With the exception of the [`ImmediateScheduler`][Scheduler], schedulers do not offer synchronous execution. This helps avoid deadlocks, and encourages the use of [signal and signal producer primitives][BasicOperators] instead of blocking work. Schedulers are also somewhat similar to `NSOperationQueue`, but schedulers do not allow tasks to be reordered or depend on one another. [Design Guidelines]: DesignGuidelines.md [BasicOperators]: BasicOperators.md [README]: ../README.md [Signal]: ../ReactiveCocoa/Swift/Signal.swift [SignalProducer]: ../ReactiveCocoa/Swift/SignalProducer.swift [Action]: ../ReactiveCocoa/Swift/Action.swift [CocoaAction]: ../ReactiveCocoa/Swift/Action.swift [Disposable]: ../ReactiveCocoa/Swift/Disposable.swift [Scheduler]: ../ReactiveCocoa/Swift/Scheduler.swift [Property]: ../ReactiveCocoa/Swift/Property.swift [Event]: ../ReactiveCocoa/Swift/Event.swift [Observer]: ../ReactiveCocoa/Swift/Observer.swift ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Documentation/Legacy/BasicOperators.md ================================================ # Basic Operators This document explains some of the most common operators used in ReactiveCocoa, and includes examples demonstrating their use. Operators that apply to [sequences][Sequences] _and_ [signals][Signals] are known as [stream][Streams] operators. **[Performing side effects with signals](#performing-side-effects-with-signals)** 1. [Subscription](#subscription) 1. [Injecting effects](#injecting-effects) **[Transforming streams](#transforming-streams)** 1. [Mapping](#mapping) 1. [Filtering](#filtering) **[Combining streams](#combining-streams)** 1. [Concatenating](#concatenating) 1. [Flattening](#flattening) 1. [Mapping and flattening](#mapping-and-flattening) **[Combining signals](#combining-signals)** 1. [Sequencing](#sequencing) 1. [Merging](#merging) 1. [Combining latest values](#combining-latest-values) 1. [Switching](#switching) ## Performing side effects with signals Most signals start out "cold," which means that they will not do any work until [subscription](#subscription). Upon subscription, a signal or its [subscribers][Subscription] can perform _side effects_, like logging to the console, making a network request, updating the user interface, etc. Side effects can also be [injected](#injecting-effects) into a signal, where they won't be performed immediately, but will instead take effect with each subscription later. ### Subscription The [-subscribe…][RACSignal] methods give you access to the current and future values in a signal: ```objc RACSignal *letters = [@"A B C D E F G H I" componentsSeparatedByString:@" "].rac_sequence.signal; // Outputs: A B C D E F G H I [letters subscribeNext:^(NSString *x) { NSLog(@"%@", x); }]; ``` For a cold signal, side effects will be performed once _per subscription_: ```objc __block unsigned subscriptions = 0; RACSignal *loggingSignal = [RACSignal createSignal:^ RACDisposable * (id subscriber) { subscriptions++; [subscriber sendCompleted]; return nil; }]; // Outputs: // subscription 1 [loggingSignal subscribeCompleted:^{ NSLog(@"subscription %u", subscriptions); }]; // Outputs: // subscription 2 [loggingSignal subscribeCompleted:^{ NSLog(@"subscription %u", subscriptions); }]; ``` This behavior can be changed using a [connection][Connections]. ### Injecting effects The [-do…][RACSignal+Operations] methods add side effects to a signal without actually subscribing to it: ```objc __block unsigned subscriptions = 0; RACSignal *loggingSignal = [RACSignal createSignal:^ RACDisposable * (id subscriber) { subscriptions++; [subscriber sendCompleted]; return nil; }]; // Does not output anything yet loggingSignal = [loggingSignal doCompleted:^{ NSLog(@"about to complete subscription %u", subscriptions); }]; // Outputs: // about to complete subscription 1 // subscription 1 [loggingSignal subscribeCompleted:^{ NSLog(@"subscription %u", subscriptions); }]; ``` ## Transforming streams These operators transform a single stream into a new stream. ### Mapping The [-map:][RACStream] method is used to transform the values in a stream, and create a new stream with the results: ```objc RACSequence *letters = [@"A B C D E F G H I" componentsSeparatedByString:@" "].rac_sequence; // Contains: AA BB CC DD EE FF GG HH II RACSequence *mapped = [letters map:^(NSString *value) { return [value stringByAppendingString:value]; }]; ``` ### Filtering The [-filter:][RACStream] method uses a block to test each value, including it into the resulting stream only if the test passes: ```objc RACSequence *numbers = [@"1 2 3 4 5 6 7 8 9" componentsSeparatedByString:@" "].rac_sequence; // Contains: 2 4 6 8 RACSequence *filtered = [numbers filter:^ BOOL (NSString *value) { return (value.intValue % 2) == 0; }]; ``` ## Combining streams These operators combine multiple streams into a single new stream. ### Concatenating The [-concat:][RACStream] method appends one stream's values to another: ```objc RACSequence *letters = [@"A B C D E F G H I" componentsSeparatedByString:@" "].rac_sequence; RACSequence *numbers = [@"1 2 3 4 5 6 7 8 9" componentsSeparatedByString:@" "].rac_sequence; // Contains: A B C D E F G H I 1 2 3 4 5 6 7 8 9 RACSequence *concatenated = [letters concat:numbers]; ``` ### Flattening The [-flatten][RACStream] operator is applied to a stream-of-streams, and combines their values into a single new stream. Sequences are [concatenated](#concatenating): ```objc RACSequence *letters = [@"A B C D E F G H I" componentsSeparatedByString:@" "].rac_sequence; RACSequence *numbers = [@"1 2 3 4 5 6 7 8 9" componentsSeparatedByString:@" "].rac_sequence; RACSequence *sequenceOfSequences = @[ letters, numbers ].rac_sequence; // Contains: A B C D E F G H I 1 2 3 4 5 6 7 8 9 RACSequence *flattened = [sequenceOfSequences flatten]; ``` Signals are [merged](#merging): ```objc RACSubject *letters = [RACSubject subject]; RACSubject *numbers = [RACSubject subject]; RACSignal *signalOfSignals = [RACSignal createSignal:^ RACDisposable * (id subscriber) { [subscriber sendNext:letters]; [subscriber sendNext:numbers]; [subscriber sendCompleted]; return nil; }]; RACSignal *flattened = [signalOfSignals flatten]; // Outputs: A 1 B C 2 [flattened subscribeNext:^(NSString *x) { NSLog(@"%@", x); }]; [letters sendNext:@"A"]; [numbers sendNext:@"1"]; [letters sendNext:@"B"]; [letters sendNext:@"C"]; [numbers sendNext:@"2"]; ``` ### Mapping and flattening [Flattening](#flattening) isn't that interesting on its own, but understanding how it works is important for [-flattenMap:][RACStream]. `-flattenMap:` is used to transform each of a stream's values into _a new stream_. Then, all of the streams returned will be flattened down into a single stream. In other words, it's [-map:](#mapping) followed by [-flatten](#flattening). This can be used to extend or edit sequences: ```objc RACSequence *numbers = [@"1 2 3 4 5 6 7 8 9" componentsSeparatedByString:@" "].rac_sequence; // Contains: 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 RACSequence *extended = [numbers flattenMap:^(NSString *num) { return @[ num, num ].rac_sequence; }]; // Contains: 1_ 3_ 5_ 7_ 9_ RACSequence *edited = [numbers flattenMap:^(NSString *num) { if (num.intValue % 2 == 0) { return [RACSequence empty]; } else { NSString *newNum = [num stringByAppendingString:@"_"]; return [RACSequence return:newNum]; } }]; ``` Or create multiple signals of work which are automatically recombined: ```objc RACSignal *letters = [@"A B C D E F G H I" componentsSeparatedByString:@" "].rac_sequence.signal; [[letters flattenMap:^(NSString *letter) { return [database saveEntriesForLetter:letter]; }] subscribeCompleted:^{ NSLog(@"All database entries saved successfully."); }]; ``` ## Combining signals These operators combine multiple signals into a single new [RACSignal][]. ### Sequencing [-then:][RACSignal+Operations] starts the original signal, waits for it to complete, and then only forwards the values from a new signal: ```objc RACSignal *letters = [@"A B C D E F G H I" componentsSeparatedByString:@" "].rac_sequence.signal; // The new signal only contains: 1 2 3 4 5 6 7 8 9 // // But when subscribed to, it also outputs: A B C D E F G H I RACSignal *sequenced = [[letters doNext:^(NSString *letter) { NSLog(@"%@", letter); }] then:^{ return [@"1 2 3 4 5 6 7 8 9" componentsSeparatedByString:@" "].rac_sequence.signal; }]; ``` This is most useful for executing all the side effects of one signal, then starting another, and only returning the second signal's values. ### Merging The [+merge:][RACSignal+Operations] method will forward the values from many signals into a single stream, as soon as those values arrive: ```objc RACSubject *letters = [RACSubject subject]; RACSubject *numbers = [RACSubject subject]; RACSignal *merged = [RACSignal merge:@[ letters, numbers ]]; // Outputs: A 1 B C 2 [merged subscribeNext:^(NSString *x) { NSLog(@"%@", x); }]; [letters sendNext:@"A"]; [numbers sendNext:@"1"]; [letters sendNext:@"B"]; [letters sendNext:@"C"]; [numbers sendNext:@"2"]; ``` ### Combining latest values The [+combineLatest:][RACSignal+Operations] and `+combineLatest:reduce:` methods will watch multiple signals for changes, and then send the latest values from _all_ of them when a change occurs: ```objc RACSubject *letters = [RACSubject subject]; RACSubject *numbers = [RACSubject subject]; RACSignal *combined = [RACSignal combineLatest:@[ letters, numbers ] reduce:^(NSString *letter, NSString *number) { return [letter stringByAppendingString:number]; }]; // Outputs: B1 B2 C2 C3 [combined subscribeNext:^(id x) { NSLog(@"%@", x); }]; [letters sendNext:@"A"]; [letters sendNext:@"B"]; [numbers sendNext:@"1"]; [numbers sendNext:@"2"]; [letters sendNext:@"C"]; [numbers sendNext:@"3"]; ``` Note that the combined signal will only send its first value when all of the inputs have sent at least one. In the example above, `@"A"` was never forwarded because `numbers` had not sent a value yet. ### Switching The [-switchToLatest][RACSignal+Operations] operator is applied to a signal-of-signals, and always forwards the values from the latest signal: ```objc RACSubject *letters = [RACSubject subject]; RACSubject *numbers = [RACSubject subject]; RACSubject *signalOfSignals = [RACSubject subject]; RACSignal *switched = [signalOfSignals switchToLatest]; // Outputs: A B 1 D [switched subscribeNext:^(NSString *x) { NSLog(@"%@", x); }]; [signalOfSignals sendNext:letters]; [letters sendNext:@"A"]; [letters sendNext:@"B"]; [signalOfSignals sendNext:numbers]; [letters sendNext:@"C"]; [numbers sendNext:@"1"]; [signalOfSignals sendNext:letters]; [numbers sendNext:@"2"]; [letters sendNext:@"D"]; ``` [Connections]: FrameworkOverview.md#connections [RACSequence]: ../../ReactiveCocoa/Objective-C/RACSequence.h [RACSignal]: ../../ReactiveCocoa/Objective-C/RACSignal.h [RACSignal+Operations]: ../../ReactiveCocoa/Objective-C/RACSignal+Operations.h [RACStream]: ../../ReactiveCocoa/Objective-C/RACStream.h [Sequences]: FrameworkOverview.md#sequences [Signals]: FrameworkOverview.md#signals [Streams]: FrameworkOverview.md#streams [Subscription]: FrameworkOverview.md#subscription ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Documentation/Legacy/DesignGuidelines.md ================================================ # Design Guidelines This document contains guidelines for projects that want to make use of ReactiveCocoa. The content here is heavily inspired by the [Rx Design Guidelines](http://blogs.msdn.com/b/rxteam/archive/2010/10/28/rx-design-guidelines.aspx). This document assumes basic familiarity with the features of ReactiveCocoa. The [Framework Overview][] is a better resource for getting up to speed on the functionality provided by RAC. **[The RACSequence contract](#the-racsequence-contract)** 1. [Evaluation occurs lazily by default](#evaluation-occurs-lazily-by-default) 1. [Evaluation blocks the caller](#evaluation-blocks-the-caller) 1. [Side effects occur only once](#side-effects-occur-only-once) **[The RACSignal contract](#the-racsignal-contract)** 1. [Signal events are serialized](#signal-events-are-serialized) 1. [Subscription will always occur on a scheduler](#subscription-will-always-occur-on-a-scheduler) 1. [Errors are propagated immediately](#errors-are-propagated-immediately) 1. [Side effects occur for each subscription](#side-effects-occur-for-each-subscription) 1. [Subscriptions are automatically disposed upon completion or error](#subscriptions-are-automatically-disposed-upon-completion-or-error) 1. [Disposal cancels in-progress work and cleans up resources](#disposal-cancels-in-progress-work-and-cleans-up-resources) **[Best practices](#best-practices)** 1. [Use descriptive declarations for methods and properties that return a signal](#use-descriptive-declarations-for-methods-and-properties-that-return-a-signal) 1. [Indent stream operations consistently](#indent-stream-operations-consistently) 1. [Use the same type for all the values of a stream](#use-the-same-type-for-all-the-values-of-a-stream) 1. [Avoid retaining streams for too long](#avoid-retaining-streams-for-too-long) 1. [Process only as much of a stream as needed](#process-only-as-much-of-a-stream-as-needed) 1. [Deliver signal events onto a known scheduler](#deliver-signal-events-onto-a-known-scheduler) 1. [Switch schedulers in as few places as possible](#switch-schedulers-in-as-few-places-as-possible) 1. [Make the side effects of a signal explicit](#make-the-side-effects-of-a-signal-explicit) 1. [Share the side effects of a signal by multicasting](#share-the-side-effects-of-a-signal-by-multicasting) 1. [Debug streams by giving them names](#debug-streams-by-giving-them-names) 1. [Avoid explicit subscriptions and disposal](#avoid-explicit-subscriptions-and-disposal) 1. [Avoid using subjects when possible](#avoid-using-subjects-when-possible) **[Implementing new operators](#implementing-new-operators)** 1. [Prefer building on RACStream methods](#prefer-building-on-racstream-methods) 1. [Compose existing operators when possible](#compose-existing-operators-when-possible) 1. [Avoid introducing concurrency](#avoid-introducing-concurrency) 1. [Cancel work and clean up all resources in a disposable](#cancel-work-and-clean-up-all-resources-in-a-disposable) 1. [Do not block in an operator](#do-not-block-in-an-operator) 1. [Avoid stack overflow from deep recursion](#avoid-stack-overflow-from-deep-recursion) ## The RACSequence contract [RACSequence][] is a _pull-driven_ stream. Sequences behave similarly to built-in collections, but with a few unique twists. ### Evaluation occurs lazily by default Sequences are evaluated lazily by default. For example, in this sequence: ```objc NSArray *strings = @[ @"A", @"B", @"C" ]; RACSequence *sequence = [strings.rac_sequence map:^(NSString *str) { return [str stringByAppendingString:@"_"]; }]; ``` … no string appending is actually performed until the values of the sequence are needed. Accessing `sequence.head` will perform the concatenation of `A_`, accessing `sequence.tail.head` will perform the concatenation of `B_`, and so on. This generally avoids performing unnecessary work (since values that are never used are never calculated), but means that sequence processing [should be limited only to what's actually needed](#process-only-as-much-of-a-stream-as-needed). Once evaluated, the values in a sequence are memoized and do not need to be recalculated. Accessing `sequence.head` multiple times will only do the work of one string concatenation. If lazy evaluation is undesirable – for instance, because limiting memory usage is more important than avoiding unnecessary work – the [eagerSequence][RACSequence] property can be used to force a sequence (and any sequences derived from it afterward) to evaluate eagerly. ### Evaluation blocks the caller Regardless of whether a sequence is lazy or eager, evaluation of any part of a sequence will block the calling thread until completed. This is necessary because values must be synchronously retrieved from a sequence. If evaluating a sequence is expensive enough that it might block the thread for a significant amount of time, consider creating a signal with [-signalWithScheduler:][RACSequence] and using that instead. ### Side effects occur only once When the block passed to a sequence operator involves side effects, it is important to realize that those side effects will only occur once per value – namely, when the value is evaluated: ```objc NSArray *strings = @[ @"A", @"B", @"C" ]; RACSequence *sequence = [strings.rac_sequence map:^(NSString *str) { NSLog(@"%@", str); return [str stringByAppendingString:@"_"]; }]; // Logs "A" during this call. NSString *concatA = sequence.head; // Logs "B" during this call. NSString *concatB = sequence.tail.head; // Does not log anything. NSString *concatB2 = sequence.tail.head; RACSequence *derivedSequence = [sequence map:^(NSString *str) { return [@"_" stringByAppendingString:str]; }]; // Still does not log anything, because "B_" was already evaluated, and the log // statement associated with it will never be re-executed. NSString *concatB3 = derivedSequence.tail.head; ``` ## The RACSignal contract [RACSignal][] is a _push-driven_ stream with a focus on asynchronous event delivery through _subscriptions_. For more information about signals and subscriptions, see the [Framework Overview][]. ### Signal events are serialized A signal may choose to deliver its events on any thread. Consecutive events are even allowed to arrive on different threads or schedulers, unless explicitly [delivered onto a particular scheduler](#deliver-signal-events-onto-a-known-scheduler). However, RAC guarantees that no two signal events will ever arrive concurrently. While an event is being processed, no other events will be delivered. The senders of any other events will be forced to wait until the current event has been handled. Most notably, this means that the blocks passed to [-subscribeNext:error:completed:][RACSignal] do not need to be synchronized with respect to each other, because they will never be invoked simultaneously. ### Subscription will always occur on a scheduler To ensure consistent behavior for the `+createSignal:` and `-subscribe:` methods, each [RACSignal][] subscription is guaranteed to take place on a valid [RACScheduler][]. If the subscriber's thread already has a [+currentScheduler][RACScheduler], scheduling takes place immediately; otherwise, scheduling occurs as soon as possible on a background scheduler. Note that the main thread is always associated with the [+mainThreadScheduler][RACScheduler], so subscription will always be immediate there. See the documentation for [-subscribe:][RACSignal] for more information. ### Errors are propagated immediately In RAC, `error` events have exception semantics. When an error is sent on a signal, it will be immediately forwarded to all dependent signals, causing the entire chain to terminate. [Operators][RACSignal+Operations] whose primary purpose is to change error-handling behavior – like `-catch:`, `-catchTo:`, or `-materialize` – are obviously not subject to this rule. ### Side effects occur for each subscription Each new subscription to a [RACSignal][] will trigger its side effects. This means that any side effects will happen as many times as subscriptions to the signal itself. Consider this example: ```objc __block int aNumber = 0; // Signal that will have the side effect of incrementing `aNumber` block // variable for each subscription before sending it. RACSignal *aSignal = [RACSignal createSignal:^ RACDisposable * (id subscriber) { aNumber++; [subscriber sendNext:@(aNumber)]; [subscriber sendCompleted]; return nil; }]; // This will print "subscriber one: 1" [aSignal subscribeNext:^(id x) { NSLog(@"subscriber one: %@", x); }]; // This will print "subscriber two: 2" [aSignal subscribeNext:^(id x) { NSLog(@"subscriber two: %@", x); }]; ``` Side effects are repeated for each subscription. The same applies to [stream][RACStream] and [signal][RACSignal+Operations] operators: ```objc __block int missilesToLaunch = 0; // Signal that will have the side effect of changing `missilesToLaunch` on // subscription. RACSignal *processedSignal = [[RACSignal return:@"missiles"] map:^(id x) { missilesToLaunch++; return [NSString stringWithFormat:@"will launch %d %@", missilesToLaunch, x]; }]; // This will print "First will launch 1 missiles" [processedSignal subscribeNext:^(id x) { NSLog(@"First %@", x); }]; // This will print "Second will launch 2 missiles" [processedSignal subscribeNext:^(id x) { NSLog(@"Second %@", x); }]; ``` To suppress this behavior and have multiple subscriptions to a signal execute its side effects only once, a signal can be [multicasted](#share-the-side-effects-of-a-signal-by-multicasting). Side effects can be insidious and produce problems that are difficult to diagnose. For this reason it is suggested to [make side effects explicit](#make-the-side-effects-of-a-signal-explicit) when possible. ### Subscriptions are automatically disposed upon completion or error When a [subscriber][RACSubscriber] is sent a `completed` or `error` event, the associated subscription will automatically be disposed. This behavior usually eliminates the need to manually dispose of subscriptions. See the [Memory Management][] document for more information about signal lifetime. ### Disposal cancels in-progress work and cleans up resources When a subscription is disposed, manually or automatically, any in-progress or outstanding work associated with that subscription is gracefully cancelled as soon as possible, and any resources associated with the subscription are cleaned up. Disposing of the subscription to a signal representing a file upload, for example, would cancel any in-flight network request, and free the file data from memory. ## Best practices The following recommendations are intended to help keep RAC-based code predictable, understandable, and performant. They are, however, only guidelines. Use best judgement when determining whether to apply the recommendations here to a given piece of code. ### Use descriptive declarations for methods and properties that return a signal When a method or property has a return type of [RACSignal][], it can be difficult to understand the signal's semantics at a glance. There are three key questions that can inform a declaration: 1. Is the signal _hot_ (already activated by the time it's returned to the caller) or _cold_ (activated when subscribed to)? 1. Will the signal include zero, one, or more values? 1. Does the signal have side effects? **Hot signals without side effects** should typically be properties instead of methods. The use of a property indicates that no initialization is needed before subscribing to the signal's events, and that additional subscribers will not change the semantics. Signal properties should usually be named after events (e.g., `textChanged`). **Cold signals without side effects** should be returned from methods that have noun-like names (e.g., `-currentText`). A method declaration indicates that the signal might not be kept around, hinting that work is performed at the time of subscription. If the signal sends multiple values, the noun should be pluralized (e.g., `-currentModels`). **Signals with side effects** should be returned from methods that have verb-like names (e.g., `-logIn`). The verb indicates that the method is not idempotent and that callers must be careful to call it only when the side effects are desired. If the signal will send one or more values, include a noun that describes them (e.g., `-loadConfiguration`, `-fetchLatestEvents`). ### Indent stream operations consistently It's easy for stream-heavy code to become very dense and confusing if not properly formatted. Use consistent indentation to highlight where chains of streams begin and end. When invoking a single method upon a stream, no additional indentation is necessary (block arguments aside): ```objc RACStream *result = [stream startWith:@0]; RACStream *result2 = [stream map:^(NSNumber *value) { return @(value.integerValue + 1); }]; ``` When transforming the same stream multiple times, ensure that all of the steps are aligned. Complex operators like [+zip:reduce:][RACStream] or [+combineLatest:reduce:][RACSignal+Operations] may be split over multiple lines for readability: ```objc RACStream *result = [[[RACStream zip:@[ firstStream, secondStream ] reduce:^(NSNumber *first, NSNumber *second) { return @(first.integerValue + second.integerValue); }] filter:^ BOOL (NSNumber *value) { return value.integerValue >= 0; }] map:^(NSNumber *value) { return @(value.integerValue + 1); }]; ``` Of course, streams nested within block arguments should start at the natural indentation of the block: ```objc [[signal then:^{ @strongify(self); return [[self doSomethingElse] catch:^(NSError *error) { @strongify(self); [self presentError:error]; return [RACSignal empty]; }]; }] subscribeCompleted:^{ NSLog(@"All done."); }]; ``` ### Use the same type for all the values of a stream [RACStream][] (and, by extension, [RACSignal][] and [RACSequence][]) allows streams to be composed of heterogenous objects, just like Cocoa collections do. However, using different object types within the same stream complicates the use of operators and puts an additional burden on any consumers of that stream, who must be careful to only invoke supported methods. Whenever possible, streams should only contain objects of the same type. ### Avoid retaining streams for too long Retaining any [RACStream][] longer than it's needed will cause any dependencies to be retained as well, potentially keeping memory usage much higher than it would be otherwise. A [RACSequence][] should be retained only for as long as the `head` of the sequence is needed. If the head will no longer be used, retain the `tail` of the node instead of the node itself. See the [Memory Management][] guide for more information on object lifetime. ### Process only as much of a stream as needed As well as [consuming additional memory](#avoid-retaining-streams-for-too-long), unnecessarily keeping a stream or [RACSignal][] subscription alive can result in increased CPU usage, as unnecessary work is performed for results that will never be used. If only a certain number of values are needed from a stream, the [-take:][RACStream] operator can be used to retrieve only that many values, and then automatically terminate the stream immediately thereafter. Operators like `-take:` and [-takeUntil:][RACSignal+Operations] automatically propagate cancellation up the stack as well. If nothing else needs the rest of the values, any dependencies will be terminated too, potentially saving a significant amount of work. ### Deliver signal events onto a known scheduler When a signal is returned from a method, or combined with such a signal, it can be difficult to know which thread events will be delivered upon. Although events are [guaranteed to be serial](#signal-events-are-serialized), sometimes stronger guarantees are needed, like when performing UI updates (which must occur on the main thread). Whenever such a guarantee is important, the [-deliverOn:][RACSignal+Operations] operator should be used to force a signal's events to arrive on a specific [RACScheduler][]. ### Switch schedulers in as few places as possible Notwithstanding the above, events should only be delivered to a specific [scheduler][RACScheduler] when absolutely necessary. Switching schedulers can introduce unnecessary delays and cause an increase in CPU load. Generally, the use of [-deliverOn:][RACSignal+Operations] should be restricted to the end of a signal chain – e.g., before subscription, or before the values are bound to a property. ### Make the side effects of a signal explicit As much as possible, [RACSignal][] side effects should be avoided, because subscribers may find the [behavior of side effects](#side-effects-occur-for-each-subscription) unexpected. However, because Cocoa is predominantly imperative, it is sometimes useful to perform side effects when signal events occur. Although most [RACStream][] and [RACSignal][RACSignal+Operations] operators accept arbitrary blocks (which can contain side effects), the use of `-doNext:`, `-doError:`, and `-doCompleted:` will make side effects more explicit and self-documenting: ```objc NSMutableArray *nexts = [NSMutableArray array]; __block NSError *receivedError = nil; __block BOOL success = NO; RACSignal *bookkeepingSignal = [[[valueSignal doNext:^(id x) { [nexts addObject:x]; }] doError:^(NSError *error) { receivedError = error; }] doCompleted:^{ success = YES; }]; RAC(self, value) = bookkeepingSignal; ``` ### Share the side effects of a signal by multicasting [Side effects occur for each subscription](#side-effects-occur-for-each-subscription) by default, but there are certain situations where side effects should only occur once – for example, a network request typically should not be repeated when a new subscriber is added. The `-publish` and `-multicast:` operators of [RACSignal][RACSignal+Operations] allow a single subscription to be shared to any number of subscribers by using a [RACMulticastConnection][]: ```objc // This signal starts a new request on each subscription. RACSignal *networkRequest = [RACSignal createSignal:^(id subscriber) { AFHTTPRequestOperation *operation = [client HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id response) { [subscriber sendNext:response]; [subscriber sendCompleted]; } failure:^(AFHTTPRequestOperation *operation, NSError *error) { [subscriber sendError:error]; }]; [client enqueueHTTPRequestOperation:operation]; return [RACDisposable disposableWithBlock:^{ [operation cancel]; }]; }]; // Starts a single request, no matter how many subscriptions `connection.signal` // gets. This is equivalent to the -replay operator, or similar to // +startEagerlyWithScheduler:block:. RACMulticastConnection *connection = [networkRequest multicast:[RACReplaySubject subject]]; [connection connect]; [connection.signal subscribeNext:^(id response) { NSLog(@"subscriber one: %@", response); }]; [connection.signal subscribeNext:^(id response) { NSLog(@"subscriber two: %@", response); }]; ``` ### Debug streams by giving them names Every [RACStream][] has a `name` property to assist with debugging. A stream's `-description` includes its name, and all operators provided by RAC will automatically add to the name. This usually makes it possible to identify a stream from its default name alone. For example, this snippet: ```objc RACSignal *signal = [[[RACObserve(self, username) distinctUntilChanged] take:3] filter:^(NSString *newUsername) { return [newUsername isEqualToString:@"joshaber"]; }]; NSLog(@"%@", signal); ``` … would log a name similar to `[[[RACObserve(self, username)] -distinctUntilChanged] -take: 3] -filter:`. Names can also be manually applied by using [-setNameWithFormat:][RACStream]. [RACSignal][] also offers `-logNext`, `-logError`, `-logCompleted`, and `-logAll` methods, which will automatically log signal events as they occur, and include the name of the signal in the messages. This can be used to conveniently inspect a signal in real-time. ### Avoid explicit subscriptions and disposal Although [-subscribeNext:error:completed:][RACSignal] and its variants are the most basic way to process a signal, their use can complicate code by being less declarative, encouraging the use of side effects, and potentially duplicating built-in functionality. Likewise, explicit use of the [RACDisposable][] class can quickly lead to a rat's nest of resource management and cleanup code. There are almost always higher-level patterns that can be used instead of manual subscriptions and disposal: * The [RAC()][RAC] or [RACChannelTo()][RACChannelTo] macros can be used to bind a signal to a property, instead of performing manual updates when changes occur. * The [-rac_liftSelector:withSignals:][NSObject+RACLifting] method can be used to automatically invoke a selector when one or more signals fire. * Operators like [-takeUntil:][RACSignal+Operations] can be used to automatically dispose of a subscription when an event occurs (like a "Cancel" button being pressed in the UI). Generally, the use of built-in [stream][RACStream] and [signal][RACSignal+Operations] operators will lead to simpler and less error-prone code than replicating the same behaviors in a subscription callback. ### Avoid using subjects when possible [Subjects][] are a powerful tool for bridging imperative code into the world of signals, but, as the "mutable variables" of RAC, they can quickly lead to complexity when overused. Since they can be manipulated from anywhere, at any time, subjects often break the linear flow of stream processing and make logic much harder to follow. They also don't support meaningful [disposal](#disposal-cancels-in-progress-work-and-cleans-up-resources), which can result in unnecessary work. Subjects can usually be replaced with other patterns from ReactiveCocoa: * Instead of feeding initial values into a subject, consider generating the values in a [+createSignal:][RACSignal] block instead. * Instead of delivering intermediate results to a subject, try combining the output of multiple signals with operators like [+combineLatest:][RACSignal+Operations] or [+zip:][RACStream]. * Instead of using subjects to share results with multiple subscribers, [multicast](#share-the-side-effects-of-a-signal-by-multicasting) a base signal instead. * Instead of implementing an action method which simply controls a subject, use a [command][RACCommand] or [-rac_signalForSelector:][NSObject+RACSelectorSignal] instead. When subjects _are_ necessary, they should almost always be the "base" input for a signal chain, not used in the middle of one. ## Implementing new operators RAC provides a long list of built-in operators for [streams][RACStream] and [signals][RACSignal+Operations] that should cover most use cases; however, RAC is not a closed system. It's entirely valid to implement additional operators for specialized uses, or for consideration in ReactiveCocoa itself. Implementing a new operator requires a careful attention to detail and a focus on simplicity, to avoid introducing bugs into the calling code. These guidelines cover some of the common pitfalls and help preserve the expected API contracts. ### Prefer building on RACStream methods [RACStream][] offers a simpler interface than [RACSequence][] and [RACSignal][], and all stream operators are automatically applicable to sequences and signals as well. For these reasons, new operators should be implemented using only [RACStream][] methods whenever possible. The minimal required methods of the class, including `-bind:`, `-zipWith:`, and `-concat:`, are quite powerful, and many tasks can be accomplished without needing anything else. If a new [RACSignal][] operator needs to handle `error` and `completed` events, consider using the [-materialize][RACSignal+Operations] method to bring the events into the stream. All of the events of a materialized signal can be manipulated by stream operators, which helps minimize the use of non-stream operators. ### Compose existing operators when possible Considerable thought has been put into the operators provided by RAC, and they have been validated through automated tests and through their real world use in other projects. An operator that has been written from scratch may not be as robust, or might not handle a special case that the built-in operators are aware of. To minimize duplication and possible bugs, use the provided operators as much as possible in a custom operator implementation. Generally, there should be very little code written from scratch. ### Avoid introducing concurrency Concurrency is an extremely common source of bugs in programming. To minimize the potential for deadlocks and race conditions, operators should not concurrently perform their work. Callers always have the ability to subscribe or deliver events on a specific [RACScheduler][], and RAC offers powerful ways to [parallelize work][Parallelizing Independent Work] without making operators unnecessarily complex. ### Cancel work and clean up all resources in a disposable When implementing a signal with the [+createSignal:][RACSignal] method, the provided block is expected to return a [RACDisposable][]. This disposable should: * As soon as it is convenient, gracefully cancel any in-progress work that was started by the signal. * Immediately dispose of any subscriptions to other signals, thus triggering their cancellation and cleanup code as well. * Release any memory or other resources that were allocated by the signal. This helps fulfill [the RACSignal contract](#disposal-cancels-in-progress-work-and-cleans-up-resources). ### Do not block in an operator Stream operators should return a new stream more-or-less immediately. Any work that the operator needs to perform should be part of evaluating the new stream, _not_ part of the operator invocation itself. ```objc // WRONG! - (RACSequence *)map:(id (^)(id))block { RACSequence *result = [RACSequence empty]; for (id obj in self) { id mappedObj = block(obj); result = [result concat:[RACSequence return:mappedObj]]; } return result; } // Right! - (RACSequence *)map:(id (^)(id))block { return [self flattenMap:^(id obj) { id mappedObj = block(obj); return [RACSequence return:mappedObj]; }]; } ``` This guideline can be safely ignored when the purpose of an operator is to synchronously retrieve one or more values from a stream (like [-first][RACSignal+Operations]). ### Avoid stack overflow from deep recursion Any operator that might recurse indefinitely should use the `-scheduleRecursiveBlock:` method of [RACScheduler][]. This method will transform recursion into iteration instead, preventing a stack overflow. For example, this would be an incorrect implementation of [-repeat][RACSignal+Operations], due to its potential to overflow the call stack and cause a crash: ```objc - (RACSignal *)repeat { return [RACSignal createSignal:^(id subscriber) { RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable]; __block void (^resubscribe)(void) = ^{ RACDisposable *disposable = [self subscribeNext:^(id x) { [subscriber sendNext:x]; } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ resubscribe(); }]; [compoundDisposable addDisposable:disposable]; }; return compoundDisposable; }]; } ``` By contrast, this version will avoid a stack overflow: ```objc - (RACSignal *)repeat { return [RACSignal createSignal:^(id subscriber) { RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable]; RACScheduler *scheduler = RACScheduler.currentScheduler ?: [RACScheduler scheduler]; RACDisposable *disposable = [scheduler scheduleRecursiveBlock:^(void (^reschedule)(void)) { RACDisposable *disposable = [self subscribeNext:^(id x) { [subscriber sendNext:x]; } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ reschedule(); }]; [compoundDisposable addDisposable:disposable]; }]; [compoundDisposable addDisposable:disposable]; return compoundDisposable; }]; } ``` [Framework Overview]: FrameworkOverview.md [Memory Management]: MemoryManagement.md [NSObject+RACLifting]: ../../ReactiveCocoa/Objective-C/NSObject+RACLifting.h [NSObject+RACSelectorSignal]: ../../ReactiveCocoa/Objective-C/NSObject+RACSelectorSignal.h [RAC]: ../../ReactiveCocoa/Objective-C/RACSubscriptingAssignmentTrampoline.h [RACChannelTo]: ../../ReactiveCocoa/Objective-C/RACKVOChannel.h [RACCommand]: ../../ReactiveCocoa/Objective-C/RACCommand.h [RACDisposable]: ../../ReactiveCocoa/Objective-C/RACDisposable.h [RACEvent]: ../../ReactiveCocoa/Objective-C/RACEvent.h [RACMulticastConnection]: ../../ReactiveCocoa/Objective-C/RACMulticastConnection.h [RACObserve]: ../../ReactiveCocoa/Objective-C/NSObject+RACPropertySubscribing.h [RACScheduler]: ../../ReactiveCocoa/Objective-C/RACScheduler.h [RACSequence]: ../../ReactiveCocoa/Objective-C/RACSequence.h [RACSignal]: ../../ReactiveCocoa/Objective-C/RACSignal.h [RACSignal+Operations]: ../../ReactiveCocoa/Objective-C/RACSignal+Operations.h [RACStream]: ../../ReactiveCocoa/Objective-C/RACStream.h [RACSubscriber]: ../../ReactiveCocoa/Objective-C/RACSubscriber.h [Subjects]: FrameworkOverview.md#subjects [Parallelizing Independent Work]: ../README.md#parallelizing-independent-work ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Documentation/Legacy/FrameworkOverview.md ================================================ # Framework Overview This document contains a high-level description of the different components within the ReactiveCocoa framework, and an attempt to explain how they work together and divide responsibilities. This is meant to be a starting point for learning about new modules and finding more specific documentation. For examples and help understanding how to use RAC, see the [README][] or the [Design Guidelines][]. ## Streams A **stream**, represented by the [RACStream][] abstract class, is any series of object values. Values may be available immediately or in the future, but must be retrieved sequentially. There is no way to retrieve the second value of a stream without evaluating or waiting for the first value. Streams are [monads][]. Among other things, this allows complex operations to be built on a few basic primitives (`-bind:` in particular). [RACStream][] also implements the equivalent of the [Monoid][] and [MonadZip][] typeclasses from [Haskell][]. [RACStream][] isn't terribly useful on its own. Most streams are treated as [signals](#signals) or [sequences](#sequences) instead. ## Signals A **signal**, represented by the [RACSignal][] class, is a _push-driven_ [stream](#streams). Signals generally represent data that will be delivered in the future. As work is performed or data is received, values are _sent_ on the signal, which pushes them out to any subscribers. Users must [subscribe](#subscription) to a signal in order to access its values. Signals send three different types of events to their subscribers: * The **next** event provides a new value from the stream. [RACStream][] methods only operate on events of this type. Unlike Cocoa collections, it is completely valid for a signal to include `nil`. * The **error** event indicates that an error occurred before the signal could finish. The event may include an `NSError` object that indicates what went wrong. Errors must be handled specially – they are not included in the stream's values. * The **completed** event indicates that the signal finished successfully, and that no more values will be added to the stream. Completion must be handled specially – it is not included in the stream of values. The lifetime of a signal consists of any number of `next` events, followed by one `error` or `completed` event (but not both). ### Subscription A **subscriber** is anything that is waiting or capable of waiting for events from a [signal](#signals). Within RAC, a subscriber is represented as any object that conforms to the [RACSubscriber][] protocol. A **subscription** is created through any call to [-subscribeNext:error:completed:][RACSignal], or one of the corresponding convenience methods. Technically, most [RACStream][] and [RACSignal][RACSignal+Operations] operators create subscriptions as well, but these intermediate subscriptions are usually an implementation detail. Subscriptions [retain their signals][Memory Management], and are automatically disposed of when the signal completes or errors. Subscriptions can also be [disposed of manually](#disposables). ### Subjects A **subject**, represented by the [RACSubject][] class, is a [signal](#signals) that can be manually controlled. Subjects can be thought of as the "mutable" variant of a signal, much like `NSMutableArray` is for `NSArray`. They are extremely useful for bridging non-RAC code into the world of signals. For example, instead of handling application logic in block callbacks, the blocks can simply send events to a shared subject instead. The subject can then be returned as a [RACSignal][], hiding the implementation detail of the callbacks. Some subjects offer additional behaviors as well. In particular, [RACReplaySubject][] can be used to buffer events for future [subscribers](#subscription), like when a network request finishes before anything is ready to handle the result. ### Commands A **command**, represented by the [RACCommand][] class, creates and subscribes to a signal in response to some action. This makes it easy to perform side-effecting work as the user interacts with the app. Usually the action triggering a command is UI-driven, like when a button is clicked. Commands can also be automatically disabled based on a signal, and this disabled state can be represented in a UI by disabling any controls associated with the command. On OS X, RAC adds a `rac_command` property to [NSButton][NSButton+RACCommandSupport] for setting up these behaviors automatically. ### Connections A **connection**, represented by the [RACMulticastConnection][] class, is a [subscription](#subscription) that is shared between any number of subscribers. [Signals](#signals) are _cold_ by default, meaning that they start doing work _each_ time a new subscription is added. This behavior is usually desirable, because it means that data will be freshly recalculated for each subscriber, but it can be problematic if the signal has side effects or the work is expensive (for example, sending a network request). A connection is created through the `-publish` or `-multicast:` methods on [RACSignal][RACSignal+Operations], and ensures that only one underlying subscription is created, no matter how many times the connection is subscribed to. Once connected, the connection's signal is said to be _hot_, and the underlying subscription will remain active until _all_ subscriptions to the connection are [disposed](#disposables). ## Sequences A **sequence**, represented by the [RACSequence][] class, is a _pull-driven_ [stream](#streams). Sequences are a kind of collection, similar in purpose to `NSArray`. Unlike an array, the values in a sequence are evaluated _lazily_ (i.e., only when they are needed) by default, potentially improving performance if only part of a sequence is used. Just like Cocoa collections, sequences cannot contain `nil`. Sequences are similar to [Clojure's sequences][seq] ([lazy-seq][] in particular), or the [List][] type in [Haskell][]. RAC adds a `-rac_sequence` method to most of Cocoa's collection classes, allowing them to be used as [RACSequences][RACSequence] instead. ## Disposables The **[RACDisposable][]** class is used for cancellation and resource cleanup. Disposables are most commonly used to unsubscribe from a [signal](#signals). When a [subscription](#subscription) is disposed, the corresponding subscriber will not receive _any_ further events from the signal. Additionally, any work associated with the subscription (background processing, network requests, etc.) will be cancelled, since the results are no longer needed. For more information about cancellation, see the RAC [Design Guidelines][]. ## Schedulers A **scheduler**, represented by the [RACScheduler][] class, is a serial execution queue for [signals](#signals) to perform work or deliver their results upon. Schedulers are similar to Grand Central Dispatch queues, but schedulers support cancellation (via [disposables](#disposables)), and always execute serially. With the exception of the [+immediateScheduler][RACScheduler], schedulers do not offer synchronous execution. This helps avoid deadlocks, and encourages the use of [signal operators][RACSignal+Operations] instead of blocking work. [RACScheduler][] is also somewhat similar to `NSOperationQueue`, but schedulers do not allow tasks to be reordered or depend on one another. ## Value types RAC offers a few miscellaneous classes for conveniently representing values in a [stream](#streams): * **[RACTuple][]** is a small, constant-sized collection that can contain `nil` (represented by `RACTupleNil`). It is generally used to represent the combined values of multiple streams. * **[RACUnit][]** is a singleton "empty" value. It is used as a value in a stream for those times when more meaningful data doesn't exist. * **[RACEvent][]** represents any [signal event](#signals) as a single value. It is primarily used by the `-materialize` method of [RACSignal][RACSignal+Operations]. [Design Guidelines]: DesignGuidelines.md [Haskell]: http://www.haskell.org [lazy-seq]: http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/lazy-seq [List]: https://downloads.haskell.org/~ghc/latest/docs/html/libraries/Data-List.html [Memory Management]: MemoryManagement.md [monads]: http://en.wikipedia.org/wiki/Monad_(functional_programming) [Monoid]: http://downloads.haskell.org/~ghc/latest/docs/html/libraries/Data-Monoid.html [MonadZip]: http://downloads.haskell.org/~ghc/latest/docs/html/libraries/Control-Monad-Zip.html [NSButton+RACCommandSupport]: ../../ReactiveCocoa/Objective-C/NSButton+RACCommandSupport.h [RACCommand]: ../../ReactiveCocoa/Objective-C/RACCommand.h [RACDisposable]: ../../ReactiveCocoa/Objective-C/RACDisposable.h [RACEvent]: ../../ReactiveCocoa/Objective-C/RACEvent.h [RACMulticastConnection]: ../../ReactiveCocoa/Objective-C/RACMulticastConnection.h [RACReplaySubject]: ../../ReactiveCocoa/Objective-C/RACReplaySubject.h [RACScheduler]: ../../ReactiveCocoa/Objective-C/RACScheduler.h [RACSequence]: ../../ReactiveCocoa/Objective-C/RACSequence.h [RACSignal]: ../../ReactiveCocoa/Objective-C/RACSignal.h [RACSignal+Operations]: ../../ReactiveCocoa/Objective-C/RACSignal+Operations.h [RACStream]: ../../ReactiveCocoa/Objective-C/RACStream.h [RACSubject]: ../../ReactiveCocoa/Objective-C/RACSubject.h [RACSubscriber]: ../../ReactiveCocoa/Objective-C/RACSubscriber.h [RACTuple]: ../../ReactiveCocoa/Objective-C/RACTuple.h [RACUnit]: ../../ReactiveCocoa/Objective-C/RACUnit.h [README]: README.md [seq]: http://clojure.org/sequences ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Documentation/Legacy/MemoryManagement.md ================================================ # Memory Management ReactiveCocoa's memory management is quite complex, but the end result is that **you don't need to retain signals in order to process them**. If the framework required you to retain every signal, it'd be much more unwieldy to use, especially for one-shot signals that are used like futures (e.g., network requests). You'd have to save any long-lived signal into a property, and then also make sure to clear it out when you're done with it. Not fun. ## Subscribers Before going any further, it's worth noting that `subscribeNext:error:completed:` (and all variants thereof) create an _implicit_ subscriber using the given blocks. Any objects referenced from those blocks will therefore be retained as part of the subscription. Just like any other object, `self` won't be retained without a direct or indirect reference to it. ## Finite or Short-Lived Signals The most important guideline to RAC memory management is that a **subscription is automatically terminated upon completion or error, and the subscriber removed**. For example, if you have some code like this in your view controller: ```objc self.disposable = [signal subscribeCompleted:^{ doSomethingPossiblyInvolving(self); }]; ``` … the memory management will look something like the following: ``` view controller -> RACDisposable -> RACSignal -> RACSubscriber -> view controller ``` However, the `RACSignal -> RACSubscriber` relationship is torn down as soon as `signal` finishes, breaking the retain cycle. **This is often all you need**, because the lifetime of the `RACSignal` in memory will naturally match the logical lifetime of the event stream. ## Infinite Signals Infinite signals (or signals that live so long that they might as well be infinite), however, will never tear down naturally. This is where disposables shine. **Disposing of a subscription will remove the associated subscriber**, and just generally clean up any resources associated with that subscription. To that one subscriber, it's just as if the signal had completed or errored, except no final event is sent on the signal. All other subscribers will remain intact. However, as a general rule of thumb, if you have to manually manage a subscription's lifecycle, [there's probably a better way to do what you want][avoid-explicit-subscriptions-and-disposal]. ## Signals Derived from `self` There's still a bit of a tricky middle case here, though. Any time a signal's lifetime is tied to the calling scope, you'll have a much harder cycle to break. This commonly occurs when using `RACObserve()` on a key path that's relative to `self`, and then applying a block that needs to capture `self`. The easiest answer here is just to **capture `self` weakly**: ```objc __weak id weakSelf = self; [RACObserve(self, username) subscribeNext:^(NSString *username) { id strongSelf = weakSelf; [strongSelf validateUsername]; }]; ``` Or, after importing the included [EXTScope.h](https://github.com/jspahrsummers/libextobjc/blob/master/extobjc/EXTScope.h) header: ```objc @weakify(self); [RACObserve(self, username) subscribeNext:^(NSString *username) { @strongify(self); [self validateUsername]; }]; ``` *(Replace `__weak` or `@weakify` with `__unsafe_unretained` or `@unsafeify`, respectively, if the object doesn't support weak references.)* However, [there's probably a better pattern you could use instead][avoid-explicit-subscriptions-and-disposal]. For example, the above sample could perhaps be written like: ```objc [self rac_liftSelector:@selector(validateUsername:) withSignals:RACObserve(self, username), nil]; ``` or: ```objc RACSignal *validated = [RACObserve(self, username) map:^(NSString *username) { // Put validation logic here. return @YES; }]; ``` As with infinite signals, there are generally ways you can avoid referencing `self` (or any object) from blocks in a signal chain. ---- The above information is really all you should need in order to use ReactiveCocoa effectively. However, there's one more point to address, just for the technically curious or for anyone interested in contributing to RAC. The design goal of "no retaining necessary" begs the question: how do we know when a signal should be deallocated? What if it was just created, escaped an autorelease pool, and hasn't been retained yet? The real answer is _we don't_, BUT we can usually assume that the caller will retain the signal within the current run loop iteration if they want to keep it. Consequently: 1. A created signal is automatically added to a global set of active signals. 2. The signal will wait for a single pass of the main run loop, and then remove itself from the active set _if it has no subscribers_. Unless the signal was retained somehow, it would deallocate at this point. 3. If something did subscribe in that run loop iteration, the signal stays in the set. 4. Later, when all the subscribers are gone, step 2 is triggered again. This could backfire if the run loop is spun recursively (like in a modal event loop on OS X), but it makes the life of the framework consumer much easier for most or all other cases. [avoid-explicit-subscriptions-and-disposal]: DesignGuidelines.md#avoid-explicit-subscriptions-and-disposal ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Documentation/Legacy/README.md ================================================ # ReactiveCocoa _NOTE: This is legacy introduction to the Objective-C ReactiveCocoa. For the updated version that uses Swift please see the main [README][]_ ReactiveCocoa (RAC) is an Objective-C framework inspired by [Functional Reactive Programming][]. It provides APIs for **composing and transforming streams of values**. If you're already familiar with functional reactive programming or know the basic premise of ReactiveCocoa, check out the other documentation in this folder for a framework overview and more in-depth information about how it all works in practice. ## New to ReactiveCocoa? ReactiveCocoa is documented like crazy, and there's a wealth of introductory material available to explain what RAC is and how you can use it. If you want to learn more, we recommend these resources, roughly in order: 1. [Introduction](#introduction) 1. [When to use ReactiveCocoa](#when-to-use-reactivecocoa) 1. [Framework Overview][] 1. [Basic Operators][] 1. [Header documentation](../../ReactiveCocoa/Objective-C) 1. Previously answered [Stack Overflow](https://github.com/ReactiveCocoa/ReactiveCocoa/wiki) questions and [GitHub issues](https://github.com/ReactiveCocoa/ReactiveCocoa/issues?labels=question&state=closed) 1. The rest of this folder 1. [Functional Reactive Programming on iOS](https://leanpub.com/iosfrp/) (eBook) If you have any further questions, please feel free to [file an issue](https://github.com/ReactiveCocoa/ReactiveCocoa/issues/new). ## Introduction ReactiveCocoa is inspired by [functional reactive programming](http://blog.maybeapps.com/post/42894317939/input-and-output). Rather than using mutable variables which are replaced and modified in-place, RAC provides signals (represented by `RACSignal`) that capture present and future values. By chaining, combining, and reacting to signals, software can be written declaratively, without the need for code that continually observes and updates values. For example, a text field can be bound to the latest time, even as it changes, instead of using additional code that watches the clock and updates the text field every second. It works much like KVO, but with blocks instead of overriding `-observeValueForKeyPath:ofObject:change:context:`. Signals can also represent asynchronous operations, much like [futures and promises][]. This greatly simplifies asynchronous software, including networking code. One of the major advantages of RAC is that it provides a single, unified approach to dealing with asynchronous behaviors, including delegate methods, callback blocks, target-action mechanisms, notifications, and KVO. Here's a simple example: ```objc // When self.username changes, logs the new name to the console. // // RACObserve(self, username) creates a new RACSignal that sends the current // value of self.username, then the new value whenever it changes. // -subscribeNext: will execute the block whenever the signal sends a value. [RACObserve(self, username) subscribeNext:^(NSString *newName) { NSLog(@"%@", newName); }]; ``` But unlike KVO notifications, signals can be chained together and operated on: ```objc // Only logs names that starts with "j". // // -filter returns a new RACSignal that only sends a new value when its block // returns YES. [[RACObserve(self, username) filter:^(NSString *newName) { return [newName hasPrefix:@"j"]; }] subscribeNext:^(NSString *newName) { NSLog(@"%@", newName); }]; ``` Signals can also be used to derive state. Instead of observing properties and setting other properties in response to the new values, RAC makes it possible to express properties in terms of signals and operations: ```objc // Creates a one-way binding so that self.createEnabled will be // true whenever self.password and self.passwordConfirmation // are equal. // // RAC() is a macro that makes the binding look nicer. // // +combineLatest:reduce: takes an array of signals, executes the block with the // latest value from each signal whenever any of them changes, and returns a new // RACSignal that sends the return value of that block as values. RAC(self, createEnabled) = [RACSignal combineLatest:@[ RACObserve(self, password), RACObserve(self, passwordConfirmation) ] reduce:^(NSString *password, NSString *passwordConfirm) { return @([passwordConfirm isEqualToString:password]); }]; ``` Signals can be built on any stream of values over time, not just KVO. For example, they can also represent button presses: ```objc // Logs a message whenever the button is pressed. // // RACCommand creates signals to represent UI actions. Each signal can // represent a button press, for example, and have additional work associated // with it. // // -rac_command is an addition to NSButton. The button will send itself on that // command whenever it's pressed. self.button.rac_command = [[RACCommand alloc] initWithSignalBlock:^(id _) { NSLog(@"button was pressed!"); return [RACSignal empty]; }]; ``` Or asynchronous network operations: ```objc // Hooks up a "Log in" button to log in over the network. // // This block will be run whenever the login command is executed, starting // the login process. self.loginCommand = [[RACCommand alloc] initWithSignalBlock:^(id sender) { // The hypothetical -logIn method returns a signal that sends a value when // the network request finishes. return [client logIn]; }]; // -executionSignals returns a signal that includes the signals returned from // the above block, one for each time the command is executed. [self.loginCommand.executionSignals subscribeNext:^(RACSignal *loginSignal) { // Log a message whenever we log in successfully. [loginSignal subscribeCompleted:^{ NSLog(@"Logged in successfully!"); }]; }]; // Executes the login command when the button is pressed. self.loginButton.rac_command = self.loginCommand; ``` Signals can also represent timers, other UI events, or anything else that changes over time. Using signals for asynchronous operations makes it possible to build up more complex behavior by chaining and transforming those signals. Work can easily be triggered after a group of operations completes: ```objc // Performs 2 network operations and logs a message to the console when they are // both completed. // // +merge: takes an array of signals and returns a new RACSignal that passes // through the values of all of the signals and completes when all of the // signals complete. // // -subscribeCompleted: will execute the block when the signal completes. [[RACSignal merge:@[ [client fetchUserRepos], [client fetchOrgRepos] ]] subscribeCompleted:^{ NSLog(@"They're both done!"); }]; ``` Signals can be chained to sequentially execute asynchronous operations, instead of nesting callbacks with blocks. This is similar to how [futures and promises][] are usually used: ```objc // Logs in the user, then loads any cached messages, then fetches the remaining // messages from the server. After that's all done, logs a message to the // console. // // The hypothetical -logInUser methods returns a signal that completes after // logging in. // // -flattenMap: will execute its block whenever the signal sends a value, and // returns a new RACSignal that merges all of the signals returned from the block // into a single signal. [[[[client logInUser] flattenMap:^(User *user) { // Return a signal that loads cached messages for the user. return [client loadCachedMessagesForUser:user]; }] flattenMap:^(NSArray *messages) { // Return a signal that fetches any remaining messages. return [client fetchMessagesAfterMessage:messages.lastObject]; }] subscribeNext:^(NSArray *newMessages) { NSLog(@"New messages: %@", newMessages); } completed:^{ NSLog(@"Fetched all messages."); }]; ``` RAC even makes it easy to bind to the result of an asynchronous operation: ```objc // Creates a one-way binding so that self.imageView.image will be set as the user's // avatar as soon as it's downloaded. // // The hypothetical -fetchUserWithUsername: method returns a signal which sends // the user. // // -deliverOn: creates new signals that will do their work on other queues. In // this example, it's used to move work to a background queue and then back to the main thread. // // -map: calls its block with each user that's fetched and returns a new // RACSignal that sends values returned from the block. RAC(self.imageView, image) = [[[[client fetchUserWithUsername:@"joshaber"] deliverOn:[RACScheduler scheduler]] map:^(User *user) { // Download the avatar (this is done on a background queue). return [[NSImage alloc] initWithContentsOfURL:user.avatarURL]; }] // Now the assignment will be done on the main thread. deliverOn:RACScheduler.mainThreadScheduler]; ``` That demonstrates some of what RAC can do, but it doesn't demonstrate why RAC is so powerful. It's hard to appreciate RAC from README-sized examples, but it makes it possible to write code with less state, less boilerplate, better code locality, and better expression of intent. For more sample code, check out [C-41][] or [GroceryList][], which are real iOS apps written using ReactiveCocoa. Additional information about RAC can be found in this folder. ## When to use ReactiveCocoa Upon first glance, ReactiveCocoa is very abstract, and it can be difficult to understand how to apply it to concrete problems. Here are some of the use cases that RAC excels at. ### Handling asynchronous or event-driven data sources Much of Cocoa programming is focused on reacting to user events or changes in application state. Code that deals with such events can quickly become very complex and spaghetti-like, with lots of callbacks and state variables to handle ordering issues. Patterns that seem superficially different, like UI callbacks, network responses, and KVO notifications, actually have a lot in common. [RACSignal][] unifies all these different APIs so that they can be composed together and manipulated in the same way. For example, the following code: ```objc static void *ObservationContext = &ObservationContext; - (void)viewDidLoad { [super viewDidLoad]; [LoginManager.sharedManager addObserver:self forKeyPath:@"loggingIn" options:NSKeyValueObservingOptionInitial context:&ObservationContext]; [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(loggedOut:) name:UserDidLogOutNotification object:LoginManager.sharedManager]; [self.usernameTextField addTarget:self action:@selector(updateLogInButton) forControlEvents:UIControlEventEditingChanged]; [self.passwordTextField addTarget:self action:@selector(updateLogInButton) forControlEvents:UIControlEventEditingChanged]; [self.logInButton addTarget:self action:@selector(logInPressed:) forControlEvents:UIControlEventTouchUpInside]; } - (void)dealloc { [LoginManager.sharedManager removeObserver:self forKeyPath:@"loggingIn" context:ObservationContext]; [NSNotificationCenter.defaultCenter removeObserver:self]; } - (void)updateLogInButton { BOOL textFieldsNonEmpty = self.usernameTextField.text.length > 0 && self.passwordTextField.text.length > 0; BOOL readyToLogIn = !LoginManager.sharedManager.isLoggingIn && !self.loggedIn; self.logInButton.enabled = textFieldsNonEmpty && readyToLogIn; } - (IBAction)logInPressed:(UIButton *)sender { [[LoginManager sharedManager] logInWithUsername:self.usernameTextField.text password:self.passwordTextField.text success:^{ self.loggedIn = YES; } failure:^(NSError *error) { [self presentError:error]; }]; } - (void)loggedOut:(NSNotification *)notification { self.loggedIn = NO; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (context == ObservationContext) { [self updateLogInButton]; } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } ``` … could be expressed in RAC like so: ```objc - (void)viewDidLoad { [super viewDidLoad]; @weakify(self); RAC(self.logInButton, enabled) = [RACSignal combineLatest:@[ self.usernameTextField.rac_textSignal, self.passwordTextField.rac_textSignal, RACObserve(LoginManager.sharedManager, loggingIn), RACObserve(self, loggedIn) ] reduce:^(NSString *username, NSString *password, NSNumber *loggingIn, NSNumber *loggedIn) { return @(username.length > 0 && password.length > 0 && !loggingIn.boolValue && !loggedIn.boolValue); }]; [[self.logInButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(UIButton *sender) { @strongify(self); RACSignal *loginSignal = [LoginManager.sharedManager logInWithUsername:self.usernameTextField.text password:self.passwordTextField.text]; [loginSignal subscribeError:^(NSError *error) { @strongify(self); [self presentError:error]; } completed:^{ @strongify(self); self.loggedIn = YES; }]; }]; RAC(self, loggedIn) = [[NSNotificationCenter.defaultCenter rac_addObserverForName:UserDidLogOutNotification object:nil] mapReplace:@NO]; } ``` ### Chaining dependent operations Dependencies are most often found in network requests, where a previous request to the server needs to complete before the next one can be constructed, and so on: ```objc [client logInWithSuccess:^{ [client loadCachedMessagesWithSuccess:^(NSArray *messages) { [client fetchMessagesAfterMessage:messages.lastObject success:^(NSArray *nextMessages) { NSLog(@"Fetched all messages."); } failure:^(NSError *error) { [self presentError:error]; }]; } failure:^(NSError *error) { [self presentError:error]; }]; } failure:^(NSError *error) { [self presentError:error]; }]; ``` ReactiveCocoa makes this pattern particularly easy: ```objc [[[[client logIn] then:^{ return [client loadCachedMessages]; }] flattenMap:^(NSArray *messages) { return [client fetchMessagesAfterMessage:messages.lastObject]; }] subscribeError:^(NSError *error) { [self presentError:error]; } completed:^{ NSLog(@"Fetched all messages."); }]; ``` ### Parallelizing independent work Working with independent data sets in parallel and then combining them into a final result is non-trivial in Cocoa, and often involves a lot of synchronization: ```objc __block NSArray *databaseObjects; __block NSArray *fileContents; NSOperationQueue *backgroundQueue = [[NSOperationQueue alloc] init]; NSBlockOperation *databaseOperation = [NSBlockOperation blockOperationWithBlock:^{ databaseObjects = [databaseClient fetchObjectsMatchingPredicate:predicate]; }]; NSBlockOperation *filesOperation = [NSBlockOperation blockOperationWithBlock:^{ NSMutableArray *filesInProgress = [NSMutableArray array]; for (NSString *path in files) { [filesInProgress addObject:[NSData dataWithContentsOfFile:path]]; } fileContents = [filesInProgress copy]; }]; NSBlockOperation *finishOperation = [NSBlockOperation blockOperationWithBlock:^{ [self finishProcessingDatabaseObjects:databaseObjects fileContents:fileContents]; NSLog(@"Done processing"); }]; [finishOperation addDependency:databaseOperation]; [finishOperation addDependency:filesOperation]; [backgroundQueue addOperation:databaseOperation]; [backgroundQueue addOperation:filesOperation]; [backgroundQueue addOperation:finishOperation]; ``` The above code can be cleaned up and optimized by simply composing signals: ```objc RACSignal *databaseSignal = [[databaseClient fetchObjectsMatchingPredicate:predicate] subscribeOn:[RACScheduler scheduler]]; RACSignal *fileSignal = [RACSignal startEagerlyWithScheduler:[RACScheduler scheduler] block:^(id subscriber) { NSMutableArray *filesInProgress = [NSMutableArray array]; for (NSString *path in files) { [filesInProgress addObject:[NSData dataWithContentsOfFile:path]]; } [subscriber sendNext:[filesInProgress copy]]; [subscriber sendCompleted]; }]; [[RACSignal combineLatest:@[ databaseSignal, fileSignal ] reduce:^ id (NSArray *databaseObjects, NSArray *fileContents) { [self finishProcessingDatabaseObjects:databaseObjects fileContents:fileContents]; return nil; }] subscribeCompleted:^{ NSLog(@"Done processing"); }]; ``` ### Simplifying collection transformations Higher-order functions like `map`, `filter`, `fold`/`reduce` are sorely missing from Foundation, leading to loop-focused code like this: ```objc NSMutableArray *results = [NSMutableArray array]; for (NSString *str in strings) { if (str.length < 2) { continue; } NSString *newString = [str stringByAppendingString:@"foobar"]; [results addObject:newString]; } ``` [RACSequence][] allows any Cocoa collection to be manipulated in a uniform and declarative way: ```objc RACSequence *results = [[strings.rac_sequence filter:^ BOOL (NSString *str) { return str.length >= 2; }] map:^(NSString *str) { return [str stringByAppendingString:@"foobar"]; }]; ``` ## System Requirements ReactiveCocoa supports OS X 10.8+ and iOS 8.0+. ## Importing ReactiveCocoa To add RAC to your application: 1. Add the ReactiveCocoa repository as a submodule of your application's repository. 1. Run `script/bootstrap` from within the ReactiveCocoa folder. 1. Drag and drop `ReactiveCocoa.xcodeproj` into your application's Xcode project or workspace. 1. On the "Build Phases" tab of your application target, add RAC to the "Link Binary With Libraries" phase. * **On iOS**, add `libReactiveCocoa-iOS.a`. * **On OS X**, add `ReactiveCocoa.framework`. RAC must also be added to any "Copy Frameworks" build phase. If you don't already have one, simply add a "Copy Files" build phase and target the "Frameworks" destination. 1. Add `"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/include" $(inherited)` to the "Header Search Paths" build setting (this is only necessary for archive builds, but it has no negative effect otherwise). 1. **For iOS targets**, add `-ObjC` to the "Other Linker Flags" build setting. 1. **If you added RAC to a project (not a workspace)**, you will also need to add the appropriate RAC target to the "Target Dependencies" of your application. If you would prefer to use [CocoaPods](http://cocoapods.org), there are some [ReactiveCocoa podspecs](https://github.com/CocoaPods/Specs/tree/master/Specs/ReactiveCocoa) that have been generously contributed by third parties. To see a project already set up with RAC, check out [C-41][] or [GroceryList][], which are real iOS apps written using ReactiveCocoa. ## More Info ReactiveCocoa is inspired by .NET's [Reactive Extensions](http://msdn.microsoft.com/en-us/data/gg577609) (Rx). Most of the principles of Rx apply to RAC as well. There are some really good Rx resources out there: * [Reactive Extensions MSDN entry](http://msdn.microsoft.com/en-us/library/hh242985.aspx) * [Reactive Extensions for .NET Introduction](http://leecampbell.blogspot.com/2010/08/reactive-extensions-for-net.html) * [Rx - Channel 9 videos](http://channel9.msdn.com/tags/Rx/) * [Reactive Extensions wiki](http://rxwiki.wikidot.com/) * [101 Rx Samples](http://rxwiki.wikidot.com/101samples) * [Programming Reactive Extensions and LINQ](http://www.amazon.com/Programming-Reactive-Extensions-Jesse-Liberty/dp/1430237473) RAC and Rx are both frameworks inspired by functional reactive programming. Here are some resources related to FRP: * [What is FRP? - Elm Language](http://elm-lang.org/learn/What-is-FRP.elm) * [What is Functional Reactive Programming - Stack Overflow](http://stackoverflow.com/questions/1028250/what-is-functional-reactive-programming/1030631#1030631) * [Specification for a Functional Reactive Language - Stack Overflow](http://stackoverflow.com/questions/5875929/specification-for-a-functional-reactive-programming-language#5878525) * [Escape from Callback Hell](http://elm-lang.org/learn/Escape-from-Callback-Hell.elm) * [Principles of Reactive Programming on Coursera](https://www.coursera.org/course/reactive) [README]: ../../README.md [Basic Operators]: BasicOperators.md [Framework Overview]: FrameworkOverview.md [Functional Reactive Programming]: http://en.wikipedia.org/wiki/Functional_reactive_programming [GroceryList]: https://github.com/jspahrsummers/GroceryList [RACSequence]: ../../ReactiveCocoa/Objective-C/RACSequence.h [RACSignal]: ../../ReactiveCocoa/Objective-C/RACSignal.h [futures and promises]: http://en.wikipedia.org/wiki/Futures_and_promises [C-41]: https://github.com/AshFurrow/C-41 ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Documentation/ObjectiveCBridging.md ================================================ # Objective-C Bridging While ReactiveCocoa 3.0 introduces an entirely new design, it also aims for maximum compatibility with RAC 2, to ease the pain of migration. To interoperate with RAC 2’s Objective-C APIs, RAC 3 offers bridging functions that can convert Objective-C types to Swift types and vice-versa. Because the APIs are based on fundamentally different designs, the conversion is not always one-to-one; however, every attempt has been made to faithfully translate the concepts between the two APIs (and languages). The bridged types include: 1. [`RACSignal` and `SignalProducer` or `Signal`](#racsignal-and-signalproducer-or-signal) 1. [`RACCommand` and `Action`](#raccommand-and-action) 1. [`RACScheduler` and `SchedulerType`](#racscheduler-and-schedulertype) 1. [`RACDisposable` and `Disposable`](#racdisposable-and-disposable) For the complete bridging API, including documentation, see [`ObjectiveCBridging.swift`][ObjectiveCBridging]. To learn more about how to migrate between ReactiveCocoa 2 and 3, see the [CHANGELOG][]. ## `RACSignal` and `SignalProducer` or `Signal` In RAC 3, “cold” signals are represented by the `SignalProducer` type, and “hot” signals are represented by the `Signal` type. “Cold” `RACSignal`s can be converted into `SignalProducer`s using the new `toSignalProducer` method: ```swift extension RACSignal { func toSignalProducer() -> SignalProducer } ``` “Hot” `RACSignal`s cannot be directly converted into `Signal`s, because _any_ `RACSignal` subscription could potentially involve side effects. To obtain a `Signal`, use `RACSignal.toSignalProducer` followed by `SignalProducer.start`, which will make those potential side effects explicit. For the other direction, use the `toRACSignal()` function. When called with a `SignalProducer`, these functions will create a `RACSignal` to `start()` the producer once for each subscription: ```swift func toRACSignal(producer: SignalProducer) -> RACSignal func toRACSignal(producer: SignalProducer) -> RACSignal ``` When called with a `Signal`, these functions will create a `RACSignal` that simply observes it: ```swift func toRACSignal(signal: Signal) -> RACSignal func toRACSignal(signal: Signal) -> RACSignal ``` ## `RACCommand` and `Action` To convert `RACCommand`s into the new `Action` type, use the `toAction()` extension method: ```swift extension RACCommand { func toAction() -> Action } ``` To convert `Action`s into `RACCommand`s, use the `toRACCommand()` function: ```swift func toRACCommand(action: Action) -> RACCommand func toRACCommand(action: Action) -> RACCommand ``` **NOTE:** The `executing` properties of actions and commands are not synchronized across the API bridge. To ensure consistency, only observe the `executing` property from the base object (the one passed _into_ the bridge, not retrieved from it), so updates occur no matter which object is used for execution. ## `RACScheduler` and `SchedulerType` Any `RACScheduler` instance is automatically a `DateSchedulerType` (and therefore a `SchedulerType`), and can be passed directly into any function or method that expects one. Some (but not all) `SchedulerType`s from RAC 3 can be converted into `RACScheduler` instances, using the `toRACScheduler()` method: ```swift extension ImmediateScheduler { func toRACScheduler() -> RACScheduler } extension UIScheduler { func toRACScheduler() -> RACScheduler } extension QueueScheduler { func toRACScheduler() -> RACScheduler } ``` ## `RACDisposable` and `Disposable` Any `RACDisposable` instance is automatically a `Disposable`, and can be used directly anywhere a type conforming to `Disposable` is expected. Although there is no direct conversion from `Disposable` into `RACDisposable`, it is easy to do manually: ```swift let swiftDisposable: Disposable let objcDisposable = RACDisposable { swiftDisposable.dispose() } ``` [CHANGELOG]: ../CHANGELOG.md [ObjectiveCBridging]: ../ReactiveCocoa/Swift/ObjectiveCBridging.swift ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Documentation/README.md ================================================ This folder contains conceptual documentation and design guidelines that don't fit well on a single class or in any specific header file. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Instruments/README.md ================================================ This folder contains Instruments templates to make it easier to debug code using ReactiveCocoa. To get started with a template, simply double-click it. ### Signal Names The `name` property of `RACSignal` requires that the `RAC_DEBUG_SIGNAL_NAMES` environment variable be set, which means that you won't have access to meaningful names in Instruments by default. To add signal names, open your application's scheme in Xcode, select the Profile action, and add `RAC_DEBUG_SIGNAL_NAMES` with a value of `1` to the list of environment variables. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/LICENSE.md ================================================ **Copyright (c) 2012 - 2015, GitHub, Inc.** **All rights reserved.** 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. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/Logo/README.md ================================================ This folder contains brand assets. # Logo Four horizontal variations that include both the mark and the logotype. When using the logo in contexts where it's surrounded by other elements, leave a padding of about 10% of its height on each side. # Icon Four icon variations to be used on social media and other contexts where the horizontal logo wouldn't fit. # Colors Primary color: `#88CD79` Secondary color: `#41AD71` Tertiary color: `#4F6B97` ![](Palette.png) # Type Avenir Next, designed by Adrian Frutiger and Akira Kobayashi for Linotype. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/README.md ================================================ ![](Logo/header.png) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![GitHub release](https://img.shields.io/github/release/ReactiveCocoa/ReactiveCocoa.svg)](https://github.com/ReactiveCocoa/ReactiveCocoa/releases) ![Swift 2.1.1](https://img.shields.io/badge/Swift-2.1.1-orange.svg) ![platforms](https://img.shields.io/badge/platforms-iOS%20%7C%20OS%20X%20%7C%20watchOS%20%7C%20tvOS%20-lightgrey.svg) ReactiveCocoa (RAC) is a Cocoa framework inspired by [Functional Reactive Programming](https://en.wikipedia.org/wiki/Functional_reactive_programming). It provides APIs for composing and transforming **streams of values over time**. 1. [Introduction](#introduction) 1. [Example: online search](#example-online-search) 1. [Objective-C and Swift](#objective-c-and-swift) 1. [How does ReactiveCocoa relate to Rx?](#how-does-reactivecocoa-relate-to-rx) 1. [Getting started](#getting-started) If you’re already familiar with functional reactive programming or what ReactiveCocoa is about, check out the [Documentation][] folder for more in-depth information about how it all works. Then, dive straight into our [documentation comments][Code] for learning more about individual APIs. If you have a question, please see if any discussions in our [GitHub issues](https://github.com/ReactiveCocoa/ReactiveCocoa/issues?q=is%3Aissue+label%3Aquestion+) or [Stack Overflow](http://stackoverflow.com/questions/tagged/reactive-cocoa) have already answered it. If not, please feel free to [file your own](https://github.com/ReactiveCocoa/ReactiveCocoa/issues/new)! #### Compatibility This documents the RAC 4 (currently alpha) which targets Swift 2.x. For Swift 1.2 support see the [RAC 3](https://github.com/ReactiveCocoa/ReactiveCocoa/tree/v3.0.0). _Many thanks to [Rheinfabrik](http://www.rheinfabrik.de) for generously sponsoring the development of ReactiveCocoa 3!_ ## Introduction ReactiveCocoa is inspired by [functional reactive programming](http://blog.maybeapps.com/post/42894317939/input-and-output). Rather than using mutable variables which are replaced and modified in-place, RAC offers “event streams,” represented by the [`Signal`][Signals] and [`SignalProducer`][Signal producers] types, that send values over time. Event streams unify all of Cocoa’s common patterns for asynchrony and event handling, including: * Delegate methods * Callback blocks * `NSNotification`s * Control actions and responder chain events * [Futures and promises](https://en.wikipedia.org/wiki/Futures_and_promises) * [Key-value observing](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html) (KVO) Because all of these different mechanisms can be represented in the _same_ way, it’s easy to declaratively chain and combine them together, with less spaghetti code and state to bridge the gap. For more information about the concepts in ReactiveCocoa, see the [Framework Overview][]. ## Example: online search Let’s say you have a text field, and whenever the user types something into it, you want to make a network request which searches for that query. #### Observing text edits The first step is to observe edits to the text field, using a RAC extension to `UITextField` specifically for this purpose: ```swift let searchStrings = textField.rac_textSignal() .toSignalProducer() .map { text in text as! String } ``` This gives us a [signal producer][Signal producers] which sends values of type `String`. _(The cast is [currently necessary](https://github.com/ReactiveCocoa/ReactiveCocoa/issues/2182) to bridge this extension method from Objective-C.)_ #### Making network requests With each string, we want to execute a network request. Luckily, RAC offers an `NSURLSession` extension for doing exactly that: ```swift let searchResults = searchStrings .flatMap(.Latest) { (query: String) -> SignalProducer<(NSData, NSURLResponse), NSError> in let URLRequest = self.searchRequestWithEscapedQuery(query) return NSURLSession.sharedSession().rac_dataWithRequest(URLRequest) } .map { (data, URLResponse) -> String in let string = String(data: data, encoding: NSUTF8StringEncoding)! return self.parseJSONResultsFromString(string) } .observeOn(UIScheduler()) ``` This has transformed our producer of `String`s into a producer of `Array`s containing the search results, which will be forwarded on the main thread (thanks to the [`UIScheduler`][Schedulers]). Additionally, [`flatMap(.Latest)`][flatMapLatest] here ensures that _only one search_—the latest—is allowed to be running. If the user types another character while the network request is still in flight, it will be cancelled before starting a new one. Just think of how much code that would take to do by hand! #### Receiving the results This won’t actually execute yet, because producers must be _started_ in order to receive the results (which prevents doing work when the results are never used). That’s easy enough: ```swift searchResults.startWithNext { results in print("Search results: \(results)") } ``` Here, we watch for the `Next` [event][Events], which contains our results, and just log them to the console. This could easily do something else instead, like update a table view or a label on screen. #### Handling failures In this example so far, any network error will generate a `Failed` [event][Events], which will terminate the event stream. Unfortunately, this means that future queries won’t even be attempted. To remedy this, we need to decide what to do with failures that occur. The quickest solution would be to log them, then ignore them: ```swift .flatMap(.Latest) { (query: String) -> SignalProducer<(NSData, NSURLResponse), NSError> in let URLRequest = self.searchRequestWithEscapedQuery(query) return NSURLSession.sharedSession() .rac_dataWithRequest(URLRequest) .flatMapError { error in print("Network error occurred: \(error)") return SignalProducer.empty } } ``` By replacing failures with the `empty` event stream, we’re able to effectively ignore them. However, it’s probably more appropriate to retry at least a couple of times before giving up. Conveniently, there’s a [`retry`][retry] operator to do exactly that! Our improved `searchResults` producer might look like this: ```swift let searchResults = searchStrings .flatMap(.Latest) { (query: String) -> SignalProducer<(NSData, NSURLResponse), NSError> in let URLRequest = self.searchRequestWithEscapedQuery(query) return NSURLSession.sharedSession() .rac_dataWithRequest(URLRequest) .retry(2) .flatMapError { error in print("Network error occurred: \(error)") return SignalProducer.empty } } .map { (data, URLResponse) -> String in let string = String(data: data, encoding: NSUTF8StringEncoding)! return self.parseJSONResultsFromString(string) } .observeOn(UIScheduler()) ``` #### Throttling requests Now, let’s say you only want to actually perform the search when the user pauses typing, to minimize traffic. ReactiveCocoa has a declarative `throttle` operator that we can apply to our search strings: ```swift let searchStrings = textField.rac_textSignal() .toSignalProducer() .map { text in text as! String } .throttle(0.5, onScheduler: QueueScheduler.mainQueueScheduler) ``` This prevents values from being sent less than 0.5 seconds apart, so the user must stop editing for at least that long before we’ll use their search string. To do this manually would require significant state, and end up much harder to read! With ReactiveCocoa, we can use just one operator to incorporate _time_ into our event stream. ## Objective-C and Swift Although ReactiveCocoa was started as an Objective-C framework, as of [version 3.0][CHANGELOG], all major feature development is concentrated on the [Swift API][]. RAC’s [Objective-C API][] and Swift API are entirely separate, but there is a [bridge][Objective-C Bridging] to convert between the two. This is mostly meant as a compatibility layer for older ReactiveCocoa projects, or to use Cocoa extensions which haven’t been added to the Swift API yet. The Objective-C API will continue to exist and be supported for the foreseeable future, but it won’t receive many improvements. For more information about using this API, please consult our [legacy documentation][]. **We highly recommend that all new projects use the Swift API.** ## How does ReactiveCocoa relate to Rx? ReactiveCocoa was originally inspired, and therefore heavily influenced, by Microsoft’s [Reactive Extensions](https://msdn.microsoft.com/en-us/data/gg577609.aspx) (Rx) library. There are many ports of Rx, including [RxSwift](https://github.com/ReactiveX/RxSwift), but ReactiveCocoa is _intentionally_ not a direct port. **Where RAC differs from Rx**, it is usually to: * Create a simpler API * Address common sources of confusion * More closely match Cocoa conventions The following are some of the concrete differences, along with their rationales. ### Naming In most versions of Rx, Streams over time are known as `Observable`s, which parallels the `Enumerable` type in .NET. Additionally, most operations in Rx.NET borrow names from [LINQ](https://msdn.microsoft.com/en-us/library/bb397926.aspx), which uses terms reminiscent of relational databases, like `Select` and `Where`. **RAC is focused on matching Swift naming first and foremost**, with terms like `map` and `filter` instead. Other naming differences are typically inspired by significantly better alternatives from [Haskell](https://www.haskell.org) or [Elm](http://elm-lang.org) (which is the primary source for the “signal” terminology). ### Signals and Signal Producers (“hot” and “cold” observables) One of the most confusing aspects of Rx is that of [“hot”, “cold”, and “warm” observables](http://www.introtorx.com/content/v1.0.10621.0/14_HotAndColdObservables.html) (event streams). In short, given just a method or function declaration like this, in C#: ```csharp IObservable Search(string query) ``` … it is **impossible to tell** whether subscribing to (observing) that `IObservable` will involve side effects. If it _does_ involve side effects, it’s also impossible to tell whether _each subscription_ has a side effect, or if only the first one does. This example is contrived, but it demonstrates **a real, pervasive problem** that makes it extremely hard to understand Rx code (and pre-3.0 ReactiveCocoa code) at a glance. [ReactiveCocoa 3.0][CHANGELOG] has solved this problem by distinguishing side effects with the separate [`Signal`][Signals] and [`SignalProducer`][Signal producers] types. Although this means there’s another type to learn about, it improves code clarity and helps communicates intent much better. In other words, **ReactiveCocoa’s changes here are [simple, not easy](http://www.infoq.com/presentations/Simple-Made-Easy)**. ### Typed errors When [signals][] and [signal producers][] are allowed to [fail][Events] in ReactiveCocoa, the kind of error must be specified in the type system. For example, `Signal` is a signal of integer values that may fail with an error of type `NSError`. More importantly, RAC allows the special type `NoError` to be used instead, which _statically guarantees_ that an event stream is not allowed to send a failure. **This eliminates many bugs caused by unexpected failure events.** In Rx systems with types, event streams only specify the type of their values—not the type of their errors—so this sort of guarantee is impossible. ### UI programming Rx is basically agnostic as to how it’s used. Although UI programming with Rx is very common, it has few features tailored to that particular case. RAC takes a lot of inspiration from [ReactiveUI](http://reactiveui.net/), including the basis for [Actions][]. Unlike ReactiveUI, which unfortunately cannot directly change Rx to make it more friendly for UI programming, **ReactiveCocoa has been improved many times specifically for this purpose**—even when it means diverging further from Rx. ## Getting started ReactiveCocoa supports `OS X 10.9+`, `iOS 8.0+`, `watchOS 2.0`, and `tvOS 9.0`. To add RAC to your application: 1. Add the ReactiveCocoa repository as a [submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) of your application’s repository. 1. Run `script/bootstrap` from within the ReactiveCocoa folder. 1. Drag and drop `ReactiveCocoa.xcodeproj` and `Carthage/Checkouts/Result/Result.xcodeproj` into your application’s Xcode project or workspace. 1. On the “General” tab of your application target’s settings, add `ReactiveCocoa.framework` and `Result.framework` to the “Embedded Binaries” section. 1. If your application target does not contain Swift code at all, you should also set the `EMBEDDED_CONTENT_CONTAINS_SWIFT` build setting to “Yes”. Or, if you’re using [Carthage](https://github.com/Carthage/Carthage), simply add ReactiveCocoa to your `Cartfile`: ``` github "ReactiveCocoa/ReactiveCocoa" ``` Make sure to add both `ReactiveCocoa.framework` and `Result.framework` to "Linked Frameworks and Libraries" and "copy-frameworks" Build Phases. If you would prefer to use [CocoaPods](https://cocoapods.org), there are some [unofficial podspecs](https://github.com/CocoaPods/Specs/tree/master/Specs/ReactiveCocoa) that have been generously contributed by third parties. Once you’ve set up your project, check out the [Framework Overview][] for a tour of ReactiveCocoa’s concepts, and the [Basic Operators][] for some introductory examples of using it. [Actions]: Documentation/FrameworkOverview.md#actions [Basic Operators]: Documentation/BasicOperators.md [CHANGELOG]: CHANGELOG.md [Code]: ReactiveCocoa [Documentation]: Documentation [Events]: Documentation/FrameworkOverview.md#events [Framework Overview]: Documentation/FrameworkOverview.md [Legacy Documentation]: Documentation/Legacy [Objective-C API]: ReactiveCocoa/Objective-C [Objective-C Bridging]: Documentation/ObjectiveCBridging.md [Schedulers]: Documentation/FrameworkOverview.md#schedulers [Signal producers]: Documentation/FrameworkOverview.md#signal-producers [Signals]: Documentation/FrameworkOverview.md#signals [Swift API]: ReactiveCocoa/Swift [flatMapLatest]: Documentation/BasicOperators.md#switching-to-the-latest [retry]: Documentation/BasicOperators.md#retrying ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright Copyright © 2014 GitHub. All rights reserved. NSPrincipalClass ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/MKAnnotationView+RACSignalSupport.h ================================================ // // MKAnnotationView+RACSignalSupport.h // ReactiveCocoa // // Created by Zak Remer on 3/31/15. // Copyright (c) 2015 GitHub. All rights reserved. // #import #import @class RACSignal; @interface MKAnnotationView (RACSignalSupport) /// A signal which will send a RACUnit whenever -prepareForReuse is invoked upon /// the receiver. /// /// Examples /// /// [[[self.cancelButton /// rac_signalForControlEvents:UIControlEventTouchUpInside] /// takeUntil:self.rac_prepareForReuseSignal] /// subscribeNext:^(UIButton *x) { /// // do other things /// }]; @property (nonatomic, strong, readonly) RACSignal *rac_prepareForReuseSignal; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/MKAnnotationView+RACSignalSupport.m ================================================ // // MKAnnotationView+RACSignalSupport.m // ReactiveCocoa // // Created by Zak Remer on 3/31/15. // Copyright (c) 2015 GitHub. All rights reserved. // #import "MKAnnotationView+RACSignalSupport.h" #import "NSObject+RACDescription.h" #import "NSObject+RACSelectorSignal.h" #import "RACSignal+Operations.h" #import "RACUnit.h" #import @implementation MKAnnotationView (RACSignalSupport) - (RACSignal *)rac_prepareForReuseSignal { RACSignal *signal = objc_getAssociatedObject(self, _cmd); if (signal != nil) return signal; signal = [[[self rac_signalForSelector:@selector(prepareForReuse)] mapReplace:RACUnit.defaultUnit] setNameWithFormat:@"%@ -rac_prepareForReuseSignal", RACDescription(self)]; objc_setAssociatedObject(self, _cmd, signal, OBJC_ASSOCIATION_RETAIN_NONATOMIC); return signal; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSArray+RACSequenceAdditions.h ================================================ // // NSArray+RACSequenceAdditions.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import @class RACSequence; @interface NSArray (RACSequenceAdditions) /// Creates and returns a sequence corresponding to the receiver. /// /// Mutating the receiver will not affect the sequence after it's been created. @property (nonatomic, copy, readonly) RACSequence *rac_sequence; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSArray+RACSequenceAdditions.m ================================================ // // NSArray+RACSequenceAdditions.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import "NSArray+RACSequenceAdditions.h" #import "RACArraySequence.h" @implementation NSArray (RACSequenceAdditions) - (RACSequence *)rac_sequence { return [RACArraySequence sequenceWithArray:self offset:0]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSControl+RACCommandSupport.h ================================================ // // NSControl+RACCommandSupport.h // ReactiveCocoa // // Created by Josh Abernathy on 3/3/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import @class RACCommand; @interface NSControl (RACCommandSupport) /// Sets the control's command. When the control is clicked, the command is /// executed with the sender of the event. The control's enabledness is bound /// to the command's `canExecute`. /// /// Note: this will reset the control's target and action. @property (nonatomic, strong) RACCommand *rac_command; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSControl+RACCommandSupport.m ================================================ // // NSControl+RACCommandSupport.m // ReactiveCocoa // // Created by Josh Abernathy on 3/3/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "NSControl+RACCommandSupport.h" #import "RACCommand.h" #import "RACScopedDisposable.h" #import "RACSignal+Operations.h" #import static void *NSControlRACCommandKey = &NSControlRACCommandKey; static void *NSControlEnabledDisposableKey = &NSControlEnabledDisposableKey; @implementation NSControl (RACCommandSupport) - (RACCommand *)rac_command { return objc_getAssociatedObject(self, NSControlRACCommandKey); } - (void)setRac_command:(RACCommand *)command { objc_setAssociatedObject(self, NSControlRACCommandKey, command, OBJC_ASSOCIATION_RETAIN_NONATOMIC); // Tear down any previous binding before setting up our new one, or else we // might get assertion failures. [objc_getAssociatedObject(self, NSControlEnabledDisposableKey) dispose]; objc_setAssociatedObject(self, NSControlEnabledDisposableKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); if (command == nil) { self.enabled = YES; return; } [self rac_hijackActionAndTargetIfNeeded]; RACScopedDisposable *disposable = [[command.enabled setKeyPath:@"enabled" onObject:self] asScopedDisposable]; objc_setAssociatedObject(self, NSControlEnabledDisposableKey, disposable, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (void)rac_hijackActionAndTargetIfNeeded { SEL hijackSelector = @selector(rac_commandPerformAction:); if (self.target == self && self.action == hijackSelector) return; if (self.target != nil) NSLog(@"WARNING: NSControl.rac_command hijacks the control's existing target and action."); self.target = self; self.action = hijackSelector; } - (void)rac_commandPerformAction:(id)sender { [self.rac_command execute:sender]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSControl+RACTextSignalSupport.h ================================================ // // NSControl+RACTextSignalSupport.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-03-08. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACSignal; @interface NSControl (RACTextSignalSupport) /// Observes a text-based control for changes. /// /// Using this method on a control without editable text is considered undefined /// behavior. /// /// Returns a signal which sends the current string value of the receiver, then /// the new value any time it changes. - (RACSignal *)rac_textSignal; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSControl+RACTextSignalSupport.m ================================================ // // NSControl+RACTextSignalSupport.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-03-08. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "NSControl+RACTextSignalSupport.h" #import #import "NSObject+RACDescription.h" #import "RACDisposable.h" #import "RACSignal.h" #import "RACSubscriber.h" @implementation NSControl (RACTextSignalSupport) - (RACSignal *)rac_textSignal { @weakify(self); return [[[[RACSignal createSignal:^(id subscriber) { @strongify(self); id observer = [NSNotificationCenter.defaultCenter addObserverForName:NSControlTextDidChangeNotification object:self queue:nil usingBlock:^(NSNotification *note) { [subscriber sendNext:note.object]; }]; return [RACDisposable disposableWithBlock:^{ [NSNotificationCenter.defaultCenter removeObserver:observer]; }]; }] map:^(NSControl *control) { return [control.stringValue copy]; }] startWith:[self.stringValue copy]] setNameWithFormat:@"%@ -rac_textSignal", RACDescription(self)]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSData+RACSupport.h ================================================ // // NSData+RACSupport.h // ReactiveCocoa // // Created by Josh Abernathy on 5/11/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import @class RACScheduler; @class RACSignal; @interface NSData (RACSupport) // Read the data at the URL using -[NSData initWithContentsOfURL:options:error:]. // Sends the data or the error. // // scheduler - cannot be nil. + (RACSignal *)rac_readContentsOfURL:(NSURL *)URL options:(NSDataReadingOptions)options scheduler:(RACScheduler *)scheduler; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSData+RACSupport.m ================================================ // // NSData+RACSupport.m // ReactiveCocoa // // Created by Josh Abernathy on 5/11/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "NSData+RACSupport.h" #import "RACReplaySubject.h" #import "RACScheduler.h" @implementation NSData (RACSupport) + (RACSignal *)rac_readContentsOfURL:(NSURL *)URL options:(NSDataReadingOptions)options scheduler:(RACScheduler *)scheduler { NSCParameterAssert(scheduler != nil); RACReplaySubject *subject = [RACReplaySubject subject]; [subject setNameWithFormat:@"+rac_readContentsOfURL: %@ options: %lu scheduler: %@", URL, (unsigned long)options, scheduler]; [scheduler schedule:^{ NSError *error = nil; NSData *data = [[NSData alloc] initWithContentsOfURL:URL options:options error:&error]; if (data == nil) { [subject sendError:error]; } else { [subject sendNext:data]; [subject sendCompleted]; } }]; return subject; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSDictionary+RACSequenceAdditions.h ================================================ // // NSDictionary+RACSequenceAdditions.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import @class RACSequence; @interface NSDictionary (RACSequenceAdditions) /// Creates and returns a sequence of RACTuple key/value pairs. The key will be /// the first element in the tuple, and the value will be the second. /// /// Mutating the receiver will not affect the sequence after it's been created. @property (nonatomic, copy, readonly) RACSequence *rac_sequence; /// Creates and returns a sequence corresponding to the keys in the receiver. /// /// Mutating the receiver will not affect the sequence after it's been created. @property (nonatomic, copy, readonly) RACSequence *rac_keySequence; /// Creates and returns a sequence corresponding to the values in the receiver. /// /// Mutating the receiver will not affect the sequence after it's been created. @property (nonatomic, copy, readonly) RACSequence *rac_valueSequence; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSDictionary+RACSequenceAdditions.m ================================================ // // NSDictionary+RACSequenceAdditions.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import "NSDictionary+RACSequenceAdditions.h" #import "NSArray+RACSequenceAdditions.h" #import "RACSequence.h" #import "RACTuple.h" @implementation NSDictionary (RACSequenceAdditions) - (RACSequence *)rac_sequence { NSDictionary *immutableDict = [self copy]; // TODO: First class support for dictionary sequences. return [immutableDict.allKeys.rac_sequence map:^(id key) { id value = immutableDict[key]; return RACTuplePack(key, value); }]; } - (RACSequence *)rac_keySequence { return self.allKeys.rac_sequence; } - (RACSequence *)rac_valueSequence { return self.allValues.rac_sequence; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSEnumerator+RACSequenceAdditions.h ================================================ // // NSEnumerator+RACSequenceAdditions.h // ReactiveCocoa // // Created by Uri Baghin on 07/01/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACSequence; @interface NSEnumerator (RACSequenceAdditions) /// Creates and returns a sequence corresponding to the receiver. /// /// The receiver is exhausted lazily as the sequence is enumerated. @property (nonatomic, copy, readonly) RACSequence *rac_sequence; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSEnumerator+RACSequenceAdditions.m ================================================ // // NSEnumerator+RACSequenceAdditions.m // ReactiveCocoa // // Created by Uri Baghin on 07/01/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "NSEnumerator+RACSequenceAdditions.h" #import "RACSequence.h" @implementation NSEnumerator (RACSequenceAdditions) - (RACSequence *)rac_sequence { return [RACSequence sequenceWithHeadBlock:^{ return [self nextObject]; } tailBlock:^{ return self.rac_sequence; }]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSFileHandle+RACSupport.h ================================================ // // NSFileHandle+RACSupport.h // ReactiveCocoa // // Created by Josh Abernathy on 5/10/12. // Copyright (c) 2012 GitHub. All rights reserved. // #import @class RACSignal; @interface NSFileHandle (RACSupport) // Read any available data in the background and send it. Completes when data // length is <= 0. - (RACSignal *)rac_readInBackground; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSFileHandle+RACSupport.m ================================================ // // NSFileHandle+RACSupport.m // ReactiveCocoa // // Created by Josh Abernathy on 5/10/12. // Copyright (c) 2012 GitHub. All rights reserved. // #import "NSFileHandle+RACSupport.h" #import "NSNotificationCenter+RACSupport.h" #import "NSObject+RACDescription.h" #import "RACReplaySubject.h" #import "RACDisposable.h" @implementation NSFileHandle (RACSupport) - (RACSignal *)rac_readInBackground { RACReplaySubject *subject = [RACReplaySubject subject]; [subject setNameWithFormat:@"%@ -rac_readInBackground", RACDescription(self)]; RACSignal *dataNotification = [[[NSNotificationCenter defaultCenter] rac_addObserverForName:NSFileHandleReadCompletionNotification object:self] map:^(NSNotification *note) { return note.userInfo[NSFileHandleNotificationDataItem]; }]; __block RACDisposable *subscription = [dataNotification subscribeNext:^(NSData *data) { if (data.length > 0) { [subject sendNext:data]; [self readInBackgroundAndNotify]; } else { [subject sendCompleted]; [subscription dispose]; } }]; [self readInBackgroundAndNotify]; return subject; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSIndexSet+RACSequenceAdditions.h ================================================ // // NSIndexSet+RACSequenceAdditions.h // ReactiveCocoa // // Created by Sergey Gavrilyuk on 12/17/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACSequence; @interface NSIndexSet (RACSequenceAdditions) /// Creates and returns a sequence of indexes (as `NSNumber`s) corresponding to /// the receiver. /// /// Mutating the receiver will not affect the sequence after it's been created. @property (nonatomic, copy, readonly) RACSequence *rac_sequence; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSIndexSet+RACSequenceAdditions.m ================================================ // // NSIndexSet+RACSequenceAdditions.m // ReactiveCocoa // // Created by Sergey Gavrilyuk on 12/17/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "NSIndexSet+RACSequenceAdditions.h" #import "RACIndexSetSequence.h" @implementation NSIndexSet (RACSequenceAdditions) - (RACSequence *)rac_sequence { return [RACIndexSetSequence sequenceWithIndexSet:self]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSInvocation+RACTypeParsing.h ================================================ // // NSInvocation+RACTypeParsing.h // ReactiveCocoa // // Created by Josh Abernathy on 11/17/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import @class RACTuple; // A private category of methods to handle wrapping and unwrapping of values. @interface NSInvocation (RACTypeParsing) // Sets the argument for the invocation at the given index by unboxing the given // object based on the type signature of the argument. // // This does not support C arrays or unions. // // Note that calling this on a char * or const char * argument can cause all // arguments to be retained. // // object - The object to unbox and set as the argument. // index - The index of the argument to set. - (void)rac_setArgument:(id)object atIndex:(NSUInteger)index; // Gets the argument for the invocation at the given index based on the // invocation's method signature. The value is then wrapped in the appropriate // object type. // // This does not support C arrays or unions. // // index - The index of the argument to get. // // Returns the argument of the invocation, wrapped in an object. - (id)rac_argumentAtIndex:(NSUInteger)index; // Arguments tuple for the invocation. // // The arguments tuple excludes implicit variables `self` and `_cmd`. // // See -rac_argumentAtIndex: and -rac_setArgumentAtIndex: for further // description of the underlying behavior. @property (nonatomic, copy) RACTuple *rac_argumentsTuple; // Gets the return value from the invocation based on the invocation's method // signature. The value is then wrapped in the appropriate object type. // // This does not support C arrays or unions. // // Returns the return value of the invocation, wrapped in an object. Voids are // returned as `RACUnit.defaultUnit`. - (id)rac_returnValue; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSInvocation+RACTypeParsing.m ================================================ // // NSInvocation+RACTypeParsing.m // ReactiveCocoa // // Created by Josh Abernathy on 11/17/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "NSInvocation+RACTypeParsing.h" #import "RACTuple.h" #import "RACUnit.h" #import @implementation NSInvocation (RACTypeParsing) - (void)rac_setArgument:(id)object atIndex:(NSUInteger)index { #define PULL_AND_SET(type, selector) \ do { \ type val = [object selector]; \ [self setArgument:&val atIndex:(NSInteger)index]; \ } while (0) const char *argType = [self.methodSignature getArgumentTypeAtIndex:index]; // Skip const type qualifier. if (argType[0] == 'r') { argType++; } if (strcmp(argType, @encode(id)) == 0 || strcmp(argType, @encode(Class)) == 0) { [self setArgument:&object atIndex:(NSInteger)index]; } else if (strcmp(argType, @encode(char)) == 0) { PULL_AND_SET(char, charValue); } else if (strcmp(argType, @encode(int)) == 0) { PULL_AND_SET(int, intValue); } else if (strcmp(argType, @encode(short)) == 0) { PULL_AND_SET(short, shortValue); } else if (strcmp(argType, @encode(long)) == 0) { PULL_AND_SET(long, longValue); } else if (strcmp(argType, @encode(long long)) == 0) { PULL_AND_SET(long long, longLongValue); } else if (strcmp(argType, @encode(unsigned char)) == 0) { PULL_AND_SET(unsigned char, unsignedCharValue); } else if (strcmp(argType, @encode(unsigned int)) == 0) { PULL_AND_SET(unsigned int, unsignedIntValue); } else if (strcmp(argType, @encode(unsigned short)) == 0) { PULL_AND_SET(unsigned short, unsignedShortValue); } else if (strcmp(argType, @encode(unsigned long)) == 0) { PULL_AND_SET(unsigned long, unsignedLongValue); } else if (strcmp(argType, @encode(unsigned long long)) == 0) { PULL_AND_SET(unsigned long long, unsignedLongLongValue); } else if (strcmp(argType, @encode(float)) == 0) { PULL_AND_SET(float, floatValue); } else if (strcmp(argType, @encode(double)) == 0) { PULL_AND_SET(double, doubleValue); } else if (strcmp(argType, @encode(BOOL)) == 0) { PULL_AND_SET(BOOL, boolValue); } else if (strcmp(argType, @encode(char *)) == 0) { const char *cString = [object UTF8String]; [self setArgument:&cString atIndex:(NSInteger)index]; [self retainArguments]; } else if (strcmp(argType, @encode(void (^)(void))) == 0) { [self setArgument:&object atIndex:(NSInteger)index]; } else { NSCParameterAssert([object isKindOfClass:NSValue.class]); NSUInteger valueSize = 0; NSGetSizeAndAlignment([object objCType], &valueSize, NULL); #if DEBUG NSUInteger argSize = 0; NSGetSizeAndAlignment(argType, &argSize, NULL); NSCAssert(valueSize == argSize, @"Value size does not match argument size in -rac_setArgument: %@ atIndex: %lu", object, (unsigned long)index); #endif unsigned char valueBytes[valueSize]; [object getValue:valueBytes]; [self setArgument:valueBytes atIndex:(NSInteger)index]; } #undef PULL_AND_SET } - (id)rac_argumentAtIndex:(NSUInteger)index { #define WRAP_AND_RETURN(type) \ do { \ type val = 0; \ [self getArgument:&val atIndex:(NSInteger)index]; \ return @(val); \ } while (0) const char *argType = [self.methodSignature getArgumentTypeAtIndex:index]; // Skip const type qualifier. if (argType[0] == 'r') { argType++; } if (strcmp(argType, @encode(id)) == 0 || strcmp(argType, @encode(Class)) == 0) { __autoreleasing id returnObj; [self getArgument:&returnObj atIndex:(NSInteger)index]; return returnObj; } else if (strcmp(argType, @encode(char)) == 0) { WRAP_AND_RETURN(char); } else if (strcmp(argType, @encode(int)) == 0) { WRAP_AND_RETURN(int); } else if (strcmp(argType, @encode(short)) == 0) { WRAP_AND_RETURN(short); } else if (strcmp(argType, @encode(long)) == 0) { WRAP_AND_RETURN(long); } else if (strcmp(argType, @encode(long long)) == 0) { WRAP_AND_RETURN(long long); } else if (strcmp(argType, @encode(unsigned char)) == 0) { WRAP_AND_RETURN(unsigned char); } else if (strcmp(argType, @encode(unsigned int)) == 0) { WRAP_AND_RETURN(unsigned int); } else if (strcmp(argType, @encode(unsigned short)) == 0) { WRAP_AND_RETURN(unsigned short); } else if (strcmp(argType, @encode(unsigned long)) == 0) { WRAP_AND_RETURN(unsigned long); } else if (strcmp(argType, @encode(unsigned long long)) == 0) { WRAP_AND_RETURN(unsigned long long); } else if (strcmp(argType, @encode(float)) == 0) { WRAP_AND_RETURN(float); } else if (strcmp(argType, @encode(double)) == 0) { WRAP_AND_RETURN(double); } else if (strcmp(argType, @encode(BOOL)) == 0) { WRAP_AND_RETURN(BOOL); } else if (strcmp(argType, @encode(char *)) == 0) { WRAP_AND_RETURN(const char *); } else if (strcmp(argType, @encode(void (^)(void))) == 0) { __unsafe_unretained id block = nil; [self getArgument:&block atIndex:(NSInteger)index]; return [block copy]; } else { NSUInteger valueSize = 0; NSGetSizeAndAlignment(argType, &valueSize, NULL); unsigned char valueBytes[valueSize]; [self getArgument:valueBytes atIndex:(NSInteger)index]; return [NSValue valueWithBytes:valueBytes objCType:argType]; } return nil; #undef WRAP_AND_RETURN } - (RACTuple *)rac_argumentsTuple { NSUInteger numberOfArguments = self.methodSignature.numberOfArguments; NSMutableArray *argumentsArray = [NSMutableArray arrayWithCapacity:numberOfArguments - 2]; for (NSUInteger index = 2; index < numberOfArguments; index++) { [argumentsArray addObject:[self rac_argumentAtIndex:index] ?: RACTupleNil.tupleNil]; } return [RACTuple tupleWithObjectsFromArray:argumentsArray]; } - (void)setRac_argumentsTuple:(RACTuple *)arguments { NSCAssert(arguments.count == self.methodSignature.numberOfArguments - 2, @"Number of supplied arguments (%lu), does not match the number expected by the signature (%lu)", (unsigned long)arguments.count, (unsigned long)self.methodSignature.numberOfArguments - 2); NSUInteger index = 2; for (id arg in arguments) { [self rac_setArgument:(arg == RACTupleNil.tupleNil ? nil : arg) atIndex:index]; index++; } } - (id)rac_returnValue { #define WRAP_AND_RETURN(type) \ do { \ type val = 0; \ [self getReturnValue:&val]; \ return @(val); \ } while (0) const char *returnType = self.methodSignature.methodReturnType; // Skip const type qualifier. if (returnType[0] == 'r') { returnType++; } if (strcmp(returnType, @encode(id)) == 0 || strcmp(returnType, @encode(Class)) == 0 || strcmp(returnType, @encode(void (^)(void))) == 0) { __autoreleasing id returnObj; [self getReturnValue:&returnObj]; return returnObj; } else if (strcmp(returnType, @encode(char)) == 0) { WRAP_AND_RETURN(char); } else if (strcmp(returnType, @encode(int)) == 0) { WRAP_AND_RETURN(int); } else if (strcmp(returnType, @encode(short)) == 0) { WRAP_AND_RETURN(short); } else if (strcmp(returnType, @encode(long)) == 0) { WRAP_AND_RETURN(long); } else if (strcmp(returnType, @encode(long long)) == 0) { WRAP_AND_RETURN(long long); } else if (strcmp(returnType, @encode(unsigned char)) == 0) { WRAP_AND_RETURN(unsigned char); } else if (strcmp(returnType, @encode(unsigned int)) == 0) { WRAP_AND_RETURN(unsigned int); } else if (strcmp(returnType, @encode(unsigned short)) == 0) { WRAP_AND_RETURN(unsigned short); } else if (strcmp(returnType, @encode(unsigned long)) == 0) { WRAP_AND_RETURN(unsigned long); } else if (strcmp(returnType, @encode(unsigned long long)) == 0) { WRAP_AND_RETURN(unsigned long long); } else if (strcmp(returnType, @encode(float)) == 0) { WRAP_AND_RETURN(float); } else if (strcmp(returnType, @encode(double)) == 0) { WRAP_AND_RETURN(double); } else if (strcmp(returnType, @encode(BOOL)) == 0) { WRAP_AND_RETURN(BOOL); } else if (strcmp(returnType, @encode(char *)) == 0) { WRAP_AND_RETURN(const char *); } else if (strcmp(returnType, @encode(void)) == 0) { return RACUnit.defaultUnit; } else { NSUInteger valueSize = 0; NSGetSizeAndAlignment(returnType, &valueSize, NULL); unsigned char valueBytes[valueSize]; [self getReturnValue:valueBytes]; return [NSValue valueWithBytes:valueBytes objCType:returnType]; } return nil; #undef WRAP_AND_RETURN } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSNotificationCenter+RACSupport.h ================================================ // // NSNotificationCenter+RACSupport.h // ReactiveCocoa // // Created by Josh Abernathy on 5/10/12. // Copyright (c) 2012 GitHub. All rights reserved. // #import @class RACSignal; @interface NSNotificationCenter (RACSupport) // Sends the NSNotification every time the notification is posted. - (RACSignal *)rac_addObserverForName:(NSString *)notificationName object:(id)object; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSNotificationCenter+RACSupport.m ================================================ // // NSNotificationCenter+RACSupport.m // ReactiveCocoa // // Created by Josh Abernathy on 5/10/12. // Copyright (c) 2012 GitHub. All rights reserved. // #import "NSNotificationCenter+RACSupport.h" #import #import "RACSignal.h" #import "RACSubscriber.h" #import "RACDisposable.h" @implementation NSNotificationCenter (RACSupport) - (RACSignal *)rac_addObserverForName:(NSString *)notificationName object:(id)object { @unsafeify(object); return [[RACSignal createSignal:^(id subscriber) { @strongify(object); id observer = [self addObserverForName:notificationName object:object queue:nil usingBlock:^(NSNotification *note) { [subscriber sendNext:note]; }]; return [RACDisposable disposableWithBlock:^{ [self removeObserver:observer]; }]; }] setNameWithFormat:@"-rac_addObserverForName: %@ object: <%@: %p>", notificationName, [object class], object]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSObject+RACAppKitBindings.h ================================================ // // NSObject+RACAppKitBindings.h // ReactiveCocoa // // Created by Josh Abernathy on 4/17/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import @class RACChannelTerminal; @interface NSObject (RACAppKitBindings) /// Invokes -rac_channelToBinding:options: without any options. - (RACChannelTerminal *)rac_channelToBinding:(NSString *)binding; /// Applies a Cocoa binding to the receiver, then exposes a RACChannel-based /// interface for manipulating it. /// /// Creating two of the same bindings on the same object will result in undefined /// behavior. /// /// binding - The name of the binding. This must not be nil. /// options - Any options to pass to Cocoa Bindings. This may be nil. /// /// Returns a RACChannelTerminal which will send future values from the receiver, /// and update the receiver when values are sent to the terminal. - (RACChannelTerminal *)rac_channelToBinding:(NSString *)binding options:(NSDictionary *)options; @end @interface NSObject (RACUnavailableAppKitBindings) - (void)rac_bind:(NSString *)binding toObject:(id)object withKeyPath:(NSString *)keyPath __attribute__((unavailable("Use -rac_bind:options: instead"))); - (void)rac_bind:(NSString *)binding toObject:(id)object withKeyPath:(NSString *)keyPath nilValue:(id)nilValue __attribute__((unavailable("Use -rac_bind:options: instead"))); - (void)rac_bind:(NSString *)binding toObject:(id)object withKeyPath:(NSString *)keyPath transform:(id (^)(id value))transformBlock __attribute__((unavailable("Use -rac_bind:options: instead"))); - (void)rac_bind:(NSString *)binding toObject:(id)object withNegatedKeyPath:(NSString *)keyPath __attribute__((unavailable("Use -rac_bind:options: instead"))); @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSObject+RACAppKitBindings.m ================================================ // // NSObject+RACAppKitBindings.m // ReactiveCocoa // // Created by Josh Abernathy on 4/17/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "NSObject+RACAppKitBindings.h" #import #import #import "NSObject+RACDeallocating.h" #import "RACChannel.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACKVOChannel.h" #import "RACValueTransformer.h" #import // Used as an object to bind to, so we can hide the object creation and just // expose a RACChannel instead. @interface RACChannelProxy : NSObject // The RACChannel used for this Cocoa binding. @property (nonatomic, strong, readonly) RACChannel *channel; // The KVC- and KVO-compliant property to be read and written by the Cocoa // binding. // // This should not be set manually. @property (nonatomic, strong) id value; // The target of the Cocoa binding. // // This should be set to nil when the target deallocates. @property (atomic, unsafe_unretained) id target; // The name of the Cocoa binding used. @property (nonatomic, copy, readonly) NSString *bindingName; // Improves the performance of KVO on the receiver. // // See the documentation for for more information. @property (atomic, assign) void *observationInfo; // Initializes the receiver and binds to the given target. // // target - The target of the Cocoa binding. This must not be nil. // bindingName - The name of the Cocoa binding to use. This must not be nil. // options - Any options to pass to the binding. This may be nil. // // Returns an initialized channel proxy. - (id)initWithTarget:(id)target bindingName:(NSString *)bindingName options:(NSDictionary *)options; @end @implementation NSObject (RACAppKitBindings) - (RACChannelTerminal *)rac_channelToBinding:(NSString *)binding { return [self rac_channelToBinding:binding options:nil]; } - (RACChannelTerminal *)rac_channelToBinding:(NSString *)binding options:(NSDictionary *)options { NSCParameterAssert(binding != nil); RACChannelProxy *proxy = [[RACChannelProxy alloc] initWithTarget:self bindingName:binding options:options]; return proxy.channel.leadingTerminal; } @end @implementation RACChannelProxy #pragma mark Properties - (void)setValue:(id)value { [self willChangeValueForKey:@keypath(self.value)]; _value = value; [self didChangeValueForKey:@keypath(self.value)]; } #pragma mark Lifecycle - (id)initWithTarget:(id)target bindingName:(NSString *)bindingName options:(NSDictionary *)options { NSCParameterAssert(target != nil); NSCParameterAssert(bindingName != nil); self = [super init]; if (self == nil) return nil; _target = target; _bindingName = [bindingName copy]; _channel = [[RACChannel alloc] init]; @weakify(self); void (^cleanUp)() = ^{ @strongify(self); id target = self.target; if (target == nil) return; self.target = nil; [target unbind:bindingName]; objc_setAssociatedObject(target, (__bridge void *)self, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); }; // When the channel terminates, tear down this proxy. [self.channel.followingTerminal subscribeError:^(NSError *error) { cleanUp(); } completed:cleanUp]; [self.target bind:bindingName toObject:self withKeyPath:@keypath(self.value) options:options]; // Keep the proxy alive as long as the target, or until the property subject // terminates. objc_setAssociatedObject(self.target, (__bridge void *)self, self, OBJC_ASSOCIATION_RETAIN_NONATOMIC); [[self.target rac_deallocDisposable] addDisposable:[RACDisposable disposableWithBlock:^{ @strongify(self); [self.channel.followingTerminal sendCompleted]; }]]; RACChannelTo(self, value, options[NSNullPlaceholderBindingOption]) = self.channel.followingTerminal; return self; } - (void)dealloc { [self.channel.followingTerminal sendCompleted]; } #pragma mark NSObject - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p>{ target: %@, binding: %@ }", self.class, self, self.target, self.bindingName]; } #pragma mark NSKeyValueObserving + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key { // Generating manual notifications for `value` is simpler and more // performant than having KVO swizzle our class and add its own logic. return NO; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSObject+RACDeallocating.h ================================================ // // NSObject+RACDeallocating.h // ReactiveCocoa // // Created by Kazuo Koga on 2013/03/15. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACCompoundDisposable; @class RACDisposable; @class RACSignal; @interface NSObject (RACDeallocating) /// The compound disposable which will be disposed of when the receiver is /// deallocated. @property (atomic, readonly, strong) RACCompoundDisposable *rac_deallocDisposable; /// Returns a signal that will complete immediately before the receiver is fully /// deallocated. If already deallocated when the signal is subscribed to, /// a `completed` event will be sent immediately. - (RACSignal *)rac_willDeallocSignal; @end @interface NSObject (RACUnavailableDeallocating) - (RACSignal *)rac_didDeallocSignal __attribute__((unavailable("Use -rac_willDeallocSignal"))); - (void)rac_addDeallocDisposable:(RACDisposable *)disposable __attribute__((unavailable("Add disposables to -rac_deallocDisposable instead"))); @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSObject+RACDeallocating.m ================================================ // // NSObject+RACDeallocating.m // ReactiveCocoa // // Created by Kazuo Koga on 2013/03/15. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "NSObject+RACDeallocating.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACReplaySubject.h" #import #import static const void *RACObjectCompoundDisposable = &RACObjectCompoundDisposable; static NSMutableSet *swizzledClasses() { static dispatch_once_t onceToken; static NSMutableSet *swizzledClasses = nil; dispatch_once(&onceToken, ^{ swizzledClasses = [[NSMutableSet alloc] init]; }); return swizzledClasses; } static void swizzleDeallocIfNeeded(Class classToSwizzle) { @synchronized (swizzledClasses()) { NSString *className = NSStringFromClass(classToSwizzle); if ([swizzledClasses() containsObject:className]) return; SEL deallocSelector = sel_registerName("dealloc"); __block void (*originalDealloc)(__unsafe_unretained id, SEL) = NULL; id newDealloc = ^(__unsafe_unretained id self) { RACCompoundDisposable *compoundDisposable = objc_getAssociatedObject(self, RACObjectCompoundDisposable); [compoundDisposable dispose]; if (originalDealloc == NULL) { struct objc_super superInfo = { .receiver = self, .super_class = class_getSuperclass(classToSwizzle) }; void (*msgSend)(struct objc_super *, SEL) = (__typeof__(msgSend))objc_msgSendSuper; msgSend(&superInfo, deallocSelector); } else { originalDealloc(self, deallocSelector); } }; IMP newDeallocIMP = imp_implementationWithBlock(newDealloc); if (!class_addMethod(classToSwizzle, deallocSelector, newDeallocIMP, "v@:")) { // The class already contains a method implementation. Method deallocMethod = class_getInstanceMethod(classToSwizzle, deallocSelector); // We need to store original implementation before setting new implementation // in case method is called at the time of setting. originalDealloc = (__typeof__(originalDealloc))method_getImplementation(deallocMethod); // We need to store original implementation again, in case it just changed. originalDealloc = (__typeof__(originalDealloc))method_setImplementation(deallocMethod, newDeallocIMP); } [swizzledClasses() addObject:className]; } } @implementation NSObject (RACDeallocating) - (RACSignal *)rac_willDeallocSignal { RACSignal *signal = objc_getAssociatedObject(self, _cmd); if (signal != nil) return signal; RACReplaySubject *subject = [RACReplaySubject subject]; [self.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ [subject sendCompleted]; }]]; objc_setAssociatedObject(self, _cmd, subject, OBJC_ASSOCIATION_RETAIN); return subject; } - (RACCompoundDisposable *)rac_deallocDisposable { @synchronized (self) { RACCompoundDisposable *compoundDisposable = objc_getAssociatedObject(self, RACObjectCompoundDisposable); if (compoundDisposable != nil) return compoundDisposable; swizzleDeallocIfNeeded(self.class); compoundDisposable = [RACCompoundDisposable compoundDisposable]; objc_setAssociatedObject(self, RACObjectCompoundDisposable, compoundDisposable, OBJC_ASSOCIATION_RETAIN_NONATOMIC); return compoundDisposable; } } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSObject+RACDescription.h ================================================ // // NSObject+RACDescription.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-05-13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import // A simplified description of the object, which does not invoke -description // (and thus should be much faster in many cases). // // This is for debugging purposes only, and will return a constant string // unless the RAC_DEBUG_SIGNAL_NAMES environment variable is set. NSString *RACDescription(id object); ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSObject+RACDescription.m ================================================ // // NSObject+RACDescription.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-05-13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "NSObject+RACDescription.h" #import "RACTuple.h" @implementation NSValue (RACDescription) - (NSString *)rac_description { return self.description; } @end @implementation NSString (RACDescription) - (NSString *)rac_description { return self.description; } @end @implementation RACTuple (RACDescription) - (NSString *)rac_description { if (getenv("RAC_DEBUG_SIGNAL_NAMES") != NULL) { return self.allObjects.description; } else { return @"(description skipped)"; } } @end NSString *RACDescription(id object) { if (getenv("RAC_DEBUG_SIGNAL_NAMES") != NULL) { if ([object respondsToSelector:@selector(rac_description)]) { return [object rac_description]; } else { return [[NSString alloc] initWithFormat:@"<%@: %p>", [object class], object]; } } else { return @"(description skipped)"; } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSObject+RACKVOWrapper.h ================================================ // // NSObject+RACKVOWrapper.h // ReactiveCocoa // // Created by Josh Abernathy on 10/11/11. // Copyright (c) 2011 GitHub. All rights reserved. // #import @class RACDisposable; @class RACKVOTrampoline; // A private category providing a block based interface to KVO. @interface NSObject (RACKVOWrapper) // Adds the given block as the callbacks for when the key path changes. // // Unlike direct KVO observation, this handles deallocation of `weak` properties // by generating an appropriate notification. This will only occur if there is // an `@property` declaration visible in the observed class, with the `weak` // memory management attribute. // // The observation does not need to be explicitly removed. It will be removed // when the observer or the receiver deallocate. // // keyPath - The key path to observe. Must not be nil. // options - The KVO observation options. // observer - The object that requested the observation. May be nil. // block - The block called when the value at the key path changes. It is // passed the current value of the key path and the extended KVO // change dictionary including RAC-specific keys and values. Must not // be nil. // // Returns a disposable that can be used to stop the observation. - (RACDisposable *)rac_observeKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)observer block:(void (^)(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent))block; @end typedef void (^RACKVOBlock)(id target, id observer, NSDictionary *change); @interface NSObject (RACUnavailableKVOWrapper) - (RACKVOTrampoline *)rac_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block __attribute((unavailable("Use rac_observeKeyPath:options:observer:block: instead."))); @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSObject+RACKVOWrapper.m ================================================ // // NSObject+RACKVOWrapper.m // ReactiveCocoa // // Created by Josh Abernathy on 10/11/11. // Copyright (c) 2011 GitHub. All rights reserved. // #import "NSObject+RACKVOWrapper.h" #import #import #import "NSObject+RACDeallocating.h" #import "NSString+RACKeyPathUtilities.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACKVOTrampoline.h" #import "RACSerialDisposable.h" @implementation NSObject (RACKVOWrapper) - (RACDisposable *)rac_observeKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)weakObserver block:(void (^)(id, NSDictionary *, BOOL, BOOL))block { NSCParameterAssert(block != nil); NSCParameterAssert(keyPath.rac_keyPathComponents.count > 0); keyPath = [keyPath copy]; NSObject *strongObserver = weakObserver; NSArray *keyPathComponents = keyPath.rac_keyPathComponents; BOOL keyPathHasOneComponent = (keyPathComponents.count == 1); NSString *keyPathHead = keyPathComponents[0]; NSString *keyPathTail = keyPath.rac_keyPathByDeletingFirstKeyPathComponent; RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable]; // The disposable that groups all disposal necessary to clean up the callbacks // added to the value of the first key path component. RACSerialDisposable *firstComponentSerialDisposable = [RACSerialDisposable serialDisposableWithDisposable:[RACCompoundDisposable compoundDisposable]]; RACCompoundDisposable * (^firstComponentDisposable)(void) = ^{ return (RACCompoundDisposable *)firstComponentSerialDisposable.disposable; }; [disposable addDisposable:firstComponentSerialDisposable]; BOOL shouldAddDeallocObserver = NO; objc_property_t property = class_getProperty(object_getClass(self), keyPathHead.UTF8String); if (property != NULL) { rac_propertyAttributes *attributes = rac_copyPropertyAttributes(property); if (attributes != NULL) { @onExit { free(attributes); }; BOOL isObject = attributes->objectClass != nil || strstr(attributes->type, @encode(id)) == attributes->type; BOOL isProtocol = attributes->objectClass == NSClassFromString(@"Protocol"); BOOL isBlock = strcmp(attributes->type, @encode(void(^)())) == 0; BOOL isWeak = attributes->weak; // If this property isn't actually an object (or is a Class object), // no point in observing the deallocation of the wrapper returned by // KVC. // // If this property is an object, but not declared `weak`, we // don't need to watch for it spontaneously being set to nil. // // Attempting to observe non-weak properties will result in // broken behavior for dynamic getters, so don't even try. shouldAddDeallocObserver = isObject && isWeak && !isBlock && !isProtocol; } } // Adds the callback block to the value's deallocation. Also adds the logic to // clean up the callback to the firstComponentDisposable. void (^addDeallocObserverToPropertyValue)(NSObject *) = ^(NSObject *value) { if (!shouldAddDeallocObserver) return; // If a key path value is the observer, commonly when a key path begins // with "self", we prevent deallocation triggered callbacks for any such key // path components. Thus, the observer's deallocation is not considered a // change to the key path. if (value == weakObserver) return; NSDictionary *change = @{ NSKeyValueChangeKindKey: @(NSKeyValueChangeSetting), NSKeyValueChangeNewKey: NSNull.null, }; RACCompoundDisposable *valueDisposable = value.rac_deallocDisposable; RACDisposable *deallocDisposable = [RACDisposable disposableWithBlock:^{ block(nil, change, YES, keyPathHasOneComponent); }]; [valueDisposable addDisposable:deallocDisposable]; [firstComponentDisposable() addDisposable:[RACDisposable disposableWithBlock:^{ [valueDisposable removeDisposable:deallocDisposable]; }]]; }; // Adds the callback block to the remaining path components on the value. Also // adds the logic to clean up the callbacks to the firstComponentDisposable. void (^addObserverToValue)(NSObject *) = ^(NSObject *value) { RACDisposable *observerDisposable = [value rac_observeKeyPath:keyPathTail options:(options & ~NSKeyValueObservingOptionInitial) observer:weakObserver block:block]; [firstComponentDisposable() addDisposable:observerDisposable]; }; // Observe only the first key path component, when the value changes clean up // the callbacks on the old value, add callbacks to the new value and call the // callback block as needed. // // Note this does not use NSKeyValueObservingOptionInitial so this only // handles changes to the value, callbacks to the initial value must be added // separately. NSKeyValueObservingOptions trampolineOptions = (options | NSKeyValueObservingOptionPrior) & ~NSKeyValueObservingOptionInitial; RACKVOTrampoline *trampoline = [[RACKVOTrampoline alloc] initWithTarget:self observer:strongObserver keyPath:keyPathHead options:trampolineOptions block:^(id trampolineTarget, id trampolineObserver, NSDictionary *change) { // If this is a prior notification, clean up all the callbacks added to the // previous value and call the callback block. Everything else is deferred // until after we get the notification after the change. if ([change[NSKeyValueChangeNotificationIsPriorKey] boolValue]) { [firstComponentDisposable() dispose]; if ((options & NSKeyValueObservingOptionPrior) != 0) { block([trampolineTarget valueForKeyPath:keyPath], change, NO, keyPathHasOneComponent); } return; } // From here the notification is not prior. NSObject *value = [trampolineTarget valueForKey:keyPathHead]; // If the value has changed but is nil, there is no need to add callbacks to // it, just call the callback block. if (value == nil) { block(nil, change, NO, keyPathHasOneComponent); return; } // From here the notification is not prior and the value is not nil. // Create a new firstComponentDisposable while getting rid of the old one at // the same time, in case this is being called concurrently. RACDisposable *oldFirstComponentDisposable = [firstComponentSerialDisposable swapInDisposable:[RACCompoundDisposable compoundDisposable]]; [oldFirstComponentDisposable dispose]; addDeallocObserverToPropertyValue(value); // If there are no further key path components, there is no need to add the // other callbacks, just call the callback block with the value itself. if (keyPathHasOneComponent) { block(value, change, NO, keyPathHasOneComponent); return; } // The value has changed, is not nil, and there are more key path components // to consider. Add the callbacks to the value for the remaining key path // components and call the callback block with the current value of the full // key path. addObserverToValue(value); block([value valueForKeyPath:keyPathTail], change, NO, keyPathHasOneComponent); }]; // Stop the KVO observation when this one is disposed of. [disposable addDisposable:trampoline]; // Add the callbacks to the initial value if needed. NSObject *value = [self valueForKey:keyPathHead]; if (value != nil) { addDeallocObserverToPropertyValue(value); if (!keyPathHasOneComponent) { addObserverToValue(value); } } // Call the block with the initial value if needed. if ((options & NSKeyValueObservingOptionInitial) != 0) { id initialValue = [self valueForKeyPath:keyPath]; NSDictionary *initialChange = @{ NSKeyValueChangeKindKey: @(NSKeyValueChangeSetting), NSKeyValueChangeNewKey: initialValue ?: NSNull.null, }; block(initialValue, initialChange, NO, keyPathHasOneComponent); } RACCompoundDisposable *observerDisposable = strongObserver.rac_deallocDisposable; RACCompoundDisposable *selfDisposable = self.rac_deallocDisposable; // Dispose of this observation if the receiver or the observer deallocate. [observerDisposable addDisposable:disposable]; [selfDisposable addDisposable:disposable]; return [RACDisposable disposableWithBlock:^{ [disposable dispose]; [observerDisposable removeDisposable:disposable]; [selfDisposable removeDisposable:disposable]; }]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSObject+RACLifting.h ================================================ // // NSObject+RACLifting.h // ReactiveCocoa // // Created by Josh Abernathy on 10/13/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import @class RACSignal; @interface NSObject (RACLifting) /// Lifts the selector on the receiver into the reactive world. The selector will /// be invoked whenever any signal argument sends a value, but only after each /// signal has sent an initial value. /// /// It will replay the most recently sent value to new subscribers. /// /// This does not support C arrays or unions. /// /// selector - The selector on self to invoke. /// firstSignal - The signal corresponding to the first method argument. This /// must not be nil. /// ... - A list of RACSignals corresponding to the remaining arguments. /// There must be a non-nil signal for each method argument. /// /// Examples /// /// [button rac_liftSelector:@selector(setTitleColor:forState:) withSignals:textColorSignal, [RACSignal return:@(UIControlStateNormal)], nil]; /// /// Returns a signal which sends the return value from each invocation of the /// selector. If the selector returns void, it instead sends RACUnit.defaultUnit. /// It completes only after all the signal arguments complete. - (RACSignal *)rac_liftSelector:(SEL)selector withSignals:(RACSignal *)firstSignal, ... NS_REQUIRES_NIL_TERMINATION; /// Like -rac_liftSelector:withSignals:, but accepts an array instead of /// a variadic list of arguments. - (RACSignal *)rac_liftSelector:(SEL)selector withSignalsFromArray:(NSArray *)signals; /// Like -rac_liftSelector:withSignals:, but accepts a signal sending tuples of /// arguments instead of a variadic list of arguments. - (RACSignal *)rac_liftSelector:(SEL)selector withSignalOfArguments:(RACSignal *)arguments; @end @interface NSObject (RACUnavailableLifting) - (RACSignal *)rac_liftSelector:(SEL)selector withObjects:(id)arg, ... __attribute__((unavailable("Use -rac_liftSelector:withSignals: instead"))); - (RACSignal *)rac_liftSelector:(SEL)selector withObjectsFromArray:(NSArray *)args __attribute__((unavailable("Use -rac_liftSelector:withSignalsFromArray: instead"))); - (RACSignal *)rac_liftBlock:(id)block withArguments:(id)arg, ... NS_REQUIRES_NIL_TERMINATION __attribute__((unavailable("Use +combineLatest:reduce: instead"))); - (RACSignal *)rac_liftBlock:(id)block withArgumentsFromArray:(NSArray *)args __attribute__((unavailable("Use +combineLatest:reduce: instead"))); - (instancetype)rac_lift __attribute__((unavailable("Use -rac_liftSelector:withSignals: instead"))); @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSObject+RACLifting.m ================================================ // // NSObject+RACLifting.m // ReactiveCocoa // // Created by Josh Abernathy on 10/13/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "NSObject+RACLifting.h" #import #import "NSInvocation+RACTypeParsing.h" #import "NSObject+RACDeallocating.h" #import "NSObject+RACDescription.h" #import "RACSignal+Operations.h" #import "RACTuple.h" @implementation NSObject (RACLifting) - (RACSignal *)rac_liftSelector:(SEL)selector withSignalOfArguments:(RACSignal *)arguments { NSCParameterAssert(selector != NULL); NSCParameterAssert(arguments != nil); @unsafeify(self); NSMethodSignature *methodSignature = [self methodSignatureForSelector:selector]; NSCAssert(methodSignature != nil, @"%@ does not respond to %@", self, NSStringFromSelector(selector)); return [[[[arguments takeUntil:self.rac_willDeallocSignal] map:^(RACTuple *arguments) { @strongify(self); NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; invocation.selector = selector; invocation.rac_argumentsTuple = arguments; [invocation invokeWithTarget:self]; return invocation.rac_returnValue; }] replayLast] setNameWithFormat:@"%@ -rac_liftSelector: %s withSignalsOfArguments: %@", RACDescription(self), sel_getName(selector), arguments]; } - (RACSignal *)rac_liftSelector:(SEL)selector withSignalsFromArray:(NSArray *)signals { NSCParameterAssert(signals != nil); NSCParameterAssert(signals.count > 0); NSMethodSignature *methodSignature = [self methodSignatureForSelector:selector]; NSCAssert(methodSignature != nil, @"%@ does not respond to %@", self, NSStringFromSelector(selector)); NSUInteger numberOfArguments __attribute__((unused)) = methodSignature.numberOfArguments - 2; NSCAssert(numberOfArguments == signals.count, @"Wrong number of signals for %@ (expected %lu, got %lu)", NSStringFromSelector(selector), (unsigned long)numberOfArguments, (unsigned long)signals.count); return [[self rac_liftSelector:selector withSignalOfArguments:[RACSignal combineLatest:signals]] setNameWithFormat:@"%@ -rac_liftSelector: %s withSignalsFromArray: %@", RACDescription(self), sel_getName(selector), signals]; } - (RACSignal *)rac_liftSelector:(SEL)selector withSignals:(RACSignal *)firstSignal, ... { NSCParameterAssert(firstSignal != nil); NSMutableArray *signals = [NSMutableArray array]; va_list args; va_start(args, firstSignal); for (id currentSignal = firstSignal; currentSignal != nil; currentSignal = va_arg(args, id)) { NSCAssert([currentSignal isKindOfClass:RACSignal.class], @"Argument %@ is not a RACSignal", currentSignal); [signals addObject:currentSignal]; } va_end(args); return [[self rac_liftSelector:selector withSignalsFromArray:signals] setNameWithFormat:@"%@ -rac_liftSelector: %s withSignals: %@", RACDescription(self), sel_getName(selector), signals]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSObject+RACPropertySubscribing.h ================================================ // // NSObject+RACPropertySubscribing.h // ReactiveCocoa // // Created by Josh Abernathy on 3/2/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "metamacros.h" /// Creates a signal which observes `KEYPATH` on `TARGET` for changes. /// /// In either case, the observation continues until `TARGET` _or self_ is /// deallocated. If any intermediate object is deallocated instead, it will be /// assumed to have been set to nil. /// /// Make sure to `@strongify(self)` when using this macro within a block! The /// macro will _always_ reference `self`, which can silently introduce a retain /// cycle within a block. As a result, you should make sure that `self` is a weak /// reference (e.g., created by `@weakify` and `@strongify`) before the /// expression that uses `RACObserve`. /// /// Examples /// /// // Observes self, and doesn't stop until self is deallocated. /// RACSignal *selfSignal = RACObserve(self, arrayController.items); /// /// // Observes the array controller, and stops when self _or_ the array /// // controller is deallocated. /// RACSignal *arrayControllerSignal = RACObserve(self.arrayController, items); /// /// // Observes obj.arrayController, and stops when self _or_ the array /// // controller is deallocated. /// RACSignal *signal2 = RACObserve(obj.arrayController, items); /// /// @weakify(self); /// RACSignal *signal3 = [anotherSignal flattenMap:^(NSArrayController *arrayController) { /// // Avoids a retain cycle because of RACObserve implicitly referencing /// // self. /// @strongify(self); /// return RACObserve(arrayController, items); /// }]; /// /// Returns a signal which sends the current value of the key path on /// subscription, then sends the new value every time it changes, and sends /// completed if self or observer is deallocated. #define RACObserve(TARGET, KEYPATH) \ ({ \ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wreceiver-is-weak\"") \ __weak id target_ = (TARGET); \ [target_ rac_valuesForKeyPath:@keypath(TARGET, KEYPATH) observer:self]; \ _Pragma("clang diagnostic pop") \ }) @class RACDisposable; @class RACSignal; @interface NSObject (RACPropertySubscribing) /// Creates a signal to observe the value at the given key path. /// /// The initial value is sent on subscription, the subsequent values are sent /// from whichever thread the change occured on, even if it doesn't have a valid /// scheduler. /// /// Returns a signal that immediately sends the receiver's current value at the /// given keypath, then any changes thereafter. #if OS_OBJECT_HAVE_OBJC_SUPPORT - (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(__weak NSObject *)observer; #else // Swift builds with OS_OBJECT_HAVE_OBJC_SUPPORT=0 for Playgrounds and LLDB :( - (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(NSObject *)observer; #endif /// Creates a signal to observe the changes of the given key path. /// /// The initial value is sent on subscription if `NSKeyValueObservingOptionInitial` is set. /// The subsequent values are sent from whichever thread the change occured on, /// even if it doesn't have a valid scheduler. /// /// Returns a signal that sends tuples containing the current value at the key /// path and the change dictionary for each KVO callback. #if OS_OBJECT_HAVE_OBJC_SUPPORT - (RACSignal *)rac_valuesAndChangesForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)observer; #else - (RACSignal *)rac_valuesAndChangesForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(NSObject *)observer; #endif @end #define RACAble(...) \ metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__)) \ (_RACAbleObject(self, __VA_ARGS__)) \ (_RACAbleObject(__VA_ARGS__)) #define _RACAbleObject(object, property) [object rac_signalForKeyPath:@keypath(object, property) observer:self] #define RACAbleWithStart(...) \ metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__)) \ (_RACAbleWithStartObject(self, __VA_ARGS__)) \ (_RACAbleWithStartObject(__VA_ARGS__)) #define _RACAbleWithStartObject(object, property) [object rac_signalWithStartingValueForKeyPath:@keypath(object, property) observer:self] @interface NSObject (RACUnavailablePropertySubscribing) + (RACSignal *)rac_signalFor:(NSObject *)object keyPath:(NSString *)keyPath observer:(NSObject *)observer __attribute__((unavailable("Use -rac_valuesForKeyPath:observer: or RACObserve() instead."))); + (RACSignal *)rac_signalWithStartingValueFor:(NSObject *)object keyPath:(NSString *)keyPath observer:(NSObject *)observer __attribute__((unavailable("Use -rac_valuesForKeyPath:observer: or RACObserve() instead."))); + (RACSignal *)rac_signalWithChangesFor:(NSObject *)object keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(NSObject *)observer __attribute__((unavailable("Use -rac_valuesAndChangesForKeyPath:options:observer: instead."))); - (RACSignal *)rac_signalForKeyPath:(NSString *)keyPath observer:(NSObject *)observer __attribute__((unavailable("Use -rac_valuesForKeyPath:observer: or RACObserve() instead."))); - (RACSignal *)rac_signalWithStartingValueForKeyPath:(NSString *)keyPath observer:(NSObject *)observer __attribute__((unavailable("Use -rac_valuesForKeyPath:observer: or RACObserve() instead."))); - (RACDisposable *)rac_deriveProperty:(NSString *)keyPath from:(RACSignal *)signal __attribute__((unavailable("Use -[RACSignal setKeyPath:onObject:] instead"))); @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSObject+RACPropertySubscribing.m ================================================ // // NSObject+RACPropertySubscribing.m // ReactiveCocoa // // Created by Josh Abernathy on 3/2/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "NSObject+RACPropertySubscribing.h" #import #import "NSObject+RACDeallocating.h" #import "NSObject+RACDescription.h" #import "NSObject+RACKVOWrapper.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACKVOTrampoline.h" #import "RACSubscriber.h" #import "RACSignal+Operations.h" #import "RACTuple.h" #import @implementation NSObject (RACPropertySubscribing) - (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(__weak NSObject *)observer { return [[[self rac_valuesAndChangesForKeyPath:keyPath options:NSKeyValueObservingOptionInitial observer:observer] map:^(RACTuple *value) { // -map: because it doesn't require the block trampoline that -reduceEach: uses return value[0]; }] setNameWithFormat:@"RACObserve(%@, %@)", RACDescription(self), keyPath]; } - (RACSignal *)rac_valuesAndChangesForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)weakObserver { NSObject *strongObserver = weakObserver; keyPath = [keyPath copy]; NSRecursiveLock *objectLock = [[NSRecursiveLock alloc] init]; objectLock.name = @"org.reactivecocoa.ReactiveCocoa.NSObjectRACPropertySubscribing"; __weak NSObject *weakSelf = self; RACSignal *deallocSignal = [[RACSignal zip:@[ self.rac_willDeallocSignal, strongObserver.rac_willDeallocSignal ?: [RACSignal never] ]] doCompleted:^{ // Forces deallocation to wait if the object variables are currently // being read on another thread. [objectLock lock]; @onExit { [objectLock unlock]; }; }]; return [[[RACSignal createSignal:^ RACDisposable * (id subscriber) { // Hold onto the lock the whole time we're setting up the KVO // observation, because any resurrection that might be caused by our // retaining below must be balanced out by the time -dealloc returns // (if another thread is waiting on the lock above). [objectLock lock]; @onExit { [objectLock unlock]; }; __strong NSObject *observer __attribute__((objc_precise_lifetime)) = weakObserver; __strong NSObject *self __attribute__((objc_precise_lifetime)) = weakSelf; if (self == nil) { [subscriber sendCompleted]; return nil; } return [self rac_observeKeyPath:keyPath options:options observer:observer block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { [subscriber sendNext:RACTuplePack(value, change)]; }]; }] takeUntil:deallocSignal] setNameWithFormat:@"%@ -rac_valueAndChangesForKeyPath: %@ options: %lu observer: %@", RACDescription(self), keyPath, (unsigned long)options, RACDescription(strongObserver)]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSObject+RACSelectorSignal.h ================================================ // // NSObject+RACSelectorSignal.h // ReactiveCocoa // // Created by Josh Abernathy on 3/18/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACSignal; /// The domain for any errors originating from -rac_signalForSelector:. extern NSString * const RACSelectorSignalErrorDomain; /// -rac_signalForSelector: was going to add a new method implementation for /// `selector`, but another thread added an implementation before it was able to. /// /// This will _not_ occur for cases where a method implementation exists before /// -rac_signalForSelector: is invoked. extern const NSInteger RACSelectorSignalErrorMethodSwizzlingRace; @interface NSObject (RACSelectorSignal) /// Creates a signal associated with the receiver, which will send a tuple of the /// method's arguments each time the given selector is invoked. /// /// If the selector is already implemented on the receiver, the existing /// implementation will be invoked _before_ the signal fires. /// /// If the selector is not yet implemented on the receiver, the injected /// implementation will have a `void` return type and accept only object /// arguments. Invoking the added implementation with non-object values, or /// expecting a return value, will result in undefined behavior. /// /// This is useful for changing an event or delegate callback into a signal. For /// example, on an NSView: /// /// [[view rac_signalForSelector:@selector(mouseDown:)] subscribeNext:^(RACTuple *args) { /// NSEvent *event = args.first; /// NSLog(@"mouse button pressed: %@", event); /// }]; /// /// selector - The selector for whose invocations are to be observed. If it /// doesn't exist, it will be implemented to accept object arguments /// and return void. This cannot have C arrays or unions as arguments /// or C arrays, unions, structs, complex or vector types as return /// type. /// /// Returns a signal which will send a tuple of arguments upon each invocation of /// the selector, then completes when the receiver is deallocated. `next` events /// will be sent synchronously from the thread that invoked the method. If /// a runtime call fails, the signal will send an error in the /// RACSelectorSignalErrorDomain. - (RACSignal *)rac_signalForSelector:(SEL)selector; /// Behaves like -rac_signalForSelector:, but if the selector is not yet /// implemented on the receiver, its method signature is looked up within /// `protocol`, and may accept non-object arguments. /// /// If the selector is not yet implemented and has a return value, the injected /// method will return all zero bits (equal to `nil`, `NULL`, 0, 0.0f, etc.). /// /// selector - The selector for whose invocations are to be observed. If it /// doesn't exist, it will be implemented using information from /// `protocol`, and may accept non-object arguments and return /// a value. This cannot have C arrays or unions as arguments or /// return type. /// protocol - The protocol in which `selector` is declared. This will be used /// for type information if the selector is not already implemented on /// the receiver. This must not be `NULL`, and `selector` must exist /// in this protocol. /// /// Returns a signal which will send a tuple of arguments on each invocation of /// the selector, or an error in RACSelectorSignalErrorDomain if a runtime /// call fails. - (RACSignal *)rac_signalForSelector:(SEL)selector fromProtocol:(Protocol *)protocol; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSObject+RACSelectorSignal.m ================================================ // // NSObject+RACSelectorSignal.m // ReactiveCocoa // // Created by Josh Abernathy on 3/18/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "NSObject+RACSelectorSignal.h" #import #import "NSInvocation+RACTypeParsing.h" #import "NSObject+RACDeallocating.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACObjCRuntime.h" #import "RACSubject.h" #import "RACTuple.h" #import "NSObject+RACDescription.h" #import #import NSString * const RACSelectorSignalErrorDomain = @"RACSelectorSignalErrorDomain"; const NSInteger RACSelectorSignalErrorMethodSwizzlingRace = 1; static NSString * const RACSignalForSelectorAliasPrefix = @"rac_alias_"; static NSString * const RACSubclassSuffix = @"_RACSelectorSignal"; static void *RACSubclassAssociationKey = &RACSubclassAssociationKey; static NSMutableSet *swizzledClasses() { static NSMutableSet *set; static dispatch_once_t pred; dispatch_once(&pred, ^{ set = [[NSMutableSet alloc] init]; }); return set; } @implementation NSObject (RACSelectorSignal) static BOOL RACForwardInvocation(id self, NSInvocation *invocation) { SEL aliasSelector = RACAliasForSelector(invocation.selector); RACSubject *subject = objc_getAssociatedObject(self, aliasSelector); Class class = object_getClass(invocation.target); BOOL respondsToAlias = [class instancesRespondToSelector:aliasSelector]; if (respondsToAlias) { invocation.selector = aliasSelector; [invocation invoke]; } if (subject == nil) return respondsToAlias; [subject sendNext:invocation.rac_argumentsTuple]; return YES; } static void RACSwizzleForwardInvocation(Class class) { SEL forwardInvocationSEL = @selector(forwardInvocation:); Method forwardInvocationMethod = class_getInstanceMethod(class, forwardInvocationSEL); // Preserve any existing implementation of -forwardInvocation:. void (*originalForwardInvocation)(id, SEL, NSInvocation *) = NULL; if (forwardInvocationMethod != NULL) { originalForwardInvocation = (__typeof__(originalForwardInvocation))method_getImplementation(forwardInvocationMethod); } // Set up a new version of -forwardInvocation:. // // If the selector has been passed to -rac_signalForSelector:, invoke // the aliased method, and forward the arguments to any attached signals. // // If the selector has not been passed to -rac_signalForSelector:, // invoke any existing implementation of -forwardInvocation:. If there // was no existing implementation, throw an unrecognized selector // exception. id newForwardInvocation = ^(id self, NSInvocation *invocation) { BOOL matched = RACForwardInvocation(self, invocation); if (matched) return; if (originalForwardInvocation == NULL) { [self doesNotRecognizeSelector:invocation.selector]; } else { originalForwardInvocation(self, forwardInvocationSEL, invocation); } }; class_replaceMethod(class, forwardInvocationSEL, imp_implementationWithBlock(newForwardInvocation), "v@:@"); } static void RACSwizzleRespondsToSelector(Class class) { SEL respondsToSelectorSEL = @selector(respondsToSelector:); // Preserve existing implementation of -respondsToSelector:. Method respondsToSelectorMethod = class_getInstanceMethod(class, respondsToSelectorSEL); BOOL (*originalRespondsToSelector)(id, SEL, SEL) = (__typeof__(originalRespondsToSelector))method_getImplementation(respondsToSelectorMethod); // Set up a new version of -respondsToSelector: that returns YES for methods // added by -rac_signalForSelector:. // // If the selector has a method defined on the receiver's actual class, and // if that method's implementation is _objc_msgForward, then returns whether // the instance has a signal for the selector. // Otherwise, call the original -respondsToSelector:. id newRespondsToSelector = ^ BOOL (id self, SEL selector) { Method method = rac_getImmediateInstanceMethod(class, selector); if (method != NULL && method_getImplementation(method) == _objc_msgForward) { SEL aliasSelector = RACAliasForSelector(selector); if (objc_getAssociatedObject(self, aliasSelector) != nil) return YES; } return originalRespondsToSelector(self, respondsToSelectorSEL, selector); }; class_replaceMethod(class, respondsToSelectorSEL, imp_implementationWithBlock(newRespondsToSelector), method_getTypeEncoding(respondsToSelectorMethod)); } static void RACSwizzleGetClass(Class class, Class statedClass) { SEL selector = @selector(class); Method method = class_getInstanceMethod(class, selector); IMP newIMP = imp_implementationWithBlock(^(id self) { return statedClass; }); class_replaceMethod(class, selector, newIMP, method_getTypeEncoding(method)); } static void RACSwizzleMethodSignatureForSelector(Class class) { IMP newIMP = imp_implementationWithBlock(^(id self, SEL selector) { // Don't send the -class message to the receiver because we've changed // that to return the original class. Class actualClass = object_getClass(self); Method method = class_getInstanceMethod(actualClass, selector); if (method == NULL) { // Messages that the original class dynamically implements fall // here. // // Call the original class' -methodSignatureForSelector:. struct objc_super target = { .super_class = class_getSuperclass(class), .receiver = self, }; NSMethodSignature * (*messageSend)(struct objc_super *, SEL, SEL) = (__typeof__(messageSend))objc_msgSendSuper; return messageSend(&target, @selector(methodSignatureForSelector:), selector); } char const *encoding = method_getTypeEncoding(method); return [NSMethodSignature signatureWithObjCTypes:encoding]; }); SEL selector = @selector(methodSignatureForSelector:); Method methodSignatureForSelectorMethod = class_getInstanceMethod(class, selector); class_replaceMethod(class, selector, newIMP, method_getTypeEncoding(methodSignatureForSelectorMethod)); } // It's hard to tell which struct return types use _objc_msgForward, and // which use _objc_msgForward_stret instead, so just exclude all struct, array, // union, complex and vector return types. static void RACCheckTypeEncoding(const char *typeEncoding) { #if !NS_BLOCK_ASSERTIONS // Some types, including vector types, are not encoded. In these cases the // signature starts with the size of the argument frame. NSCAssert(*typeEncoding < '1' || *typeEncoding > '9', @"unknown method return type not supported in type encoding: %s", typeEncoding); NSCAssert(strstr(typeEncoding, "(") != typeEncoding, @"union method return type not supported"); NSCAssert(strstr(typeEncoding, "{") != typeEncoding, @"struct method return type not supported"); NSCAssert(strstr(typeEncoding, "[") != typeEncoding, @"array method return type not supported"); NSCAssert(strstr(typeEncoding, @encode(_Complex float)) != typeEncoding, @"complex float method return type not supported"); NSCAssert(strstr(typeEncoding, @encode(_Complex double)) != typeEncoding, @"complex double method return type not supported"); NSCAssert(strstr(typeEncoding, @encode(_Complex long double)) != typeEncoding, @"complex long double method return type not supported"); #endif // !NS_BLOCK_ASSERTIONS } static RACSignal *NSObjectRACSignalForSelector(NSObject *self, SEL selector, Protocol *protocol) { SEL aliasSelector = RACAliasForSelector(selector); @synchronized (self) { RACSubject *subject = objc_getAssociatedObject(self, aliasSelector); if (subject != nil) return subject; Class class = RACSwizzleClass(self); NSCAssert(class != nil, @"Could not swizzle class of %@", self); subject = [[RACSubject subject] setNameWithFormat:@"%@ -rac_signalForSelector: %s", RACDescription(self), sel_getName(selector)]; objc_setAssociatedObject(self, aliasSelector, subject, OBJC_ASSOCIATION_RETAIN); [self.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ [subject sendCompleted]; }]]; Method targetMethod = class_getInstanceMethod(class, selector); if (targetMethod == NULL) { const char *typeEncoding; if (protocol == NULL) { typeEncoding = RACSignatureForUndefinedSelector(selector); } else { // Look for the selector as an optional instance method. struct objc_method_description methodDescription = protocol_getMethodDescription(protocol, selector, NO, YES); if (methodDescription.name == NULL) { // Then fall back to looking for a required instance // method. methodDescription = protocol_getMethodDescription(protocol, selector, YES, YES); NSCAssert(methodDescription.name != NULL, @"Selector %@ does not exist in <%s>", NSStringFromSelector(selector), protocol_getName(protocol)); } typeEncoding = methodDescription.types; } RACCheckTypeEncoding(typeEncoding); // Define the selector to call -forwardInvocation:. if (!class_addMethod(class, selector, _objc_msgForward, typeEncoding)) { NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedString(@"A race condition occurred implementing %@ on class %@", nil), NSStringFromSelector(selector), class], NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Invoke -rac_signalForSelector: again to override the implementation.", nil) }; return [RACSignal error:[NSError errorWithDomain:RACSelectorSignalErrorDomain code:RACSelectorSignalErrorMethodSwizzlingRace userInfo:userInfo]]; } } else if (method_getImplementation(targetMethod) != _objc_msgForward) { // Make a method alias for the existing method implementation. const char *typeEncoding = method_getTypeEncoding(targetMethod); RACCheckTypeEncoding(typeEncoding); BOOL addedAlias __attribute__((unused)) = class_addMethod(class, aliasSelector, method_getImplementation(targetMethod), typeEncoding); NSCAssert(addedAlias, @"Original implementation for %@ is already copied to %@ on %@", NSStringFromSelector(selector), NSStringFromSelector(aliasSelector), class); // Redefine the selector to call -forwardInvocation:. class_replaceMethod(class, selector, _objc_msgForward, method_getTypeEncoding(targetMethod)); } return subject; } } static SEL RACAliasForSelector(SEL originalSelector) { NSString *selectorName = NSStringFromSelector(originalSelector); return NSSelectorFromString([RACSignalForSelectorAliasPrefix stringByAppendingString:selectorName]); } static const char *RACSignatureForUndefinedSelector(SEL selector) { const char *name = sel_getName(selector); NSMutableString *signature = [NSMutableString stringWithString:@"v@:"]; while ((name = strchr(name, ':')) != NULL) { [signature appendString:@"@"]; name++; } return signature.UTF8String; } static Class RACSwizzleClass(NSObject *self) { Class statedClass = self.class; Class baseClass = object_getClass(self); // The "known dynamic subclass" is the subclass generated by RAC. // It's stored as an associated object on every instance that's already // been swizzled, so that even if something else swizzles the class of // this instance, we can still access the RAC generated subclass. Class knownDynamicSubclass = objc_getAssociatedObject(self, RACSubclassAssociationKey); if (knownDynamicSubclass != Nil) return knownDynamicSubclass; NSString *className = NSStringFromClass(baseClass); if (statedClass != baseClass) { // If the class is already lying about what it is, it's probably a KVO // dynamic subclass or something else that we shouldn't subclass // ourselves. // // Just swizzle -forwardInvocation: in-place. Since the object's class // was almost certainly dynamically changed, we shouldn't see another of // these classes in the hierarchy. // // Additionally, swizzle -respondsToSelector: because the default // implementation may be ignorant of methods added to this class. @synchronized (swizzledClasses()) { if (![swizzledClasses() containsObject:className]) { RACSwizzleForwardInvocation(baseClass); RACSwizzleRespondsToSelector(baseClass); RACSwizzleGetClass(baseClass, statedClass); RACSwizzleGetClass(object_getClass(baseClass), statedClass); RACSwizzleMethodSignatureForSelector(baseClass); [swizzledClasses() addObject:className]; } } return baseClass; } const char *subclassName = [className stringByAppendingString:RACSubclassSuffix].UTF8String; Class subclass = objc_getClass(subclassName); if (subclass == nil) { subclass = [RACObjCRuntime createClass:subclassName inheritingFromClass:baseClass]; if (subclass == nil) return nil; RACSwizzleForwardInvocation(subclass); RACSwizzleRespondsToSelector(subclass); RACSwizzleGetClass(subclass, statedClass); RACSwizzleGetClass(object_getClass(subclass), statedClass); RACSwizzleMethodSignatureForSelector(subclass); objc_registerClassPair(subclass); } object_setClass(self, subclass); objc_setAssociatedObject(self, RACSubclassAssociationKey, subclass, OBJC_ASSOCIATION_ASSIGN); return subclass; } - (RACSignal *)rac_signalForSelector:(SEL)selector { NSCParameterAssert(selector != NULL); return NSObjectRACSignalForSelector(self, selector, NULL); } - (RACSignal *)rac_signalForSelector:(SEL)selector fromProtocol:(Protocol *)protocol { NSCParameterAssert(selector != NULL); NSCParameterAssert(protocol != NULL); return NSObjectRACSignalForSelector(self, selector, protocol); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSOrderedSet+RACSequenceAdditions.h ================================================ // // NSOrderedSet+RACSequenceAdditions.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import @class RACSequence; @interface NSOrderedSet (RACSequenceAdditions) /// Creates and returns a sequence corresponding to the receiver. /// /// Mutating the receiver will not affect the sequence after it's been created. @property (nonatomic, copy, readonly) RACSequence *rac_sequence; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSOrderedSet+RACSequenceAdditions.m ================================================ // // NSOrderedSet+RACSequenceAdditions.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import "NSOrderedSet+RACSequenceAdditions.h" #import "NSArray+RACSequenceAdditions.h" @implementation NSOrderedSet (RACSequenceAdditions) - (RACSequence *)rac_sequence { // TODO: First class support for ordered set sequences. return self.array.rac_sequence; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSSet+RACSequenceAdditions.h ================================================ // // NSSet+RACSequenceAdditions.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import @class RACSequence; @interface NSSet (RACSequenceAdditions) /// Creates and returns a sequence corresponding to the receiver. /// /// Mutating the receiver will not affect the sequence after it's been created. @property (nonatomic, copy, readonly) RACSequence *rac_sequence; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSSet+RACSequenceAdditions.m ================================================ // // NSSet+RACSequenceAdditions.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import "NSSet+RACSequenceAdditions.h" #import "NSArray+RACSequenceAdditions.h" @implementation NSSet (RACSequenceAdditions) - (RACSequence *)rac_sequence { // TODO: First class support for set sequences. return self.allObjects.rac_sequence; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSString+RACKeyPathUtilities.h ================================================ // // NSString+RACKeyPathUtilities.h // ReactiveCocoa // // Created by Uri Baghin on 05/05/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import // A private category of methods to extract parts of a key path. @interface NSString (RACKeyPathUtilities) // Returns an array of the components of the receiver. // // Calling this method on a string that isn't a key path is considered undefined // behavior. - (NSArray *)rac_keyPathComponents; // Returns a key path with all the components of the receiver except for the // last one. // // Calling this method on a string that isn't a key path is considered undefined // behavior. - (NSString *)rac_keyPathByDeletingLastKeyPathComponent; // Returns a key path with all the components of the receiver expect for the // first one. // // Calling this method on a string that isn't a key path is considered undefined // behavior. - (NSString *)rac_keyPathByDeletingFirstKeyPathComponent; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSString+RACKeyPathUtilities.m ================================================ // // NSString+RACKeyPathUtilities.m // ReactiveCocoa // // Created by Uri Baghin on 05/05/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "NSString+RACKeyPathUtilities.h" @implementation NSString (RACKeyPathUtilities) - (NSArray *)rac_keyPathComponents { if (self.length == 0) { return nil; } return [self componentsSeparatedByString:@"."]; } - (NSString *)rac_keyPathByDeletingLastKeyPathComponent { NSUInteger lastDotIndex = [self rangeOfString:@"." options:NSBackwardsSearch].location; if (lastDotIndex == NSNotFound) { return nil; } return [self substringToIndex:lastDotIndex]; } - (NSString *)rac_keyPathByDeletingFirstKeyPathComponent { NSUInteger firstDotIndex = [self rangeOfString:@"."].location; if (firstDotIndex == NSNotFound) { return nil; } return [self substringFromIndex:firstDotIndex + 1]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSString+RACSequenceAdditions.h ================================================ // // NSString+RACSequenceAdditions.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import @class RACSequence; @interface NSString (RACSequenceAdditions) /// Creates and returns a sequence containing strings corresponding to each /// composed character sequence in the receiver. /// /// Mutating the receiver will not affect the sequence after it's been created. @property (nonatomic, copy, readonly) RACSequence *rac_sequence; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSString+RACSequenceAdditions.m ================================================ // // NSString+RACSequenceAdditions.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import "NSString+RACSequenceAdditions.h" #import "RACStringSequence.h" @implementation NSString (RACSequenceAdditions) - (RACSequence *)rac_sequence { return [RACStringSequence sequenceWithString:self offset:0]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSString+RACSupport.h ================================================ // // NSString+RACSupport.h // ReactiveCocoa // // Created by Josh Abernathy on 5/11/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import @class RACScheduler; @class RACSignal; @interface NSString (RACSupport) // Reads in the contents of the file using +[NSString stringWithContentsOfURL:usedEncoding:error:]. // Note that encoding won't be valid until the signal completes successfully. // // scheduler - cannot be nil. + (RACSignal *)rac_readContentsOfURL:(NSURL *)URL usedEncoding:(NSStringEncoding *)encoding scheduler:(RACScheduler *)scheduler; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSString+RACSupport.m ================================================ // // NSString+RACSupport.m // ReactiveCocoa // // Created by Josh Abernathy on 5/11/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "NSString+RACSupport.h" #import "RACReplaySubject.h" #import "RACScheduler.h" @implementation NSString (RACSupport) + (RACSignal *)rac_readContentsOfURL:(NSURL *)URL usedEncoding:(NSStringEncoding *)encoding scheduler:(RACScheduler *)scheduler { NSCParameterAssert(scheduler != nil); RACReplaySubject *subject = [RACReplaySubject subject]; [subject setNameWithFormat:@"+rac_readContentsOfURL: %@ usedEncoding:scheduler: %@", URL, scheduler]; [scheduler schedule:^{ NSError *error = nil; NSString *string = [NSString stringWithContentsOfURL:URL usedEncoding:encoding error:&error]; if (string == nil) { [subject sendError:error]; } else { [subject sendNext:string]; [subject sendCompleted]; } }]; return subject; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSText+RACSignalSupport.h ================================================ // // NSText+RACSignalSupport.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-03-08. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACSignal; @interface NSText (RACSignalSupport) /// Returns a signal which sends the current `string` of the receiver, then the /// new value any time it changes. - (RACSignal *)rac_textSignal; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSText+RACSignalSupport.m ================================================ // // NSText+RACSignalSupport.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-03-08. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "NSText+RACSignalSupport.h" #import #import "NSObject+RACDescription.h" #import "RACDisposable.h" #import "RACSignal.h" #import "RACSubscriber.h" @implementation NSText (RACSignalSupport) - (RACSignal *)rac_textSignal { @unsafeify(self); return [[[[RACSignal createSignal:^(id subscriber) { @strongify(self); id observer = [NSNotificationCenter.defaultCenter addObserverForName:NSTextDidChangeNotification object:self queue:nil usingBlock:^(NSNotification *note) { [subscriber sendNext:note.object]; }]; return [RACDisposable disposableWithBlock:^{ [NSNotificationCenter.defaultCenter removeObserver:observer]; }]; }] map:^(NSText *text) { return [text.string copy]; }] startWith:[self.string copy]] setNameWithFormat:@"%@ -rac_textSignal", RACDescription(self)]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSURLConnection+RACSupport.h ================================================ // // NSURLConnection+RACSupport.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-10-01. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACSignal; @interface NSURLConnection (RACSupport) // Lazily loads data for the given request in the background. // // request - The URL request to load. This must not be nil. // // Returns a signal which will begin loading the request upon each subscription, // then send a `RACTuple` of the received `NSURLResponse` and downloaded // `NSData`, and complete on a background thread. If any errors occur, the // returned signal will error out. + (RACSignal *)rac_sendAsynchronousRequest:(NSURLRequest *)request; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSURLConnection+RACSupport.m ================================================ // // NSURLConnection+RACSupport.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-10-01. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "NSURLConnection+RACSupport.h" #import "RACDisposable.h" #import "RACSignal.h" #import "RACSubscriber.h" #import "RACTuple.h" @implementation NSURLConnection (RACSupport) + (RACSignal *)rac_sendAsynchronousRequest:(NSURLRequest *)request { NSCParameterAssert(request != nil); return [[RACSignal createSignal:^(id subscriber) { NSOperationQueue *queue = [[NSOperationQueue alloc] init]; queue.name = @"org.reactivecocoa.ReactiveCocoa.NSURLConnectionRACSupport"; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { // The docs say that `nil` data means an error occurred, but // `nil` responses can also occur in practice (circumstances // unknown). Consider either to be an error. // // Note that _empty_ data is not necessarily erroneous, as there // may be headers but no HTTP body. if (response == nil || data == nil) { [subscriber sendError:error]; } else { [subscriber sendNext:RACTuplePack(response, data)]; [subscriber sendCompleted]; } }]; #pragma clang diagnostic pop return [RACDisposable disposableWithBlock:^{ // It's not clear if this will actually cancel the connection, // but we can at least prevent _some_ unnecessary work -- // without writing all the code for a proper delegate, which // doesn't really belong in RAC. queue.suspended = YES; [queue cancelAllOperations]; }]; }] setNameWithFormat:@"+rac_sendAsynchronousRequest: %@", request]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSUserDefaults+RACSupport.h ================================================ // // NSUserDefaults+RACSupport.h // ReactiveCocoa // // Created by Matt Diephouse on 12/19/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACChannelTerminal; @interface NSUserDefaults (RACSupport) /// Creates and returns a terminal for binding the user defaults key. /// /// **Note:** The value in the user defaults is *asynchronously* updated with /// values sent to the channel. /// /// key - The user defaults key to create the channel terminal for. /// /// Returns a channel terminal that sends the value of the user defaults key /// upon subscription, sends an updated value whenever the default changes, and /// updates the default asynchronously with values it receives. - (RACChannelTerminal *)rac_channelTerminalForKey:(NSString *)key; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/NSUserDefaults+RACSupport.m ================================================ // // NSUserDefaults+RACSupport.m // ReactiveCocoa // // Created by Matt Diephouse on 12/19/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "NSUserDefaults+RACSupport.h" #import #import "NSNotificationCenter+RACSupport.h" #import "NSObject+RACDeallocating.h" #import "RACChannel.h" #import "RACScheduler.h" #import "RACSignal+Operations.h" @implementation NSUserDefaults (RACSupport) - (RACChannelTerminal *)rac_channelTerminalForKey:(NSString *)key { RACChannel *channel = [RACChannel new]; RACScheduler *scheduler = [RACScheduler scheduler]; __block BOOL ignoreNextValue = NO; @weakify(self); [[[[[[[NSNotificationCenter.defaultCenter rac_addObserverForName:NSUserDefaultsDidChangeNotification object:self] map:^(id _) { @strongify(self); return [self objectForKey:key]; }] startWith:[self objectForKey:key]] // Don't send values that were set on the other side of the terminal. filter:^ BOOL (id _) { if (RACScheduler.currentScheduler == scheduler && ignoreNextValue) { ignoreNextValue = NO; return NO; } return YES; }] distinctUntilChanged] takeUntil:self.rac_willDeallocSignal] subscribe:channel.leadingTerminal]; [[channel.leadingTerminal deliverOn:scheduler] subscribeNext:^(id value) { @strongify(self); ignoreNextValue = YES; [self setObject:value forKey:key]; }]; return channel.followingTerminal; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACArraySequence.h ================================================ // // RACArraySequence.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import "RACSequence.h" // Private class that adapts an array to the RACSequence interface. @interface RACArraySequence : RACSequence // Returns a sequence for enumerating over the given array, starting from the // given offset. The array will be copied to prevent mutation. + (instancetype)sequenceWithArray:(NSArray *)array offset:(NSUInteger)offset; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACArraySequence.m ================================================ // // RACArraySequence.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import "RACArraySequence.h" @interface RACArraySequence () // Redeclared from the superclass and marked deprecated to prevent using `array` // where `backingArray` is intended. @property (nonatomic, copy, readonly) NSArray *array __attribute__((deprecated)); // The array being sequenced. @property (nonatomic, copy, readonly) NSArray *backingArray; // The index in the array from which the sequence starts. @property (nonatomic, assign, readonly) NSUInteger offset; @end @implementation RACArraySequence #pragma mark Lifecycle + (instancetype)sequenceWithArray:(NSArray *)array offset:(NSUInteger)offset { NSCParameterAssert(offset <= array.count); if (offset == array.count) return self.empty; RACArraySequence *seq = [[self alloc] init]; seq->_backingArray = [array copy]; seq->_offset = offset; return seq; } #pragma mark RACSequence - (id)head { return self.backingArray[self.offset]; } - (RACSequence *)tail { RACSequence *sequence = [self.class sequenceWithArray:self.backingArray offset:self.offset + 1]; sequence.name = self.name; return sequence; } #pragma mark NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(__unsafe_unretained id[])stackbuf count:(NSUInteger)len { NSCParameterAssert(len > 0); if (state->state >= self.backingArray.count) { // Enumeration has completed. return 0; } if (state->state == 0) { state->state = self.offset; // Since a sequence doesn't mutate, this just needs to be set to // something non-NULL. state->mutationsPtr = state->extra; } state->itemsPtr = stackbuf; NSUInteger startIndex = state->state; NSUInteger index = 0; for (id value in self.backingArray) { // Constructing an index set for -enumerateObjectsAtIndexes: can actually be // slower than just skipping the items we don't care about. if (index < startIndex) { ++index; continue; } stackbuf[index - startIndex] = value; ++index; if (index - startIndex >= len) break; } NSCAssert(index > startIndex, @"Final index (%lu) should be greater than start index (%lu)", (unsigned long)index, (unsigned long)startIndex); state->state = index; return index - startIndex; } #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-implementations" - (NSArray *)array { return [self.backingArray subarrayWithRange:NSMakeRange(self.offset, self.backingArray.count - self.offset)]; } #pragma clang diagnostic pop #pragma mark NSCoding - (id)initWithCoder:(NSCoder *)coder { self = [super initWithCoder:coder]; if (self == nil) return nil; _backingArray = [coder decodeObjectForKey:@"array"]; _offset = 0; return self; } - (void)encodeWithCoder:(NSCoder *)coder { // Encoding is handled in RACSequence. [super encodeWithCoder:coder]; } #pragma mark NSObject - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p>{ name = %@, array = %@ }", self.class, self, self.name, self.backingArray]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACBehaviorSubject.h ================================================ // // RACBehaviorSubject.h // ReactiveCocoa // // Created by Josh Abernathy on 3/16/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACSubject.h" /// A behavior subject sends the last value it received when it is subscribed to. @interface RACBehaviorSubject : RACSubject /// Creates a new behavior subject with a default value. If it hasn't received /// any values when it gets subscribed to, it sends the default value. + (instancetype)behaviorSubjectWithDefaultValue:(id)value; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACBehaviorSubject.m ================================================ // // RACBehaviorSubject.m // ReactiveCocoa // // Created by Josh Abernathy on 3/16/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACBehaviorSubject.h" #import "RACDisposable.h" #import "RACScheduler+Private.h" @interface RACBehaviorSubject () // This property should only be used while synchronized on self. @property (nonatomic, strong) id currentValue; @end @implementation RACBehaviorSubject #pragma mark Lifecycle + (instancetype)behaviorSubjectWithDefaultValue:(id)value { RACBehaviorSubject *subject = [self subject]; subject.currentValue = value; return subject; } #pragma mark RACSignal - (RACDisposable *)subscribe:(id)subscriber { RACDisposable *subscriptionDisposable = [super subscribe:subscriber]; RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{ @synchronized (self) { [subscriber sendNext:self.currentValue]; } }]; return [RACDisposable disposableWithBlock:^{ [subscriptionDisposable dispose]; [schedulingDisposable dispose]; }]; } #pragma mark RACSubscriber - (void)sendNext:(id)value { @synchronized (self) { self.currentValue = value; [super sendNext:value]; } } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACBlockTrampoline.h ================================================ // // RACBlockTrampoline.h // ReactiveCocoa // // Created by Josh Abernathy on 10/21/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import @class RACTuple; // A private class that allows a limited type of dynamic block invocation. @interface RACBlockTrampoline : NSObject // Invokes the given block with the given arguments. All of the block's // argument types must be objects and it must be typed to return an object. // // At this time, it only supports blocks that take up to 15 arguments. Any more // is just cray. // // block - The block to invoke. Must accept as many arguments as are given in // the arguments array. Cannot be nil. // arguments - The arguments with which to invoke the block. `RACTupleNil`s will // be passed as nils. // // Returns the return value of invoking the block. + (id)invokeBlock:(id)block withArguments:(RACTuple *)arguments; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACBlockTrampoline.m ================================================ // // RACBlockTrampoline.m // ReactiveCocoa // // Created by Josh Abernathy on 10/21/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACBlockTrampoline.h" #import "RACTuple.h" @interface RACBlockTrampoline () @property (nonatomic, readonly, copy) id block; @end @implementation RACBlockTrampoline #pragma mark API - (id)initWithBlock:(id)block { self = [super init]; if (self == nil) return nil; _block = [block copy]; return self; } + (id)invokeBlock:(id)block withArguments:(RACTuple *)arguments { NSCParameterAssert(block != NULL); RACBlockTrampoline *trampoline = [[self alloc] initWithBlock:block]; return [trampoline invokeWithArguments:arguments]; } - (id)invokeWithArguments:(RACTuple *)arguments { SEL selector = [self selectorForArgumentCount:arguments.count]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:selector]]; invocation.selector = selector; invocation.target = self; for (NSUInteger i = 0; i < arguments.count; i++) { id arg = arguments[i]; NSInteger argIndex = (NSInteger)(i + 2); [invocation setArgument:&arg atIndex:argIndex]; } [invocation invoke]; __unsafe_unretained id returnVal; [invocation getReturnValue:&returnVal]; return returnVal; } - (SEL)selectorForArgumentCount:(NSUInteger)count { NSCParameterAssert(count > 0); switch (count) { case 0: return NULL; case 1: return @selector(performWith:); case 2: return @selector(performWith::); case 3: return @selector(performWith:::); case 4: return @selector(performWith::::); case 5: return @selector(performWith:::::); case 6: return @selector(performWith::::::); case 7: return @selector(performWith:::::::); case 8: return @selector(performWith::::::::); case 9: return @selector(performWith:::::::::); case 10: return @selector(performWith::::::::::); case 11: return @selector(performWith:::::::::::); case 12: return @selector(performWith::::::::::::); case 13: return @selector(performWith:::::::::::::); case 14: return @selector(performWith::::::::::::::); case 15: return @selector(performWith:::::::::::::::); } NSCAssert(NO, @"The argument count is too damn high! Only blocks of up to 15 arguments are currently supported."); return NULL; } - (id)performWith:(id)obj1 { id (^block)(id) = self.block; return block(obj1); } - (id)performWith:(id)obj1 :(id)obj2 { id (^block)(id, id) = self.block; return block(obj1, obj2); } - (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 { id (^block)(id, id, id) = self.block; return block(obj1, obj2, obj3); } - (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 { id (^block)(id, id, id, id) = self.block; return block(obj1, obj2, obj3, obj4); } - (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 { id (^block)(id, id, id, id, id) = self.block; return block(obj1, obj2, obj3, obj4, obj5); } - (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 { id (^block)(id, id, id, id, id, id) = self.block; return block(obj1, obj2, obj3, obj4, obj5, obj6); } - (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 { id (^block)(id, id, id, id, id, id, id) = self.block; return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7); } - (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 :(id)obj8 { id (^block)(id, id, id, id, id, id, id, id) = self.block; return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8); } - (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 :(id)obj8 :(id)obj9 { id (^block)(id, id, id, id, id, id, id, id, id) = self.block; return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9); } - (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 :(id)obj8 :(id)obj9 :(id)obj10 { id (^block)(id, id, id, id, id, id, id, id, id, id) = self.block; return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10); } - (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 :(id)obj8 :(id)obj9 :(id)obj10 :(id)obj11 { id (^block)(id, id, id, id, id, id, id, id, id, id, id) = self.block; return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11); } - (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 :(id)obj8 :(id)obj9 :(id)obj10 :(id)obj11 :(id)obj12 { id (^block)(id, id, id, id, id, id, id, id, id, id, id, id) = self.block; return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12); } - (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 :(id)obj8 :(id)obj9 :(id)obj10 :(id)obj11 :(id)obj12 :(id)obj13 { id (^block)(id, id, id, id, id, id, id, id, id, id, id, id, id) = self.block; return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12, obj13); } - (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 :(id)obj8 :(id)obj9 :(id)obj10 :(id)obj11 :(id)obj12 :(id)obj13 :(id)obj14 { id (^block)(id, id, id, id, id, id, id, id, id, id, id, id, id, id) = self.block; return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12, obj13, obj14); } - (id)performWith:(id)obj1 :(id)obj2 :(id)obj3 :(id)obj4 :(id)obj5 :(id)obj6 :(id)obj7 :(id)obj8 :(id)obj9 :(id)obj10 :(id)obj11 :(id)obj12 :(id)obj13 :(id)obj14 :(id)obj15 { id (^block)(id, id, id, id, id, id, id, id, id, id, id, id, id, id, id) = self.block; return block(obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12, obj13, obj14, obj15); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACChannel.h ================================================ // // RACChannel.h // ReactiveCocoa // // Created by Uri Baghin on 01/01/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACSignal.h" #import "RACSubscriber.h" @class RACChannelTerminal; /// A two-way channel. /// /// Conceptually, RACChannel can be thought of as a bidirectional connection, /// composed of two controllable signals that work in parallel. /// /// For example, when connecting between a view and a model: /// /// Model View /// `leadingTerminal` ------> `followingTerminal` /// `leadingTerminal` <------ `followingTerminal` /// /// The initial value of the model and all future changes to it are _sent on_ the /// `leadingTerminal`, and _received by_ subscribers of the `followingTerminal`. /// /// Likewise, whenever the user changes the value of the view, that value is sent /// on the `followingTerminal`, and received in the model from the /// `leadingTerminal`. However, the initial value of the view is not received /// from the `leadingTerminal` (only future changes). @interface RACChannel : NSObject /// The terminal which "leads" the channel, by sending its latest value /// immediately to new subscribers of the `followingTerminal`. /// /// New subscribers to this terminal will not receive a starting value, but will /// receive all future values that are sent to the `followingTerminal`. @property (nonatomic, strong, readonly) RACChannelTerminal *leadingTerminal; /// The terminal which "follows" the lead of the other terminal, only sending /// _future_ values to the subscribers of the `leadingTerminal`. /// /// The latest value sent to the `leadingTerminal` (if any) will be sent /// immediately to new subscribers of this terminal, and then all future values /// as well. @property (nonatomic, strong, readonly) RACChannelTerminal *followingTerminal; @end /// Represents one end of a RACChannel. /// /// An terminal is similar to a socket or pipe -- it represents one end of /// a connection (the RACChannel, in this case). Values sent to this terminal /// will _not_ be received by its subscribers. Instead, the values will be sent /// to the subscribers of the RACChannel's _other_ terminal. /// /// For example, when using the `followingTerminal`, _sent_ values can only be /// _received_ from the `leadingTerminal`, and vice versa. /// /// To make it easy to terminate a RACChannel, `error` and `completed` events /// sent to either terminal will be received by the subscribers of _both_ /// terminals. /// /// Do not instantiate this class directly. Create a RACChannel instead. @interface RACChannelTerminal : RACSignal - (id)init __attribute__((unavailable("Instantiate a RACChannel instead"))); @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACChannel.m ================================================ // // RACChannel.m // ReactiveCocoa // // Created by Uri Baghin on 01/01/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACChannel.h" #import "RACDisposable.h" #import "RACReplaySubject.h" #import "RACSignal+Operations.h" @interface RACChannelTerminal () // The values for this terminal. @property (nonatomic, strong, readonly) RACSignal *values; // A subscriber will will send values to the other terminal. @property (nonatomic, strong, readonly) id otherTerminal; - (id)initWithValues:(RACSignal *)values otherTerminal:(id)otherTerminal; @end @implementation RACChannel - (id)init { self = [super init]; if (self == nil) return nil; // We don't want any starting value from the leadingSubject, but we do want // error and completion to be replayed. RACReplaySubject *leadingSubject = [[RACReplaySubject replaySubjectWithCapacity:0] setNameWithFormat:@"leadingSubject"]; RACReplaySubject *followingSubject = [[RACReplaySubject replaySubjectWithCapacity:1] setNameWithFormat:@"followingSubject"]; // Propagate errors and completion to everything. [[leadingSubject ignoreValues] subscribe:followingSubject]; [[followingSubject ignoreValues] subscribe:leadingSubject]; _leadingTerminal = [[[RACChannelTerminal alloc] initWithValues:leadingSubject otherTerminal:followingSubject] setNameWithFormat:@"leadingTerminal"]; _followingTerminal = [[[RACChannelTerminal alloc] initWithValues:followingSubject otherTerminal:leadingSubject] setNameWithFormat:@"followingTerminal"]; return self; } @end @implementation RACChannelTerminal #pragma mark Lifecycle - (id)initWithValues:(RACSignal *)values otherTerminal:(id)otherTerminal { NSCParameterAssert(values != nil); NSCParameterAssert(otherTerminal != nil); self = [super init]; if (self == nil) return nil; _values = values; _otherTerminal = otherTerminal; return self; } #pragma mark RACSignal - (RACDisposable *)subscribe:(id)subscriber { return [self.values subscribe:subscriber]; } #pragma mark - (void)sendNext:(id)value { [self.otherTerminal sendNext:value]; } - (void)sendError:(NSError *)error { [self.otherTerminal sendError:error]; } - (void)sendCompleted { [self.otherTerminal sendCompleted]; } - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable { [self.otherTerminal didSubscribeWithDisposable:disposable]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACCommand.h ================================================ // // RACCommand.h // ReactiveCocoa // // Created by Josh Abernathy on 3/3/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import @class RACSignal; /// The domain for errors originating within `RACCommand`. extern NSString * const RACCommandErrorDomain; /// -execute: was invoked while the command was disabled. extern const NSInteger RACCommandErrorNotEnabled; /// A `userInfo` key for an error, associated with the `RACCommand` that the /// error originated from. /// /// This is included only when the error code is `RACCommandErrorNotEnabled`. extern NSString * const RACUnderlyingCommandErrorKey; /// A command is a signal triggered in response to some action, typically /// UI-related. @interface RACCommand : NSObject /// A signal of the signals returned by successful invocations of -execute: /// (i.e., while the receiver is `enabled`). /// /// Errors will be automatically caught upon the inner signals, and sent upon /// `errors` instead. If you _want_ to receive inner errors, use -execute: or /// -[RACSignal materialize]. /// /// Only executions that begin _after_ subscription will be sent upon this /// signal. All inner signals will arrive upon the main thread. @property (nonatomic, strong, readonly) RACSignal *executionSignals; /// A signal of whether this command is currently executing. /// /// This will send YES whenever -execute: is invoked and the created signal has /// not yet terminated. Once all executions have terminated, `executing` will /// send NO. /// /// This signal will send its current value upon subscription, and then all /// future values on the main thread. @property (nonatomic, strong, readonly) RACSignal *executing; /// A signal of whether this command is able to execute. /// /// This will send NO if: /// /// - The command was created with an `enabledSignal`, and NO is sent upon that /// signal, or /// - `allowsConcurrentExecution` is NO and the command has started executing. /// /// Once the above conditions are no longer met, the signal will send YES. /// /// This signal will send its current value upon subscription, and then all /// future values on the main thread. @property (nonatomic, strong, readonly) RACSignal *enabled; /// Forwards any errors that occur within signals returned by -execute:. /// /// When an error occurs on a signal returned from -execute:, this signal will /// send the associated NSError value as a `next` event (since an `error` event /// would terminate the stream). /// /// After subscription, this signal will send all future errors on the main /// thread. @property (nonatomic, strong, readonly) RACSignal *errors; /// Whether the command allows multiple executions to proceed concurrently. /// /// The default value for this property is NO. @property (atomic, assign) BOOL allowsConcurrentExecution; /// Invokes -initWithEnabled:signalBlock: with a nil `enabledSignal`. - (id)initWithSignalBlock:(RACSignal * (^)(id input))signalBlock; /// Initializes a command that is conditionally enabled. /// /// This is the designated initializer for this class. /// /// enabledSignal - A signal of BOOLs which indicate whether the command should /// be enabled. `enabled` will be based on the latest value sent /// from this signal. Before any values are sent, `enabled` will /// default to YES. This argument may be nil. /// signalBlock - A block which will map each input value (passed to -execute:) /// to a signal of work. The returned signal will be multicasted /// to a replay subject, sent on `executionSignals`, then /// subscribed to synchronously. Neither the block nor the /// returned signal may be nil. - (id)initWithEnabled:(RACSignal *)enabledSignal signalBlock:(RACSignal * (^)(id input))signalBlock; /// If the receiver is enabled, this method will: /// /// 1. Invoke the `signalBlock` given at the time of initialization. /// 2. Multicast the returned signal to a RACReplaySubject. /// 3. Send the multicasted signal on `executionSignals`. /// 4. Subscribe (connect) to the original signal on the main thread. /// /// input - The input value to pass to the receiver's `signalBlock`. This may be /// nil. /// /// Returns the multicasted signal, after subscription. If the receiver is not /// enabled, returns a signal that will send an error with code /// RACCommandErrorNotEnabled. - (RACSignal *)execute:(id)input; @end @interface RACCommand (Unavailable) @property (atomic, readonly) BOOL canExecute __attribute__((unavailable("Use the 'enabled' signal instead"))); + (instancetype)command __attribute__((unavailable("Use -initWithSignalBlock: instead"))); + (instancetype)commandWithCanExecuteSignal:(RACSignal *)canExecuteSignal __attribute__((unavailable("Use -initWithEnabled:signalBlock: instead"))); - (id)initWithCanExecuteSignal:(RACSignal *)canExecuteSignal __attribute__((unavailable("Use -initWithEnabled:signalBlock: instead"))); - (RACSignal *)addSignalBlock:(RACSignal * (^)(id value))signalBlock __attribute__((unavailable("Pass the signalBlock to -initWithSignalBlock: instead"))); @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACCommand.m ================================================ // // RACCommand.m // ReactiveCocoa // // Created by Josh Abernathy on 3/3/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACCommand.h" #import #import "NSArray+RACSequenceAdditions.h" #import "NSObject+RACDeallocating.h" #import "NSObject+RACDescription.h" #import "NSObject+RACPropertySubscribing.h" #import "RACMulticastConnection.h" #import "RACReplaySubject.h" #import "RACScheduler.h" #import "RACSequence.h" #import "RACSignal+Operations.h" #import NSString * const RACCommandErrorDomain = @"RACCommandErrorDomain"; NSString * const RACUnderlyingCommandErrorKey = @"RACUnderlyingCommandErrorKey"; const NSInteger RACCommandErrorNotEnabled = 1; @interface RACCommand () { // Atomic backing variable for `allowsConcurrentExecution`. volatile uint32_t _allowsConcurrentExecution; } /// A subject that sends added execution signals. @property (nonatomic, strong, readonly) RACSubject *addedExecutionSignalsSubject; /// A subject that sends the new value of `allowsConcurrentExecution` whenever it changes. @property (nonatomic, strong, readonly) RACSubject *allowsConcurrentExecutionSubject; // `enabled`, but without a hop to the main thread. // // Values from this signal may arrive on any thread. @property (nonatomic, strong, readonly) RACSignal *immediateEnabled; // The signal block that the receiver was initialized with. @property (nonatomic, copy, readonly) RACSignal * (^signalBlock)(id input); @end @implementation RACCommand #pragma mark Properties - (BOOL)allowsConcurrentExecution { return _allowsConcurrentExecution != 0; } - (void)setAllowsConcurrentExecution:(BOOL)allowed { if (allowed) { OSAtomicOr32Barrier(1, &_allowsConcurrentExecution); } else { OSAtomicAnd32Barrier(0, &_allowsConcurrentExecution); } [self.allowsConcurrentExecutionSubject sendNext:@(_allowsConcurrentExecution)]; } #pragma mark Lifecycle - (id)init { NSCAssert(NO, @"Use -initWithSignalBlock: instead"); return nil; } - (id)initWithSignalBlock:(RACSignal * (^)(id input))signalBlock { return [self initWithEnabled:nil signalBlock:signalBlock]; } - (void)dealloc { [_addedExecutionSignalsSubject sendCompleted]; [_allowsConcurrentExecutionSubject sendCompleted]; } - (id)initWithEnabled:(RACSignal *)enabledSignal signalBlock:(RACSignal * (^)(id input))signalBlock { NSCParameterAssert(signalBlock != nil); self = [super init]; if (self == nil) return nil; _addedExecutionSignalsSubject = [RACSubject new]; _allowsConcurrentExecutionSubject = [RACSubject new]; _signalBlock = [signalBlock copy]; _executionSignals = [[[self.addedExecutionSignalsSubject map:^(RACSignal *signal) { return [signal catchTo:[RACSignal empty]]; }] deliverOn:RACScheduler.mainThreadScheduler] setNameWithFormat:@"%@ -executionSignals", self]; // `errors` needs to be multicasted so that it picks up all // `activeExecutionSignals` that are added. // // In other words, if someone subscribes to `errors` _after_ an execution // has started, it should still receive any error from that execution. RACMulticastConnection *errorsConnection = [[[self.addedExecutionSignalsSubject flattenMap:^(RACSignal *signal) { return [[signal ignoreValues] catch:^(NSError *error) { return [RACSignal return:error]; }]; }] deliverOn:RACScheduler.mainThreadScheduler] publish]; _errors = [errorsConnection.signal setNameWithFormat:@"%@ -errors", self]; [errorsConnection connect]; RACSignal *immediateExecuting = [[[[self.addedExecutionSignalsSubject flattenMap:^(RACSignal *signal) { return [[[signal catchTo:[RACSignal empty]] then:^{ return [RACSignal return:@-1]; }] startWith:@1]; }] scanWithStart:@0 reduce:^(NSNumber *running, NSNumber *next) { return @(running.integerValue + next.integerValue); }] map:^(NSNumber *count) { return @(count.integerValue > 0); }] startWith:@NO]; _executing = [[[[[immediateExecuting deliverOn:RACScheduler.mainThreadScheduler] // This is useful before the first value arrives on the main thread. startWith:@NO] distinctUntilChanged] replayLast] setNameWithFormat:@"%@ -executing", self]; RACSignal *moreExecutionsAllowed = [RACSignal if:[self.allowsConcurrentExecutionSubject startWith:@NO] then:[RACSignal return:@YES] else:[immediateExecuting not]]; if (enabledSignal == nil) { enabledSignal = [RACSignal return:@YES]; } else { enabledSignal = [enabledSignal startWith:@YES]; } _immediateEnabled = [[[[RACSignal combineLatest:@[ enabledSignal, moreExecutionsAllowed ]] and] takeUntil:self.rac_willDeallocSignal] replayLast]; _enabled = [[[[[self.immediateEnabled take:1] concat:[[self.immediateEnabled skip:1] deliverOn:RACScheduler.mainThreadScheduler]] distinctUntilChanged] replayLast] setNameWithFormat:@"%@ -enabled", self]; return self; } #pragma mark Execution - (RACSignal *)execute:(id)input { // `immediateEnabled` is guaranteed to send a value upon subscription, so // -first is acceptable here. BOOL enabled = [[self.immediateEnabled first] boolValue]; if (!enabled) { NSError *error = [NSError errorWithDomain:RACCommandErrorDomain code:RACCommandErrorNotEnabled userInfo:@{ NSLocalizedDescriptionKey: NSLocalizedString(@"The command is disabled and cannot be executed", nil), RACUnderlyingCommandErrorKey: self }]; return [RACSignal error:error]; } RACSignal *signal = self.signalBlock(input); NSCAssert(signal != nil, @"nil signal returned from signal block for value: %@", input); // We subscribe to the signal on the main thread so that it occurs _after_ // -addActiveExecutionSignal: completes below. // // This means that `executing` and `enabled` will send updated values before // the signal actually starts performing work. RACMulticastConnection *connection = [[signal subscribeOn:RACScheduler.mainThreadScheduler] multicast:[RACReplaySubject subject]]; [self.addedExecutionSignalsSubject sendNext:connection.signal]; [connection connect]; return [connection.signal setNameWithFormat:@"%@ -execute: %@", self, RACDescription(input)]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACCompoundDisposable.h ================================================ // // RACCompoundDisposable.h // ReactiveCocoa // // Created by Josh Abernathy on 11/30/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACDisposable.h" /// A disposable of disposables. When it is disposed, it disposes of all its /// contained disposables. /// /// If -addDisposable: is called after the compound disposable has been disposed /// of, the given disposable is immediately disposed. This allows a compound /// disposable to act as a stand-in for a disposable that will be delivered /// asynchronously. @interface RACCompoundDisposable : RACDisposable /// Creates and returns a new compound disposable. + (instancetype)compoundDisposable; /// Creates and returns a new compound disposable containing the given /// disposables. + (instancetype)compoundDisposableWithDisposables:(NSArray *)disposables; /// Adds the given disposable. If the receiving disposable has already been /// disposed of, the given disposable is disposed immediately. /// /// This method is thread-safe. /// /// disposable - The disposable to add. This may be nil, in which case nothing /// happens. - (void)addDisposable:(RACDisposable *)disposable; /// Removes the specified disposable from the compound disposable (regardless of /// its disposed status), or does nothing if it's not in the compound disposable. /// /// This is mainly useful for limiting the memory usage of the compound /// disposable for long-running operations. /// /// This method is thread-safe. /// /// disposable - The disposable to remove. This argument may be nil (to make the /// use of weak references easier). - (void)removeDisposable:(RACDisposable *)disposable; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACCompoundDisposable.m ================================================ // // RACCompoundDisposable.m // ReactiveCocoa // // Created by Josh Abernathy on 11/30/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACCompoundDisposable.h" #import "RACCompoundDisposableProvider.h" #import // The number of child disposables for which space will be reserved directly in // `RACCompoundDisposable`. // // This number has been empirically determined to provide a good tradeoff // between performance, memory usage, and `RACCompoundDisposable` instance size // in a moderately complex GUI application. // // Profile any change! #define RACCompoundDisposableInlineCount 2 static CFMutableArrayRef RACCreateDisposablesArray(void) { // Compare values using only pointer equality. CFArrayCallBacks callbacks = kCFTypeArrayCallBacks; callbacks.equal = NULL; return CFArrayCreateMutable(NULL, 0, &callbacks); } @interface RACCompoundDisposable () { // Used for synchronization. OSSpinLock _spinLock; #if RACCompoundDisposableInlineCount // A fast array to the first N of the receiver's disposables. // // Once this is full, `_disposables` will be created and used for additional // disposables. // // This array should only be manipulated while _spinLock is held. RACDisposable *_inlineDisposables[RACCompoundDisposableInlineCount]; #endif // Contains the receiver's disposables. // // This array should only be manipulated while _spinLock is held. If // `_disposed` is YES, this may be NULL. CFMutableArrayRef _disposables; // Whether the receiver has already been disposed. // // This ivar should only be accessed while _spinLock is held. BOOL _disposed; } @end @implementation RACCompoundDisposable #pragma mark Properties - (BOOL)isDisposed { OSSpinLockLock(&_spinLock); BOOL disposed = _disposed; OSSpinLockUnlock(&_spinLock); return disposed; } #pragma mark Lifecycle + (instancetype)compoundDisposable { return [[self alloc] initWithDisposables:nil]; } + (instancetype)compoundDisposableWithDisposables:(NSArray *)disposables { return [[self alloc] initWithDisposables:disposables]; } - (id)initWithDisposables:(NSArray *)otherDisposables { self = [self init]; if (self == nil) return nil; #if RACCompoundDisposableInlineCount [otherDisposables enumerateObjectsUsingBlock:^(RACDisposable *disposable, NSUInteger index, BOOL *stop) { _inlineDisposables[index] = disposable; // Stop after this iteration if we've reached the end of the inlined // array. if (index == RACCompoundDisposableInlineCount - 1) *stop = YES; }]; #endif if (otherDisposables.count > RACCompoundDisposableInlineCount) { _disposables = RACCreateDisposablesArray(); CFRange range = CFRangeMake(RACCompoundDisposableInlineCount, (CFIndex)otherDisposables.count - RACCompoundDisposableInlineCount); CFArrayAppendArray(_disposables, (__bridge CFArrayRef)otherDisposables, range); } return self; } - (id)initWithBlock:(void (^)(void))block { RACDisposable *disposable = [RACDisposable disposableWithBlock:block]; return [self initWithDisposables:@[ disposable ]]; } - (void)dealloc { #if RACCompoundDisposableInlineCount for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) { _inlineDisposables[i] = nil; } #endif if (_disposables != NULL) { CFRelease(_disposables); _disposables = NULL; } } #pragma mark Addition and Removal - (void)addDisposable:(RACDisposable *)disposable { NSCParameterAssert(disposable != self); if (disposable == nil || disposable.disposed) return; BOOL shouldDispose = NO; OSSpinLockLock(&_spinLock); { if (_disposed) { shouldDispose = YES; } else { #if RACCompoundDisposableInlineCount for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) { if (_inlineDisposables[i] == nil) { _inlineDisposables[i] = disposable; goto foundSlot; } } #endif if (_disposables == NULL) _disposables = RACCreateDisposablesArray(); CFArrayAppendValue(_disposables, (__bridge void *)disposable); if (RACCOMPOUNDDISPOSABLE_ADDED_ENABLED()) { RACCOMPOUNDDISPOSABLE_ADDED(self.description.UTF8String, disposable.description.UTF8String, CFArrayGetCount(_disposables) + RACCompoundDisposableInlineCount); } #if RACCompoundDisposableInlineCount foundSlot:; #endif } } OSSpinLockUnlock(&_spinLock); // Performed outside of the lock in case the compound disposable is used // recursively. if (shouldDispose) [disposable dispose]; } - (void)removeDisposable:(RACDisposable *)disposable { if (disposable == nil) return; OSSpinLockLock(&_spinLock); { if (!_disposed) { #if RACCompoundDisposableInlineCount for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) { if (_inlineDisposables[i] == disposable) _inlineDisposables[i] = nil; } #endif if (_disposables != NULL) { CFIndex count = CFArrayGetCount(_disposables); for (CFIndex i = count - 1; i >= 0; i--) { const void *item = CFArrayGetValueAtIndex(_disposables, i); if (item == (__bridge void *)disposable) { CFArrayRemoveValueAtIndex(_disposables, i); } } if (RACCOMPOUNDDISPOSABLE_REMOVED_ENABLED()) { RACCOMPOUNDDISPOSABLE_REMOVED(self.description.UTF8String, disposable.description.UTF8String, CFArrayGetCount(_disposables) + RACCompoundDisposableInlineCount); } } } } OSSpinLockUnlock(&_spinLock); } #pragma mark RACDisposable static void disposeEach(const void *value, void *context) { RACDisposable *disposable = (__bridge id)value; [disposable dispose]; } - (void)dispose { #if RACCompoundDisposableInlineCount RACDisposable *inlineCopy[RACCompoundDisposableInlineCount]; #endif CFArrayRef remainingDisposables = NULL; OSSpinLockLock(&_spinLock); { _disposed = YES; #if RACCompoundDisposableInlineCount for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) { inlineCopy[i] = _inlineDisposables[i]; _inlineDisposables[i] = nil; } #endif remainingDisposables = _disposables; _disposables = NULL; } OSSpinLockUnlock(&_spinLock); #if RACCompoundDisposableInlineCount // Dispose outside of the lock in case the compound disposable is used // recursively. for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) { [inlineCopy[i] dispose]; } #endif if (remainingDisposables == NULL) return; CFIndex count = CFArrayGetCount(remainingDisposables); CFArrayApplyFunction(remainingDisposables, CFRangeMake(0, count), &disposeEach, NULL); CFRelease(remainingDisposables); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACCompoundDisposableProvider.d ================================================ provider RACCompoundDisposable { probe added(char *compoundDisposable, char *disposable, long newTotal); probe removed(char *compoundDisposable, char *disposable, long newTotal); }; ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACDelegateProxy.h ================================================ // // RACDelegateProxy.h // ReactiveCocoa // // Created by Cody Krieger on 5/19/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import @class RACSignal; // A private delegate object suitable for using // -rac_signalForSelector:fromProtocol: upon. @interface RACDelegateProxy : NSObject // The delegate to which messages should be forwarded if not handled by // any -signalForSelector: applications. @property (nonatomic, unsafe_unretained) id rac_proxiedDelegate; // Creates a delegate proxy capable of responding to selectors from `protocol`. - (instancetype)initWithProtocol:(Protocol *)protocol; // Calls -rac_signalForSelector:fromProtocol: using the `protocol` specified // during initialization. - (RACSignal *)signalForSelector:(SEL)selector; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACDelegateProxy.m ================================================ // // RACDelegateProxy.m // ReactiveCocoa // // Created by Cody Krieger on 5/19/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACDelegateProxy.h" #import "NSObject+RACSelectorSignal.h" #import @interface RACDelegateProxy () { // Declared as an ivar to avoid method naming conflicts. Protocol *_protocol; } @end @implementation RACDelegateProxy #pragma mark Lifecycle - (instancetype)initWithProtocol:(Protocol *)protocol { NSCParameterAssert(protocol != NULL); self = [super init]; if (self == nil) return nil; class_addProtocol(self.class, protocol); _protocol = protocol; return self; } #pragma mark API - (RACSignal *)signalForSelector:(SEL)selector { return [self rac_signalForSelector:selector fromProtocol:_protocol]; } #pragma mark NSObject - (BOOL)isProxy { return YES; } - (void)forwardInvocation:(NSInvocation *)invocation { [invocation invokeWithTarget:self.rac_proxiedDelegate]; } - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { // Look for the selector as an optional instance method. struct objc_method_description methodDescription = protocol_getMethodDescription(_protocol, selector, NO, YES); if (methodDescription.name == NULL) { // Then fall back to looking for a required instance // method. methodDescription = protocol_getMethodDescription(_protocol, selector, YES, YES); if (methodDescription.name == NULL) return [super methodSignatureForSelector:selector]; } return [NSMethodSignature signatureWithObjCTypes:methodDescription.types]; } - (BOOL)respondsToSelector:(SEL)selector { // Add the delegate to the autorelease pool, so it doesn't get deallocated // between this method call and -forwardInvocation:. __autoreleasing id delegate = self.rac_proxiedDelegate; if ([delegate respondsToSelector:selector]) return YES; return [super respondsToSelector:selector]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACDisposable.h ================================================ // // RACDisposable.h // ReactiveCocoa // // Created by Josh Abernathy on 3/16/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import @class RACScopedDisposable; /// A disposable encapsulates the work necessary to tear down and cleanup a /// subscription. @interface RACDisposable : NSObject /// Whether the receiver has been disposed. /// /// Use of this property is discouraged, since it may be set to `YES` /// concurrently at any time. /// /// This property is not KVO-compliant. @property (atomic, assign, getter = isDisposed, readonly) BOOL disposed; + (instancetype)disposableWithBlock:(void (^)(void))block; /// Performs the disposal work. Can be called multiple times, though subsequent /// calls won't do anything. - (void)dispose; /// Returns a new disposable which will dispose of this disposable when it gets /// dealloc'd. - (RACScopedDisposable *)asScopedDisposable; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACDisposable.m ================================================ // // RACDisposable.m // ReactiveCocoa // // Created by Josh Abernathy on 3/16/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACDisposable.h" #import "RACScopedDisposable.h" #import @interface RACDisposable () { // A copied block of type void (^)(void) containing the logic for disposal, // a pointer to `self` if no logic should be performed upon disposal, or // NULL if the receiver is already disposed. // // This should only be used atomically. void * volatile _disposeBlock; } @end @implementation RACDisposable #pragma mark Properties - (BOOL)isDisposed { return _disposeBlock == NULL; } #pragma mark Lifecycle - (id)init { self = [super init]; if (self == nil) return nil; _disposeBlock = (__bridge void *)self; OSMemoryBarrier(); return self; } - (id)initWithBlock:(void (^)(void))block { NSCParameterAssert(block != nil); self = [super init]; if (self == nil) return nil; _disposeBlock = (void *)CFBridgingRetain([block copy]); OSMemoryBarrier(); return self; } + (instancetype)disposableWithBlock:(void (^)(void))block { return [[self alloc] initWithBlock:block]; } - (void)dealloc { if (_disposeBlock == NULL || _disposeBlock == (__bridge void *)self) return; CFRelease(_disposeBlock); _disposeBlock = NULL; } #pragma mark Disposal - (void)dispose { void (^disposeBlock)(void) = NULL; while (YES) { void *blockPtr = _disposeBlock; if (OSAtomicCompareAndSwapPtrBarrier(blockPtr, NULL, &_disposeBlock)) { if (blockPtr != (__bridge void *)self) { disposeBlock = CFBridgingRelease(blockPtr); } break; } } if (disposeBlock != nil) disposeBlock(); } #pragma mark Scoped Disposables - (RACScopedDisposable *)asScopedDisposable { return [RACScopedDisposable scopedDisposableWithDisposable:self]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACDynamicPropertySuperclass.h ================================================ // Copyright (c) 2015 GitHub. All rights reserved. #import /// This superclass is an implementation detail of DynamicProperty. Do /// not use it. @interface RACDynamicPropertySuperclass : NSObject @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACDynamicPropertySuperclass.m ================================================ // Copyright (c) 2015 GitHub. All rights reserved. #import "RACDynamicPropertySuperclass.h" @interface RACDynamicPropertySuperclass () @property id value; @property id rac_value; @end @implementation RACDynamicPropertySuperclass - (id)value { return self.rac_value; } - (void)setValue:(id)value { self.rac_value = value; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACDynamicSequence.h ================================================ // // RACDynamicSequence.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import "RACSequence.h" // Private class that implements a sequence dynamically using blocks. @interface RACDynamicSequence : RACSequence // Returns a sequence which evaluates `dependencyBlock` only once, the first // time either `headBlock` or `tailBlock` is evaluated. The result of // `dependencyBlock` will be passed into `headBlock` and `tailBlock` when // invoked. + (RACSequence *)sequenceWithLazyDependency:(id (^)(void))dependencyBlock headBlock:(id (^)(id dependency))headBlock tailBlock:(RACSequence *(^)(id dependency))tailBlock; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACDynamicSequence.m ================================================ // // RACDynamicSequence.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import "RACDynamicSequence.h" #import // Determines how RACDynamicSequences will be deallocated before the next one is // shifted onto the autorelease pool. // // This avoids stack overflows when deallocating long chains of dynamic // sequences. #define DEALLOC_OVERFLOW_GUARD 100 @interface RACDynamicSequence () { // The value for the "head" property, if it's been evaluated already. // // Because it's legal for head to be nil, this ivar is valid any time // headBlock is nil. // // This ivar should only be accessed while synchronized on self. id _head; // The value for the "tail" property, if it's been evaluated already. // // Because it's legal for tail to be nil, this ivar is valid any time // tailBlock is nil. // // This ivar should only be accessed while synchronized on self. RACSequence *_tail; // The result of an evaluated `dependencyBlock`. // // This ivar is valid any time `hasDependency` is YES and `dependencyBlock` // is nil. // // This ivar should only be accessed while synchronized on self. id _dependency; } // A block used to evaluate head. This should be set to nil after `_head` has been // initialized. // // This is marked `strong` instead of `copy` because of some bizarre block // copying bug. See https://github.com/ReactiveCocoa/ReactiveCocoa/pull/506. // // The signature of this block varies based on the value of `hasDependency`: // // - If YES, this block is of type `id (^)(id)`. // - If NO, this block is of type `id (^)(void)`. // // This property should only be accessed while synchronized on self. @property (nonatomic, strong) id headBlock; // A block used to evaluate tail. This should be set to nil after `_tail` has been // initialized. // // This is marked `strong` instead of `copy` because of some bizarre block // copying bug. See https://github.com/ReactiveCocoa/ReactiveCocoa/pull/506. // // The signature of this block varies based on the value of `hasDependency`: // // - If YES, this block is of type `RACSequence * (^)(id)`. // - If NO, this block is of type `RACSequence * (^)(void)`. // // This property should only be accessed while synchronized on self. @property (nonatomic, strong) id tailBlock; // Whether the receiver was initialized with a `dependencyBlock`. // // This property should only be accessed while synchronized on self. @property (nonatomic, assign) BOOL hasDependency; // A dependency which must be evaluated before `headBlock` and `tailBlock`. This // should be set to nil after `_dependency` and `dependencyBlockExecuted` have // been set. // // This is marked `strong` instead of `copy` because of some bizarre block // copying bug. See https://github.com/ReactiveCocoa/ReactiveCocoa/pull/506. // // This property should only be accessed while synchronized on self. @property (nonatomic, strong) id (^dependencyBlock)(void); @end @implementation RACDynamicSequence #pragma mark Lifecycle + (RACSequence *)sequenceWithHeadBlock:(id (^)(void))headBlock tailBlock:(RACSequence *(^)(void))tailBlock { NSCParameterAssert(headBlock != nil); RACDynamicSequence *seq = [[RACDynamicSequence alloc] init]; seq.headBlock = [headBlock copy]; seq.tailBlock = [tailBlock copy]; seq.hasDependency = NO; return seq; } + (RACSequence *)sequenceWithLazyDependency:(id (^)(void))dependencyBlock headBlock:(id (^)(id dependency))headBlock tailBlock:(RACSequence *(^)(id dependency))tailBlock { NSCParameterAssert(dependencyBlock != nil); NSCParameterAssert(headBlock != nil); RACDynamicSequence *seq = [[RACDynamicSequence alloc] init]; seq.headBlock = [headBlock copy]; seq.tailBlock = [tailBlock copy]; seq.dependencyBlock = [dependencyBlock copy]; seq.hasDependency = YES; return seq; } - (void)dealloc { static volatile int32_t directDeallocCount = 0; if (OSAtomicIncrement32(&directDeallocCount) >= DEALLOC_OVERFLOW_GUARD) { OSAtomicAdd32(-DEALLOC_OVERFLOW_GUARD, &directDeallocCount); // Put this sequence's tail onto the autorelease pool so we stop // recursing. __autoreleasing RACSequence *tail __attribute__((unused)) = _tail; } _tail = nil; } #pragma mark RACSequence - (id)head { @synchronized (self) { id untypedHeadBlock = self.headBlock; if (untypedHeadBlock == nil) return _head; if (self.hasDependency) { if (self.dependencyBlock != nil) { _dependency = self.dependencyBlock(); self.dependencyBlock = nil; } id (^headBlock)(id) = untypedHeadBlock; _head = headBlock(_dependency); } else { id (^headBlock)(void) = untypedHeadBlock; _head = headBlock(); } self.headBlock = nil; return _head; } } - (RACSequence *)tail { @synchronized (self) { id untypedTailBlock = self.tailBlock; if (untypedTailBlock == nil) return _tail; if (self.hasDependency) { if (self.dependencyBlock != nil) { _dependency = self.dependencyBlock(); self.dependencyBlock = nil; } RACSequence * (^tailBlock)(id) = untypedTailBlock; _tail = tailBlock(_dependency); } else { RACSequence * (^tailBlock)(void) = untypedTailBlock; _tail = tailBlock(); } if (_tail.name == nil) _tail.name = self.name; self.tailBlock = nil; return _tail; } } #pragma mark NSObject - (NSString *)description { id head = @"(unresolved)"; id tail = @"(unresolved)"; @synchronized (self) { if (self.headBlock == nil) head = _head; if (self.tailBlock == nil) { tail = _tail; if (tail == self) tail = @"(self)"; } } return [NSString stringWithFormat:@"<%@: %p>{ name = %@, head = %@, tail = %@ }", self.class, self, self.name, head, tail]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACDynamicSignal.h ================================================ // // RACDynamicSignal.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-10-10. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACSignal.h" // A private `RACSignal` subclasses that implements its subscription behavior // using a block. @interface RACDynamicSignal : RACSignal + (RACSignal *)createSignal:(RACDisposable * (^)(id subscriber))didSubscribe; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACDynamicSignal.m ================================================ // // RACDynamicSignal.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-10-10. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACDynamicSignal.h" #import #import "RACCompoundDisposable.h" #import "RACPassthroughSubscriber.h" #import "RACScheduler+Private.h" #import "RACSubscriber.h" #import @interface RACDynamicSignal () // The block to invoke for each subscriber. @property (nonatomic, copy, readonly) RACDisposable * (^didSubscribe)(id subscriber); @end @implementation RACDynamicSignal #pragma mark Lifecycle + (RACSignal *)createSignal:(RACDisposable * (^)(id subscriber))didSubscribe { RACDynamicSignal *signal = [[self alloc] init]; signal->_didSubscribe = [didSubscribe copy]; return [signal setNameWithFormat:@"+createSignal:"]; } #pragma mark Managing Subscribers - (RACDisposable *)subscribe:(id)subscriber { NSCParameterAssert(subscriber != nil); RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable]; subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable]; if (self.didSubscribe != NULL) { RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{ RACDisposable *innerDisposable = self.didSubscribe(subscriber); [disposable addDisposable:innerDisposable]; }]; [disposable addDisposable:schedulingDisposable]; } return disposable; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACEagerSequence.h ================================================ // // RACEagerSequence.h // ReactiveCocoa // // Created by Uri Baghin on 02/01/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACArraySequence.h" // Private class that implements an eager sequence. @interface RACEagerSequence : RACArraySequence @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACEagerSequence.m ================================================ // // RACEagerSequence.m // ReactiveCocoa // // Created by Uri Baghin on 02/01/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACEagerSequence.h" #import "NSObject+RACDescription.h" #import "RACArraySequence.h" @implementation RACEagerSequence #pragma mark RACStream + (instancetype)return:(id)value { return [[self sequenceWithArray:@[ value ] offset:0] setNameWithFormat:@"+return: %@", RACDescription(value)]; } - (instancetype)bind:(RACStreamBindBlock (^)(void))block { NSCParameterAssert(block != nil); RACStreamBindBlock bindBlock = block(); NSArray *currentArray = self.array; NSMutableArray *resultArray = [NSMutableArray arrayWithCapacity:currentArray.count]; for (id value in currentArray) { BOOL stop = NO; RACSequence *boundValue = (id)bindBlock(value, &stop); if (boundValue == nil) break; for (id x in boundValue) { [resultArray addObject:x]; } if (stop) break; } return [[self.class sequenceWithArray:resultArray offset:0] setNameWithFormat:@"[%@] -bind:", self.name]; } - (instancetype)concat:(RACSequence *)sequence { NSCParameterAssert(sequence != nil); NSCParameterAssert([sequence isKindOfClass:RACSequence.class]); NSArray *array = [self.array arrayByAddingObjectsFromArray:sequence.array]; return [[self.class sequenceWithArray:array offset:0] setNameWithFormat:@"[%@] -concat: %@", self.name, sequence]; } #pragma mark Extended methods - (RACSequence *)eagerSequence { return self; } - (RACSequence *)lazySequence { return [RACArraySequence sequenceWithArray:self.array offset:0]; } - (id)foldRightWithStart:(id)start reduce:(id (^)(id, RACSequence *rest))reduce { return [super foldRightWithStart:start reduce:^(id first, RACSequence *rest) { return reduce(first, rest.eagerSequence); }]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACEmptySequence.h ================================================ // // RACEmptySequence.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import "RACSequence.h" // Private class representing an empty sequence. @interface RACEmptySequence : RACSequence @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACEmptySequence.m ================================================ // // RACEmptySequence.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import "RACEmptySequence.h" @implementation RACEmptySequence #pragma mark Lifecycle + (instancetype)empty { static id singleton; static dispatch_once_t pred; dispatch_once(&pred, ^{ singleton = [[self alloc] init]; }); return singleton; } #pragma mark RACSequence - (id)head { return nil; } - (RACSequence *)tail { return nil; } - (RACSequence *)bind:(RACStreamBindBlock)bindBlock passingThroughValuesFromSequence:(RACSequence *)passthroughSequence { return passthroughSequence ?: self; } #pragma mark NSCoding - (Class)classForCoder { // Empty sequences should be encoded as themselves, not array sequences. return self.class; } - (id)initWithCoder:(NSCoder *)coder { // Return the singleton. return self.class.empty; } - (void)encodeWithCoder:(NSCoder *)coder { } #pragma mark NSObject - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p>{ name = %@ }", self.class, self, self.name]; } - (NSUInteger)hash { // This hash isn't ideal, but it's better than -[RACSequence hash], which // would just be zero because we have no head. return (NSUInteger)(__bridge void *)self; } - (BOOL)isEqual:(RACSequence *)seq { return (self == seq); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACEmptySignal.h ================================================ // // RACEmptySignal.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-10-10. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACSignal.h" // A private `RACSignal` subclasses that synchronously sends completed to any // subscribers. @interface RACEmptySignal : RACSignal + (RACSignal *)empty; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACEmptySignal.m ================================================ // // RACEmptySignal.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-10-10. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACEmptySignal.h" #import "RACScheduler+Private.h" #import "RACSubscriber.h" @implementation RACEmptySignal #pragma mark Properties // Only allow this signal's name to be customized in DEBUG, since it's // a singleton in release builds (see +empty). - (void)setName:(NSString *)name { #ifdef DEBUG [super setName:name]; #endif } - (NSString *)name { #ifdef DEBUG return super.name; #else return @"+empty"; #endif } #pragma mark Lifecycle + (RACSignal *)empty { #ifdef DEBUG // Create multiple instances of this class in DEBUG so users can set custom // names on each. return [[[self alloc] init] setNameWithFormat:@"+empty"]; #else static id singleton; static dispatch_once_t pred; dispatch_once(&pred, ^{ singleton = [[self alloc] init]; }); return singleton; #endif } #pragma mark Subscription - (RACDisposable *)subscribe:(id)subscriber { NSCParameterAssert(subscriber != nil); return [RACScheduler.subscriptionScheduler schedule:^{ [subscriber sendCompleted]; }]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACErrorSignal.h ================================================ // // RACErrorSignal.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-10-10. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACSignal.h" // A private `RACSignal` subclasses that synchronously sends an error to any // subscribers. @interface RACErrorSignal : RACSignal + (RACSignal *)error:(NSError *)error; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACErrorSignal.m ================================================ // // RACErrorSignal.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-10-10. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACErrorSignal.h" #import "RACScheduler+Private.h" #import "RACSubscriber.h" @interface RACErrorSignal () // The error to send upon subscription. @property (nonatomic, strong, readonly) NSError *error; @end @implementation RACErrorSignal #pragma mark Lifecycle + (RACSignal *)error:(NSError *)error { RACErrorSignal *signal = [[self alloc] init]; signal->_error = error; #ifdef DEBUG [signal setNameWithFormat:@"+error: %@", error]; #else signal.name = @"+error:"; #endif return signal; } #pragma mark Subscription - (RACDisposable *)subscribe:(id)subscriber { NSCParameterAssert(subscriber != nil); return [RACScheduler.subscriptionScheduler schedule:^{ [subscriber sendError:self.error]; }]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACEvent.h ================================================ // // RACEvent.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-01-07. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import /// Describes the type of a RACEvent. /// /// RACEventTypeCompleted - A `completed` event. /// RACEventTypeError - An `error` event. /// RACEventTypeNext - A `next` event. typedef NS_ENUM(NSUInteger, RACEventType) { RACEventTypeCompleted, RACEventTypeError, RACEventTypeNext }; /// Represents an event sent by a RACSignal. /// /// This corresponds to the `Notification` class in Rx. @interface RACEvent : NSObject /// Returns a singleton RACEvent representing the `completed` event. + (instancetype)completedEvent; /// Returns a new event of type RACEventTypeError, containing the given error. + (instancetype)eventWithError:(NSError *)error; /// Returns a new event of type RACEventTypeNext, containing the given value. + (instancetype)eventWithValue:(id)value; /// The type of event represented by the receiver. @property (nonatomic, assign, readonly) RACEventType eventType; /// Returns whether the receiver is of type RACEventTypeCompleted or /// RACEventTypeError. @property (nonatomic, getter = isFinished, assign, readonly) BOOL finished; /// The error associated with an event of type RACEventTypeError. This will be /// nil for all other event types. @property (nonatomic, strong, readonly) NSError *error; /// The value associated with an event of type RACEventTypeNext. This will be /// nil for all other event types. @property (nonatomic, strong, readonly) id value; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACEvent.m ================================================ // // RACEvent.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-01-07. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACEvent.h" @interface RACEvent () // An object associated with this event. This will be used for the error and // value properties. @property (nonatomic, strong, readonly) id object; // Initializes the receiver with the given type and object. - (id)initWithEventType:(RACEventType)type object:(id)object; @end @implementation RACEvent #pragma mark Properties - (BOOL)isFinished { return self.eventType == RACEventTypeCompleted || self.eventType == RACEventTypeError; } - (NSError *)error { return (self.eventType == RACEventTypeError ? self.object : nil); } - (id)value { return (self.eventType == RACEventTypeNext ? self.object : nil); } #pragma mark Lifecycle + (instancetype)completedEvent { static dispatch_once_t pred; static id singleton; dispatch_once(&pred, ^{ singleton = [[self alloc] initWithEventType:RACEventTypeCompleted object:nil]; }); return singleton; } + (instancetype)eventWithError:(NSError *)error { return [[self alloc] initWithEventType:RACEventTypeError object:error]; } + (instancetype)eventWithValue:(id)value { return [[self alloc] initWithEventType:RACEventTypeNext object:value]; } - (id)initWithEventType:(RACEventType)type object:(id)object { self = [super init]; if (self == nil) return nil; _eventType = type; _object = object; return self; } #pragma mark NSCopying - (id)copyWithZone:(NSZone *)zone { return self; } #pragma mark NSObject - (NSString *)description { NSString *eventDescription = nil; switch (self.eventType) { case RACEventTypeCompleted: eventDescription = @"completed"; break; case RACEventTypeError: eventDescription = [NSString stringWithFormat:@"error = %@", self.object]; break; case RACEventTypeNext: eventDescription = [NSString stringWithFormat:@"next = %@", self.object]; break; default: NSCAssert(NO, @"Unrecognized event type: %i", (int)self.eventType); } return [NSString stringWithFormat:@"<%@: %p>{ %@ }", self.class, self, eventDescription]; } - (NSUInteger)hash { return self.eventType ^ [self.object hash]; } - (BOOL)isEqual:(id)event { if (event == self) return YES; if (![event isKindOfClass:RACEvent.class]) return NO; if (self.eventType != [event eventType]) return NO; // Catches the nil case too. return self.object == [event object] || [self.object isEqual:[event object]]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACGroupedSignal.h ================================================ // // RACGroupedSignal.h // ReactiveCocoa // // Created by Josh Abernathy on 5/2/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACSubject.h" /// A grouped signal is used by -[RACSignal groupBy:transform:]. @interface RACGroupedSignal : RACSubject /// The key shared by the group. @property (nonatomic, readonly, copy) id key; + (instancetype)signalWithKey:(id)key; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACGroupedSignal.m ================================================ // // RACGroupedSignal.m // ReactiveCocoa // // Created by Josh Abernathy on 5/2/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACGroupedSignal.h" @interface RACGroupedSignal () @property (nonatomic, copy) id key; @end @implementation RACGroupedSignal #pragma mark API + (instancetype)signalWithKey:(id)key { RACGroupedSignal *subject = [self subject]; subject.key = key; return subject; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACImmediateScheduler.h ================================================ // // RACImmediateScheduler.h // ReactiveCocoa // // Created by Josh Abernathy on 11/30/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACScheduler.h" // A private scheduler which immediately executes its scheduled blocks. @interface RACImmediateScheduler : RACScheduler @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACImmediateScheduler.m ================================================ // // RACImmediateScheduler.m // ReactiveCocoa // // Created by Josh Abernathy on 11/30/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACImmediateScheduler.h" #import "RACScheduler+Private.h" @implementation RACImmediateScheduler #pragma mark Lifecycle - (id)init { return [super initWithName:@"com.ReactiveCocoa.RACScheduler.immediateScheduler"]; } #pragma mark RACScheduler - (RACDisposable *)schedule:(void (^)(void))block { NSCParameterAssert(block != NULL); block(); return nil; } - (RACDisposable *)after:(NSDate *)date schedule:(void (^)(void))block { NSCParameterAssert(date != nil); NSCParameterAssert(block != NULL); [NSThread sleepUntilDate:date]; block(); return nil; } - (RACDisposable *)after:(NSDate *)date repeatingEvery:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway schedule:(void (^)(void))block { NSCAssert(NO, @"+[RACScheduler immediateScheduler] does not support %@.", NSStringFromSelector(_cmd)); return nil; } - (RACDisposable *)scheduleRecursiveBlock:(RACSchedulerRecursiveBlock)recursiveBlock { for (__block NSUInteger remaining = 1; remaining > 0; remaining--) { recursiveBlock(^{ remaining++; }); } return nil; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACIndexSetSequence.h ================================================ // // RACIndexSetSequence.h // ReactiveCocoa // // Created by Sergey Gavrilyuk on 12/18/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACSequence.h" // Private class that adapts an array to the RACSequence interface. @interface RACIndexSetSequence : RACSequence + (instancetype)sequenceWithIndexSet:(NSIndexSet *)indexSet; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACIndexSetSequence.m ================================================ // // RACIndexSetSequence.m // ReactiveCocoa // // Created by Sergey Gavrilyuk on 12/18/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACIndexSetSequence.h" @interface RACIndexSetSequence () // A buffer holding the `NSUInteger` values to enumerate over. // // This is mostly used for memory management. Most access should go through // `indexes` instead. @property (nonatomic, strong, readonly) NSData *data; // The indexes that this sequence should enumerate. @property (nonatomic, readonly) const NSUInteger *indexes; // The number of indexes to enumerate. @property (nonatomic, readonly) NSUInteger count; @end @implementation RACIndexSetSequence #pragma mark Lifecycle + (instancetype)sequenceWithIndexSet:(NSIndexSet *)indexSet { NSUInteger count = indexSet.count; if (count == 0) return self.empty; NSUInteger sizeInBytes = sizeof(NSUInteger) * count; NSMutableData *data = [[NSMutableData alloc] initWithCapacity:sizeInBytes]; [indexSet getIndexes:data.mutableBytes maxCount:count inIndexRange:NULL]; RACIndexSetSequence *seq = [[self alloc] init]; seq->_data = data; seq->_indexes = data.bytes; seq->_count = count; return seq; } + (instancetype)sequenceWithIndexSetSequence:(RACIndexSetSequence *)indexSetSequence offset:(NSUInteger)offset { NSCParameterAssert(offset < indexSetSequence.count); RACIndexSetSequence *seq = [[self alloc] init]; seq->_data = indexSetSequence.data; seq->_indexes = indexSetSequence.indexes + offset; seq->_count = indexSetSequence.count - offset; return seq; } #pragma mark RACSequence - (id)head { return @(self.indexes[0]); } - (RACSequence *)tail { if (self.count <= 1) return [RACSequence empty]; return [self.class sequenceWithIndexSetSequence:self offset:1]; } #pragma mark NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(__unsafe_unretained id[])stackbuf count:(NSUInteger)len { NSCParameterAssert(len > 0); if (state->state >= self.count) { // Enumeration has completed. return 0; } if (state->state == 0) { // Enumeration begun, mark the mutation flag. state->mutationsPtr = state->extra; } state->itemsPtr = stackbuf; unsigned long index = 0; while (index < MIN(self.count - state->state, len)) { stackbuf[index] = @(self.indexes[index + state->state]); ++index; } state->state += index; return index; } #pragma mark NSObject - (NSString *)description { NSMutableString *indexesStr = [NSMutableString string]; for (unsigned int i = 0; i < self.count; ++i) { if (i > 0) [indexesStr appendString:@", "]; [indexesStr appendFormat:@"%lu", (unsigned long)self.indexes[i]]; } return [NSString stringWithFormat:@"<%@: %p>{ name = %@, indexes = %@ }", self.class, self, self.name, indexesStr]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACKVOChannel.h ================================================ // // RACKVOChannel.h // ReactiveCocoa // // Created by Uri Baghin on 27/12/2012. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACChannel.h" #import #import "metamacros.h" /// Creates a RACKVOChannel to the given key path. When the targeted object /// deallocates, the channel will complete. /// /// If RACChannelTo() is used as an expression, it returns a RACChannelTerminal that /// can be used to watch the specified property for changes, and set new values /// for it. The terminal will start with the property's current value upon /// subscription. /// /// If RACChannelTo() is used on the left-hand side of an assignment, there must a /// RACChannelTerminal on the right-hand side of the assignment. The two will be /// subscribed to one another: the property's value is immediately set to the /// value of the channel terminal on the right-hand side, and subsequent changes /// to either terminal will be reflected on the other. /// /// There are two different versions of this macro: /// /// - RACChannelTo(TARGET, KEYPATH, NILVALUE) will create a channel to the `KEYPATH` /// of `TARGET`. If the terminal is ever sent a `nil` value, the property will /// be set to `NILVALUE` instead. `NILVALUE` may itself be `nil` for object /// properties, but an NSValue should be used for primitive properties, to /// avoid an exception if `nil` is sent (which might occur if an intermediate /// object is set to `nil`). /// - RACChannelTo(TARGET, KEYPATH) is the same as the above, but `NILVALUE` defaults to /// `nil`. /// /// Examples /// /// RACChannelTerminal *integerChannel = RACChannelTo(self, integerProperty, @42); /// /// // Sets self.integerProperty to 5. /// [integerChannel sendNext:@5]; /// /// // Logs the current value of self.integerProperty, and all future changes. /// [integerChannel subscribeNext:^(id value) { /// NSLog(@"value: %@", value); /// }]; /// /// // Binds properties to each other, taking the initial value from the right /// side. /// RACChannelTo(view, objectProperty) = RACChannelTo(model, objectProperty); /// RACChannelTo(view, integerProperty, @2) = RACChannelTo(model, integerProperty, @10); #define RACChannelTo(TARGET, ...) \ metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__)) \ (RACChannelTo_(TARGET, __VA_ARGS__, nil)) \ (RACChannelTo_(TARGET, __VA_ARGS__)) /// Do not use this directly. Use the RACChannelTo macro above. #define RACChannelTo_(TARGET, KEYPATH, NILVALUE) \ [[RACKVOChannel alloc] initWithTarget:(TARGET) keyPath:@keypath(TARGET, KEYPATH) nilValue:(NILVALUE)][@keypath(RACKVOChannel.new, followingTerminal)] /// A RACChannel that observes a KVO-compliant key path for changes. @interface RACKVOChannel : RACChannel /// Initializes a channel that will observe the given object and key path. /// /// The current value of the key path, and future KVO notifications for the given /// key path, will be sent to subscribers of the channel's `followingTerminal`. /// Values sent to the `followingTerminal` will be set at the given key path using /// key-value coding. /// /// When the target object deallocates, the channel will complete. Signal errors /// are considered undefined behavior. /// /// This is the designated initializer for this class. /// /// target - The object to bind to. /// keyPath - The key path to observe and set the value of. /// nilValue - The value to set at the key path whenever a `nil` value is /// received. This may be nil when connecting to object properties, but /// an NSValue should be used for primitive properties, to avoid an /// exception if `nil` is received (which might occur if an intermediate /// object is set to `nil`). #if OS_OBJECT_HAVE_OBJC_SUPPORT - (id)initWithTarget:(__weak NSObject *)target keyPath:(NSString *)keyPath nilValue:(id)nilValue; #else // Swift builds with OS_OBJECT_HAVE_OBJC_SUPPORT=0 for Playgrounds and LLDB :( - (id)initWithTarget:(NSObject *)target keyPath:(NSString *)keyPath nilValue:(id)nilValue; #endif - (id)init __attribute__((unavailable("Use -initWithTarget:keyPath:nilValue: instead"))); @end /// Methods needed for the convenience macro. Do not call explicitly. @interface RACKVOChannel (RACChannelTo) - (RACChannelTerminal *)objectForKeyedSubscript:(NSString *)key; - (void)setObject:(RACChannelTerminal *)otherTerminal forKeyedSubscript:(NSString *)key; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACKVOChannel.m ================================================ // // RACKVOChannel.m // ReactiveCocoa // // Created by Uri Baghin on 27/12/2012. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACKVOChannel.h" #import #import "NSObject+RACDeallocating.h" #import "NSObject+RACKVOWrapper.h" #import "NSString+RACKeyPathUtilities.h" #import "RACChannel.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACSignal+Operations.h" // Key for the array of RACKVOChannel's additional thread local // data in the thread dictionary. static NSString * const RACKVOChannelDataDictionaryKey = @"RACKVOChannelKey"; // Wrapper class for additional thread local data. @interface RACKVOChannelData : NSObject // The flag used to ignore updates the channel itself has triggered. @property (nonatomic, assign) BOOL ignoreNextUpdate; // A pointer to the owner of the data. Only use this for pointer comparison, // never as an object reference. @property (nonatomic, assign) void *owner; + (instancetype)dataForChannel:(RACKVOChannel *)channel; @end @interface RACKVOChannel () // The object whose key path the channel is wrapping. @property (atomic, weak) NSObject *target; // The key path the channel is wrapping. @property (nonatomic, copy, readonly) NSString *keyPath; // Returns the existing thread local data container or nil if none exists. @property (nonatomic, strong, readonly) RACKVOChannelData *currentThreadData; // Creates the thread local data container for the channel. - (void)createCurrentThreadData; // Destroy the thread local data container for the channel. - (void)destroyCurrentThreadData; @end @implementation RACKVOChannel #pragma mark Properties - (RACKVOChannelData *)currentThreadData { NSMutableArray *dataArray = NSThread.currentThread.threadDictionary[RACKVOChannelDataDictionaryKey]; for (RACKVOChannelData *data in dataArray) { if (data.owner == (__bridge void *)self) return data; } return nil; } #pragma mark Lifecycle - (id)initWithTarget:(__weak NSObject *)target keyPath:(NSString *)keyPath nilValue:(id)nilValue { NSCParameterAssert(keyPath.rac_keyPathComponents.count > 0); NSObject *strongTarget = target; self = [super init]; if (self == nil) return nil; _target = target; _keyPath = [keyPath copy]; [self.leadingTerminal setNameWithFormat:@"[-initWithTarget: %@ keyPath: %@ nilValue: %@] -leadingTerminal", target, keyPath, nilValue]; [self.followingTerminal setNameWithFormat:@"[-initWithTarget: %@ keyPath: %@ nilValue: %@] -followingTerminal", target, keyPath, nilValue]; if (strongTarget == nil) { [self.leadingTerminal sendCompleted]; return self; } // Observe the key path on target for changes and forward the changes to the // terminal. // // Intentionally capturing `self` strongly in the blocks below, so the // channel object stays alive while observing. RACDisposable *observationDisposable = [strongTarget rac_observeKeyPath:keyPath options:NSKeyValueObservingOptionInitial observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { // If the change wasn't triggered by deallocation, only affects the last // path component, and ignoreNextUpdate is set, then it was triggered by // this channel and should not be forwarded. if (!causedByDealloc && affectedOnlyLastComponent && self.currentThreadData.ignoreNextUpdate) { [self destroyCurrentThreadData]; return; } [self.leadingTerminal sendNext:value]; }]; NSString *keyPathByDeletingLastKeyPathComponent = keyPath.rac_keyPathByDeletingLastKeyPathComponent; NSArray *keyPathComponents = keyPath.rac_keyPathComponents; NSUInteger keyPathComponentsCount = keyPathComponents.count; NSString *lastKeyPathComponent = keyPathComponents.lastObject; // Update the value of the property with the values received. [[self.leadingTerminal finally:^{ [observationDisposable dispose]; }] subscribeNext:^(id x) { // Check the value of the second to last key path component. Since the // channel can only update the value of a property on an object, and not // update intermediate objects, it can only update the value of the whole // key path if this object is not nil. NSObject *object = (keyPathComponentsCount > 1 ? [self.target valueForKeyPath:keyPathByDeletingLastKeyPathComponent] : self.target); if (object == nil) return; // Set the ignoreNextUpdate flag before setting the value so this channel // ignores the value in the subsequent -didChangeValueForKey: callback. [self createCurrentThreadData]; self.currentThreadData.ignoreNextUpdate = YES; [object setValue:x ?: nilValue forKey:lastKeyPathComponent]; } error:^(NSError *error) { NSCAssert(NO, @"Received error in %@: %@", self, error); // Log the error if we're running with assertions disabled. NSLog(@"Received error in %@: %@", self, error); }]; // Capture `self` weakly for the target's deallocation disposable, so we can // freely deallocate if we complete before then. @weakify(self); [strongTarget.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ @strongify(self); [self.leadingTerminal sendCompleted]; self.target = nil; }]]; return self; } - (void)createCurrentThreadData { NSMutableArray *dataArray = NSThread.currentThread.threadDictionary[RACKVOChannelDataDictionaryKey]; if (dataArray == nil) { dataArray = [NSMutableArray array]; NSThread.currentThread.threadDictionary[RACKVOChannelDataDictionaryKey] = dataArray; [dataArray addObject:[RACKVOChannelData dataForChannel:self]]; return; } for (RACKVOChannelData *data in dataArray) { if (data.owner == (__bridge void *)self) return; } [dataArray addObject:[RACKVOChannelData dataForChannel:self]]; } - (void)destroyCurrentThreadData { NSMutableArray *dataArray = NSThread.currentThread.threadDictionary[RACKVOChannelDataDictionaryKey]; NSUInteger index = [dataArray indexOfObjectPassingTest:^ BOOL (RACKVOChannelData *data, NSUInteger idx, BOOL *stop) { return data.owner == (__bridge void *)self; }]; if (index != NSNotFound) [dataArray removeObjectAtIndex:index]; } @end @implementation RACKVOChannel (RACChannelTo) - (RACChannelTerminal *)objectForKeyedSubscript:(NSString *)key { NSCParameterAssert(key != nil); RACChannelTerminal *terminal = [self valueForKey:key]; NSCAssert([terminal isKindOfClass:RACChannelTerminal.class], @"Key \"%@\" does not identify a channel terminal", key); return terminal; } - (void)setObject:(RACChannelTerminal *)otherTerminal forKeyedSubscript:(NSString *)key { NSCParameterAssert(otherTerminal != nil); RACChannelTerminal *selfTerminal = [self objectForKeyedSubscript:key]; [otherTerminal subscribe:selfTerminal]; [[selfTerminal skip:1] subscribe:otherTerminal]; } @end @implementation RACKVOChannelData + (instancetype)dataForChannel:(RACKVOChannel *)channel { RACKVOChannelData *data = [[self alloc] init]; data->_owner = (__bridge void *)channel; return data; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACKVOProxy.h ================================================ // // RACKVOProxy.h // ReactiveCocoa // // Created by Richard Speyer on 4/10/14. // Copyright (c) 2014 GitHub, Inc. All rights reserved. // #import /// A singleton that can act as a proxy between a KVO observation and a RAC /// subscriber, in order to protect against KVO lifetime issues. @interface RACKVOProxy : NSObject /// Returns the singleton KVO proxy object. + (instancetype)sharedProxy; /// Registers an observer with the proxy, such that when the proxy receives a /// KVO change with the given context, it forwards it to the observer. /// /// observer - True observer of the KVO change. Must not be nil. /// context - Arbitrary context object used to differentiate multiple /// observations of the same keypath. Must be unique, cannot be nil. - (void)addObserver:(__weak NSObject *)observer forContext:(void *)context; /// Removes an observer from the proxy. Parameters must match those passed to /// addObserver:forContext:. /// /// observer - True observer of the KVO change. Must not be nil. /// context - Arbitrary context object used to differentiate multiple /// observations of the same keypath. Must be unique, cannot be nil. - (void)removeObserver:(NSObject *)observer forContext:(void *)context; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACKVOProxy.m ================================================ // // RACKVOProxy.m // ReactiveCocoa // // Created by Richard Speyer on 4/10/14. // Copyright (c) 2014 GitHub, Inc. All rights reserved. // #import "RACKVOProxy.h" @interface RACKVOProxy() @property (strong, nonatomic, readonly) NSMapTable *trampolines; @property (strong, nonatomic, readonly) dispatch_queue_t queue; @end @implementation RACKVOProxy + (instancetype)sharedProxy { static RACKVOProxy *proxy; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ proxy = [[self alloc] init]; }); return proxy; } - (instancetype)init { self = [super init]; if (self == nil) return nil; _queue = dispatch_queue_create("org.reactivecocoa.ReactiveCocoa.RACKVOProxy", DISPATCH_QUEUE_SERIAL); _trampolines = [NSMapTable strongToWeakObjectsMapTable]; return self; } - (void)addObserver:(__weak NSObject *)observer forContext:(void *)context { NSValue *valueContext = [NSValue valueWithPointer:context]; dispatch_sync(self.queue, ^{ [self.trampolines setObject:observer forKey:valueContext]; }); } - (void)removeObserver:(NSObject *)observer forContext:(void *)context { NSValue *valueContext = [NSValue valueWithPointer:context]; dispatch_sync(self.queue, ^{ [self.trampolines removeObjectForKey:valueContext]; }); } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { NSValue *valueContext = [NSValue valueWithPointer:context]; __block NSObject *trueObserver; dispatch_sync(self.queue, ^{ trueObserver = [self.trampolines objectForKey:valueContext]; }); if (trueObserver != nil) { [trueObserver observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACKVOTrampoline.h ================================================ // // RACKVOTrampoline.h // ReactiveCocoa // // Created by Josh Abernathy on 1/15/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import "NSObject+RACKVOWrapper.h" #import "RACDisposable.h" // A private trampoline object that represents a KVO observation. // // Disposing of the trampoline will stop observation. @interface RACKVOTrampoline : RACDisposable // Initializes the receiver with the given parameters. // // target - The object whose key path should be observed. Cannot be nil. // observer - The object that gets notified when the value at the key path // changes. Can be nil. // keyPath - The key path on `target` to observe. Cannot be nil. // options - Any key value observing options to use in the observation. // block - The block to call when the value at the observed key path changes. // Cannot be nil. // // Returns the initialized object. - (id)initWithTarget:(__weak NSObject *)target observer:(__weak NSObject *)observer keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACKVOTrampoline.m ================================================ // // RACKVOTrampoline.m // ReactiveCocoa // // Created by Josh Abernathy on 1/15/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACKVOTrampoline.h" #import "NSObject+RACDeallocating.h" #import "RACCompoundDisposable.h" #import "RACKVOProxy.h" @interface RACKVOTrampoline () // The keypath which the trampoline is observing. @property (nonatomic, readonly, copy) NSString *keyPath; // These properties should only be manipulated while synchronized on the // receiver. @property (nonatomic, readonly, copy) RACKVOBlock block; @property (nonatomic, readonly, unsafe_unretained) NSObject *unsafeTarget; @property (nonatomic, readonly, weak) NSObject *weakTarget; @property (nonatomic, readonly, weak) NSObject *observer; @end @implementation RACKVOTrampoline #pragma mark Lifecycle - (id)initWithTarget:(__weak NSObject *)target observer:(__weak NSObject *)observer keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block { NSCParameterAssert(keyPath != nil); NSCParameterAssert(block != nil); NSObject *strongTarget = target; if (strongTarget == nil) return nil; self = [super init]; if (self == nil) return nil; _keyPath = [keyPath copy]; _block = [block copy]; _weakTarget = target; _unsafeTarget = strongTarget; _observer = observer; [RACKVOProxy.sharedProxy addObserver:self forContext:(__bridge void *)self]; [strongTarget addObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath options:options context:(__bridge void *)self]; [strongTarget.rac_deallocDisposable addDisposable:self]; [self.observer.rac_deallocDisposable addDisposable:self]; return self; } - (void)dealloc { [self dispose]; } #pragma mark Observation - (void)dispose { NSObject *target; NSObject *observer; @synchronized (self) { _block = nil; // The target should still exist at this point, because we still need to // tear down its KVO observation. Therefore, we can use the unsafe // reference (and need to, because the weak one will have been zeroed by // now). target = self.unsafeTarget; observer = self.observer; _unsafeTarget = nil; _observer = nil; } [target.rac_deallocDisposable removeDisposable:self]; [observer.rac_deallocDisposable removeDisposable:self]; [target removeObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath context:(__bridge void *)self]; [RACKVOProxy.sharedProxy removeObserver:self forContext:(__bridge void *)self]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (context != (__bridge void *)self) { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; return; } RACKVOBlock block; id observer; id target; @synchronized (self) { block = self.block; observer = self.observer; target = self.weakTarget; } if (block == nil || target == nil) return; block(target, observer, change); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACMulticastConnection+Private.h ================================================ // // RACMulticastConnection+Private.h // ReactiveCocoa // // Created by Josh Abernathy on 4/11/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACMulticastConnection.h" @class RACSubject; @interface RACMulticastConnection () - (id)initWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACMulticastConnection.h ================================================ // // RACMulticastConnection.h // ReactiveCocoa // // Created by Josh Abernathy on 4/11/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import @class RACDisposable; @class RACSignal; /// A multicast connection encapsulates the idea of sharing one subscription to a /// signal to many subscribers. This is most often needed if the subscription to /// the underlying signal involves side-effects or shouldn't be called more than /// once. /// /// The multicasted signal is only subscribed to when /// -[RACMulticastConnection connect] is called. Until that happens, no values /// will be sent on `signal`. See -[RACMulticastConnection autoconnect] for how /// -[RACMulticastConnection connect] can be called automatically. /// /// Note that you shouldn't create RACMulticastConnection manually. Instead use /// -[RACSignal publish] or -[RACSignal multicast:]. @interface RACMulticastConnection : NSObject /// The multicasted signal. @property (nonatomic, strong, readonly) RACSignal *signal; /// Connect to the underlying signal by subscribing to it. Calling this multiple /// times does nothing but return the existing connection's disposable. /// /// Returns the disposable for the subscription to the multicasted signal. - (RACDisposable *)connect; /// Connects to the underlying signal when the returned signal is first /// subscribed to, and disposes of the subscription to the multicasted signal /// when the returned signal has no subscribers. /// /// If new subscribers show up after being disposed, they'll subscribe and then /// be immediately disposed of. The returned signal will never re-connect to the /// multicasted signal. /// /// Returns the autoconnecting signal. - (RACSignal *)autoconnect; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACMulticastConnection.m ================================================ // // RACMulticastConnection.m // ReactiveCocoa // // Created by Josh Abernathy on 4/11/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACMulticastConnection.h" #import "RACMulticastConnection+Private.h" #import "RACDisposable.h" #import "RACSerialDisposable.h" #import "RACSubject.h" #import @interface RACMulticastConnection () { RACSubject *_signal; // When connecting, a caller should attempt to atomically swap the value of this // from `0` to `1`. // // If the swap is successful the caller is resposible for subscribing `_signal` // to `sourceSignal` and storing the returned disposable in `serialDisposable`. // // If the swap is unsuccessful it means that `_sourceSignal` has already been // connected and the caller has no action to take. int32_t volatile _hasConnected; } @property (nonatomic, readonly, strong) RACSignal *sourceSignal; @property (strong) RACSerialDisposable *serialDisposable; @end @implementation RACMulticastConnection #pragma mark Lifecycle - (id)initWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject { NSCParameterAssert(source != nil); NSCParameterAssert(subject != nil); self = [super init]; if (self == nil) return nil; _sourceSignal = source; _serialDisposable = [[RACSerialDisposable alloc] init]; _signal = subject; return self; } #pragma mark Connecting - (RACDisposable *)connect { BOOL shouldConnect = OSAtomicCompareAndSwap32Barrier(0, 1, &_hasConnected); if (shouldConnect) { self.serialDisposable.disposable = [self.sourceSignal subscribe:_signal]; } return self.serialDisposable; } - (RACSignal *)autoconnect { __block volatile int32_t subscriberCount = 0; return [[RACSignal createSignal:^(id subscriber) { OSAtomicIncrement32Barrier(&subscriberCount); RACDisposable *subscriptionDisposable = [self.signal subscribe:subscriber]; RACDisposable *connectionDisposable = [self connect]; return [RACDisposable disposableWithBlock:^{ [subscriptionDisposable dispose]; if (OSAtomicDecrement32Barrier(&subscriberCount) == 0) { [connectionDisposable dispose]; } }]; }] setNameWithFormat:@"[%@] -autoconnect", self.signal.name]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACObjCRuntime.h ================================================ // // RACObjCRuntime.h // ReactiveCocoa // // Created by Cody Krieger on 5/19/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import // A private class containing wrappers to runtime functions. @interface RACObjCRuntime : NSObject // Invokes objc_allocateClassPair(). Can be called from ARC code. + (Class)createClass:(const char *)className inheritingFromClass:(Class)superclass; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACObjCRuntime.m ================================================ // // RACObjCRuntime.m // ReactiveCocoa // // Created by Cody Krieger on 5/19/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACObjCRuntime.h" #import #if __has_feature(objc_arc) #error "This file must be compiled without ARC." #endif @implementation RACObjCRuntime + (Class)createClass:(const char *)className inheritingFromClass:(Class)superclass { return objc_allocateClassPair(superclass, className, 0); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACPassthroughSubscriber.h ================================================ // // RACPassthroughSubscriber.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-06-13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import "RACSubscriber.h" @class RACCompoundDisposable; @class RACSignal; // A private subscriber that passes through all events to another subscriber // while not disposed. @interface RACPassthroughSubscriber : NSObject // Initializes the receiver to pass through events until disposed. // // subscriber - The subscriber to forward events to. This must not be nil. // signal - The signal that will be sending events to the receiver. // disposable - When this disposable is disposed, no more events will be // forwarded. This must not be nil. // // Returns an initialized passthrough subscriber. - (instancetype)initWithSubscriber:(id)subscriber signal:(RACSignal *)signal disposable:(RACCompoundDisposable *)disposable; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACPassthroughSubscriber.m ================================================ // // RACPassthroughSubscriber.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-06-13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACPassthroughSubscriber.h" #import "RACCompoundDisposable.h" #import "RACSignal.h" #import "RACSignalProvider.h" #if !defined(DTRACE_PROBES_DISABLED) || !DTRACE_PROBES_DISABLED static const char *cleanedDTraceString(NSString *original) { return [original stringByReplacingOccurrencesOfString:@"\\s+" withString:@" " options:NSRegularExpressionSearch range:NSMakeRange(0, original.length)].UTF8String; } static const char *cleanedSignalDescription(RACSignal *signal) { NSString *desc = signal.description; NSRange range = [desc rangeOfString:@" name:"]; if (range.location != NSNotFound) { desc = [desc stringByReplacingCharactersInRange:range withString:@""]; } return cleanedDTraceString(desc); } #endif @interface RACPassthroughSubscriber () // The subscriber to which events should be forwarded. @property (nonatomic, strong, readonly) id innerSubscriber; // The signal sending events to this subscriber. // // This property isn't `weak` because it's only used for DTrace probes, so // a zeroing weak reference would incur an unnecessary performance penalty in // normal usage. @property (nonatomic, unsafe_unretained, readonly) RACSignal *signal; // A disposable representing the subscription. When disposed, no further events // should be sent to the `innerSubscriber`. @property (nonatomic, strong, readonly) RACCompoundDisposable *disposable; @end @implementation RACPassthroughSubscriber #pragma mark Lifecycle - (instancetype)initWithSubscriber:(id)subscriber signal:(RACSignal *)signal disposable:(RACCompoundDisposable *)disposable { NSCParameterAssert(subscriber != nil); self = [super init]; if (self == nil) return nil; _innerSubscriber = subscriber; _signal = signal; _disposable = disposable; [self.innerSubscriber didSubscribeWithDisposable:self.disposable]; return self; } #pragma mark RACSubscriber - (void)sendNext:(id)value { if (self.disposable.disposed) return; if (RACSIGNAL_NEXT_ENABLED()) { RACSIGNAL_NEXT(cleanedSignalDescription(self.signal), cleanedDTraceString(self.innerSubscriber.description), cleanedDTraceString([value description])); } [self.innerSubscriber sendNext:value]; } - (void)sendError:(NSError *)error { if (self.disposable.disposed) return; if (RACSIGNAL_ERROR_ENABLED()) { RACSIGNAL_ERROR(cleanedSignalDescription(self.signal), cleanedDTraceString(self.innerSubscriber.description), cleanedDTraceString(error.description)); } [self.innerSubscriber sendError:error]; } - (void)sendCompleted { if (self.disposable.disposed) return; if (RACSIGNAL_COMPLETED_ENABLED()) { RACSIGNAL_COMPLETED(cleanedSignalDescription(self.signal), cleanedDTraceString(self.innerSubscriber.description)); } [self.innerSubscriber sendCompleted]; } - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable { if (disposable != self.disposable) { [self.disposable addDisposable:disposable]; } } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACQueueScheduler+Subclass.h ================================================ // // RACQueueScheduler+Subclass.h // ReactiveCocoa // // Created by Josh Abernathy on 6/6/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACQueueScheduler.h" #import "RACScheduler+Subclass.h" /// An interface for use by GCD queue-based subclasses. /// /// See RACScheduler+Subclass.h for subclassing notes. @interface RACQueueScheduler () /// The queue on which blocks are enqueued. #if OS_OBJECT_USE_OBJC @property (nonatomic, strong, readonly) dispatch_queue_t queue; #else // Swift builds with OS_OBJECT_HAVE_OBJC_SUPPORT=0 for Playgrounds and LLDB :( @property (nonatomic, assign, readonly) dispatch_queue_t queue; #endif /// Initializes the receiver with the name of the scheduler and the queue which /// the scheduler should use. /// /// name - The name of the scheduler. If nil, a default name will be used. /// queue - The queue upon which the receiver should enqueue scheduled blocks. /// This argument must not be NULL. /// /// Returns the initialized object. - (id)initWithName:(NSString *)name queue:(dispatch_queue_t)queue; /// Converts a date into a GCD time using dispatch_walltime(). /// /// date - The date to convert. This must not be nil. + (dispatch_time_t)wallTimeWithDate:(NSDate *)date; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACQueueScheduler.h ================================================ // // RACQueueScheduler.h // ReactiveCocoa // // Created by Josh Abernathy on 11/30/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACScheduler.h" /// An abstract scheduler which asynchronously enqueues all its work to a Grand /// Central Dispatch queue. /// /// Because RACQueueScheduler is abstract, it should not be instantiated /// directly. Create a subclass using the `RACQueueScheduler+Subclass.h` /// interface and use that instead. @interface RACQueueScheduler : RACScheduler @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACQueueScheduler.m ================================================ // // RACQueueScheduler.m // ReactiveCocoa // // Created by Josh Abernathy on 11/30/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACQueueScheduler.h" #import "RACDisposable.h" #import "RACQueueScheduler+Subclass.h" #import "RACScheduler+Private.h" @implementation RACQueueScheduler #pragma mark Lifecycle - (id)initWithName:(NSString *)name queue:(dispatch_queue_t)queue { NSCParameterAssert(queue != NULL); self = [super initWithName:name]; if (self == nil) return nil; _queue = queue; #if !OS_OBJECT_USE_OBJC dispatch_retain(_queue); #endif return self; } #if !OS_OBJECT_USE_OBJC - (void)dealloc { if (_queue != NULL) { dispatch_release(_queue); _queue = NULL; } } #endif #pragma mark Date Conversions + (dispatch_time_t)wallTimeWithDate:(NSDate *)date { NSCParameterAssert(date != nil); double seconds = 0; double frac = modf(date.timeIntervalSince1970, &seconds); struct timespec walltime = { .tv_sec = (time_t)fmin(fmax(seconds, LONG_MIN), LONG_MAX), .tv_nsec = (long)fmin(fmax(frac * NSEC_PER_SEC, LONG_MIN), LONG_MAX) }; return dispatch_walltime(&walltime, 0); } #pragma mark RACScheduler - (RACDisposable *)schedule:(void (^)(void))block { NSCParameterAssert(block != NULL); RACDisposable *disposable = [[RACDisposable alloc] init]; dispatch_async(self.queue, ^{ if (disposable.disposed) return; [self performAsCurrentScheduler:block]; }); return disposable; } - (RACDisposable *)after:(NSDate *)date schedule:(void (^)(void))block { NSCParameterAssert(date != nil); NSCParameterAssert(block != NULL); RACDisposable *disposable = [[RACDisposable alloc] init]; dispatch_after([self.class wallTimeWithDate:date], self.queue, ^{ if (disposable.disposed) return; [self performAsCurrentScheduler:block]; }); return disposable; } - (RACDisposable *)after:(NSDate *)date repeatingEvery:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway schedule:(void (^)(void))block { NSCParameterAssert(date != nil); NSCParameterAssert(interval > 0.0 && interval < INT64_MAX / NSEC_PER_SEC); NSCParameterAssert(leeway >= 0.0 && leeway < INT64_MAX / NSEC_PER_SEC); NSCParameterAssert(block != NULL); uint64_t intervalInNanoSecs = (uint64_t)(interval * NSEC_PER_SEC); uint64_t leewayInNanoSecs = (uint64_t)(leeway * NSEC_PER_SEC); dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.queue); dispatch_source_set_timer(timer, [self.class wallTimeWithDate:date], intervalInNanoSecs, leewayInNanoSecs); dispatch_source_set_event_handler(timer, block); dispatch_resume(timer); return [RACDisposable disposableWithBlock:^{ dispatch_source_cancel(timer); }]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACReplaySubject.h ================================================ // // RACReplaySubject.h // ReactiveCocoa // // Created by Josh Abernathy on 3/14/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACSubject.h" extern const NSUInteger RACReplaySubjectUnlimitedCapacity; /// A replay subject saves the values it is sent (up to its defined capacity) /// and resends those to new subscribers. It will also replay an error or /// completion. @interface RACReplaySubject : RACSubject /// Creates a new replay subject with the given capacity. A capacity of /// RACReplaySubjectUnlimitedCapacity means values are never trimmed. + (instancetype)replaySubjectWithCapacity:(NSUInteger)capacity; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACReplaySubject.m ================================================ // // RACReplaySubject.m // ReactiveCocoa // // Created by Josh Abernathy on 3/14/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACReplaySubject.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACScheduler+Private.h" #import "RACSubscriber.h" #import "RACTuple.h" const NSUInteger RACReplaySubjectUnlimitedCapacity = NSUIntegerMax; @interface RACReplaySubject () @property (nonatomic, assign, readonly) NSUInteger capacity; // These properties should only be modified while synchronized on self. @property (nonatomic, strong, readonly) NSMutableArray *valuesReceived; @property (nonatomic, assign) BOOL hasCompleted; @property (nonatomic, assign) BOOL hasError; @property (nonatomic, strong) NSError *error; @end @implementation RACReplaySubject #pragma mark Lifecycle + (instancetype)replaySubjectWithCapacity:(NSUInteger)capacity { return [(RACReplaySubject *)[self alloc] initWithCapacity:capacity]; } - (instancetype)init { return [self initWithCapacity:RACReplaySubjectUnlimitedCapacity]; } - (instancetype)initWithCapacity:(NSUInteger)capacity { self = [super init]; if (self == nil) return nil; _capacity = capacity; _valuesReceived = (capacity == RACReplaySubjectUnlimitedCapacity ? [NSMutableArray array] : [NSMutableArray arrayWithCapacity:capacity]); return self; } #pragma mark RACSignal - (RACDisposable *)subscribe:(id)subscriber { RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable]; RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{ @synchronized (self) { for (id value in self.valuesReceived) { if (compoundDisposable.disposed) return; [subscriber sendNext:(value == RACTupleNil.tupleNil ? nil : value)]; } if (compoundDisposable.disposed) return; if (self.hasCompleted) { [subscriber sendCompleted]; } else if (self.hasError) { [subscriber sendError:self.error]; } else { RACDisposable *subscriptionDisposable = [super subscribe:subscriber]; [compoundDisposable addDisposable:subscriptionDisposable]; } } }]; [compoundDisposable addDisposable:schedulingDisposable]; return compoundDisposable; } #pragma mark RACSubscriber - (void)sendNext:(id)value { @synchronized (self) { [self.valuesReceived addObject:value ?: RACTupleNil.tupleNil]; [super sendNext:value]; if (self.capacity != RACReplaySubjectUnlimitedCapacity && self.valuesReceived.count > self.capacity) { [self.valuesReceived removeObjectsInRange:NSMakeRange(0, self.valuesReceived.count - self.capacity)]; } } } - (void)sendCompleted { @synchronized (self) { self.hasCompleted = YES; [super sendCompleted]; } } - (void)sendError:(NSError *)e { @synchronized (self) { self.hasError = YES; self.error = e; [super sendError:e]; } } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACReturnSignal.h ================================================ // // RACReturnSignal.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-10-10. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACSignal.h" // A private `RACSignal` subclasses that synchronously sends a value to any // subscribers, then completes. @interface RACReturnSignal : RACSignal + (RACSignal *)return:(id)value; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACReturnSignal.m ================================================ // // RACReturnSignal.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-10-10. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACReturnSignal.h" #import "RACScheduler+Private.h" #import "RACSubscriber.h" #import "RACUnit.h" @interface RACReturnSignal () // The value to send upon subscription. @property (nonatomic, strong, readonly) id value; @end @implementation RACReturnSignal #pragma mark Properties // Only allow this signal's name to be customized in DEBUG, since it's // potentially a singleton in release builds (see +return:). - (void)setName:(NSString *)name { #ifdef DEBUG [super setName:name]; #endif } - (NSString *)name { #ifdef DEBUG return super.name; #else return @"+return:"; #endif } #pragma mark Lifecycle + (RACSignal *)return:(id)value { #ifndef DEBUG // In release builds, use singletons for two very common cases. if (value == RACUnit.defaultUnit) { static RACReturnSignal *unitSingleton; static dispatch_once_t unitPred; dispatch_once(&unitPred, ^{ unitSingleton = [[self alloc] init]; unitSingleton->_value = RACUnit.defaultUnit; }); return unitSingleton; } else if (value == nil) { static RACReturnSignal *nilSingleton; static dispatch_once_t nilPred; dispatch_once(&nilPred, ^{ nilSingleton = [[self alloc] init]; nilSingleton->_value = nil; }); return nilSingleton; } #endif RACReturnSignal *signal = [[self alloc] init]; signal->_value = value; #ifdef DEBUG [signal setNameWithFormat:@"+return: %@", value]; #endif return signal; } #pragma mark Subscription - (RACDisposable *)subscribe:(id)subscriber { NSCParameterAssert(subscriber != nil); return [RACScheduler.subscriptionScheduler schedule:^{ [subscriber sendNext:self.value]; [subscriber sendCompleted]; }]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACScheduler+Private.h ================================================ // // RACScheduler+Private.h // ReactiveCocoa // // Created by Josh Abernathy on 11/29/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACScheduler.h" // The thread-specific current scheduler key. extern NSString * const RACSchedulerCurrentSchedulerKey; // A private interface for internal RAC use only. @interface RACScheduler () // A dedicated scheduler that fills two requirements: // // 1. By the time subscription happens, we need a valid +currentScheduler. // 2. Subscription should happen as soon as possible. // // To fulfill those two, if we already have a valid +currentScheduler, it // immediately executes scheduled blocks. If we don't, it will execute scheduled // blocks with a private background scheduler. + (instancetype)subscriptionScheduler; // Initializes the receiver with the given name. // // name - The name of the scheduler. If nil, a default name will be used. // // Returns the initialized object. - (id)initWithName:(NSString *)name; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACScheduler+Subclass.h ================================================ // // RACScheduler.m // ReactiveCocoa // // Created by Miķelis Vindavs on 5/27/14. // Copyright (c) 2014 GitHub, Inc. All rights reserved. // #import #import "RACScheduler.h" /// An interface for use by subclasses. /// /// Subclasses should use `-performAsCurrentScheduler:` to do the actual block /// invocation so that +[RACScheduler currentScheduler] behaves as expected. /// /// **Note that RACSchedulers are expected to be serial**. Subclasses must honor /// that contract. See `RACTargetQueueScheduler` for a queue-based scheduler /// which will enforce the serialization guarantee. @interface RACScheduler () /// Performs the given block with the receiver as the current scheduler for /// its thread. This should only be called by subclasses to perform their /// scheduled blocks. /// /// block - The block to execute. Cannot be NULL. - (void)performAsCurrentScheduler:(void (^)(void))block; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACScheduler.h ================================================ // // RACScheduler.h // ReactiveCocoa // // Created by Josh Abernathy on 4/16/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import /// The priority for the scheduler. /// /// RACSchedulerPriorityHigh - High priority. /// RACSchedulerPriorityDefault - Default priority. /// RACSchedulerPriorityLow - Low priority. /// RACSchedulerPriorityBackground - Background priority. typedef enum : long { RACSchedulerPriorityHigh = DISPATCH_QUEUE_PRIORITY_HIGH, RACSchedulerPriorityDefault = DISPATCH_QUEUE_PRIORITY_DEFAULT, RACSchedulerPriorityLow = DISPATCH_QUEUE_PRIORITY_LOW, RACSchedulerPriorityBackground = DISPATCH_QUEUE_PRIORITY_BACKGROUND, } RACSchedulerPriority; /// Scheduled with -scheduleRecursiveBlock:, this type of block is passed a block /// with which it can call itself recursively. typedef void (^RACSchedulerRecursiveBlock)(void (^reschedule)(void)); @class RACDisposable; /// Schedulers are used to control when and where work is performed. @interface RACScheduler : NSObject /// A singleton scheduler that immediately executes the blocks it is given. /// /// **Note:** Unlike most other schedulers, this does not set the current /// scheduler. There may still be a valid +currentScheduler if this is used /// within a block scheduled on a different scheduler. + (RACScheduler *)immediateScheduler; /// A singleton scheduler that executes blocks in the main thread. + (RACScheduler *)mainThreadScheduler; /// Creates and returns a new background scheduler with the given priority and /// name. The name is for debug and instrumentation purposes only. /// /// Scheduler creation is cheap. It's unnecessary to save the result of this /// method call unless you want to serialize some actions on the same background /// scheduler. + (RACScheduler *)schedulerWithPriority:(RACSchedulerPriority)priority name:(NSString *)name; /// Invokes +schedulerWithPriority:name: with a default name. + (RACScheduler *)schedulerWithPriority:(RACSchedulerPriority)priority; /// Invokes +schedulerWithPriority: with RACSchedulerPriorityDefault. + (RACScheduler *)scheduler; /// The current scheduler. This will only be valid when used from within a /// -[RACScheduler schedule:] block or when on the main thread. + (RACScheduler *)currentScheduler; /// Schedule the given block for execution on the scheduler. /// /// Scheduled blocks will be executed in the order in which they were scheduled. /// /// block - The block to schedule for execution. Cannot be nil. /// /// Returns a disposable which can be used to cancel the scheduled block before /// it begins executing, or nil if cancellation is not supported. - (RACDisposable *)schedule:(void (^)(void))block; /// Schedule the given block for execution on the scheduler at or after /// a specific time. /// /// Note that blocks scheduled for a certain time will not preempt any other /// scheduled work that is executing at the time. /// /// When invoked on the +immediateScheduler, the calling thread **will block** /// until the specified time. /// /// date - The earliest time at which `block` should begin executing. The block /// may not execute immediately at this time, whether due to system load /// or another block on the scheduler currently being run. Cannot be nil. /// block - The block to schedule for execution. Cannot be nil. /// /// Returns a disposable which can be used to cancel the scheduled block before /// it begins executing, or nil if cancellation is not supported. - (RACDisposable *)after:(NSDate *)date schedule:(void (^)(void))block; /// Schedule the given block for execution on the scheduler after the delay. /// /// Converts the delay into an NSDate, then invokes `-after:schedule:`. - (RACDisposable *)afterDelay:(NSTimeInterval)delay schedule:(void (^)(void))block; /// Reschedule the given block at a particular interval, starting at a specific /// time, and with a given leeway for deferral. /// /// Note that blocks scheduled for a certain time will not preempt any other /// scheduled work that is executing at the time. /// /// Regardless of the value of `leeway`, the given block may not execute exactly /// at `when` or exactly on successive intervals, whether due to system load or /// because another block is currently being run on the scheduler. /// /// It is considered undefined behavior to invoke this method on the /// +immediateScheduler. /// /// date - The earliest time at which `block` should begin executing. The /// block may not execute immediately at this time, whether due to /// system load or another block on the scheduler currently being /// run. Cannot be nil. /// interval - The interval at which the block should be rescheduled, starting /// from `date`. This will use the system wall clock, to avoid /// skew when the computer goes to sleep. /// leeway - A hint to the system indicating the number of seconds that each /// scheduling can be deferred. Note that this is just a hint, and /// there may be some additional latency no matter what. /// block - The block to repeatedly schedule for execution. Cannot be nil. /// /// Returns a disposable which can be used to cancel the automatic scheduling and /// rescheduling, or nil if cancellation is not supported. - (RACDisposable *)after:(NSDate *)date repeatingEvery:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway schedule:(void (^)(void))block; /// Schedule the given recursive block for execution on the scheduler. The /// scheduler will automatically flatten any recursive scheduling into iteration /// instead, so this can be used without issue for blocks that may keep invoking /// themselves forever. /// /// Scheduled blocks will be executed in the order in which they were scheduled. /// /// recursiveBlock - The block to schedule for execution. When invoked, the /// recursive block will be passed a `void (^)(void)` block /// which will reschedule the recursive block at the end of the /// receiver's queue. This passed-in block will automatically /// skip scheduling if the scheduling of the `recursiveBlock` /// was disposed in the meantime. /// /// Returns a disposable which can be used to cancel the scheduled block before /// it begins executing, or to stop it from rescheduling if it's already begun /// execution. - (RACDisposable *)scheduleRecursiveBlock:(RACSchedulerRecursiveBlock)recursiveBlock; @end @interface RACScheduler (Unavailable) + (RACScheduler *)schedulerWithQueue:(dispatch_queue_t)queue name:(NSString *)name __attribute__((unavailable("Use -[RACTargetQueueScheduler initWithName:targetQueue:] instead."))); @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACScheduler.m ================================================ // // RACScheduler.m // ReactiveCocoa // // Created by Josh Abernathy on 4/16/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACScheduler.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACImmediateScheduler.h" #import "RACScheduler+Private.h" #import "RACSubscriptionScheduler.h" #import "RACTargetQueueScheduler.h" // The key for the thread-specific current scheduler. NSString * const RACSchedulerCurrentSchedulerKey = @"RACSchedulerCurrentSchedulerKey"; @interface RACScheduler () @property (nonatomic, readonly, copy) NSString *name; @end @implementation RACScheduler #pragma mark NSObject - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p> %@", self.class, self, self.name]; } #pragma mark Initializers - (id)initWithName:(NSString *)name { self = [super init]; if (self == nil) return nil; if (name == nil) { _name = [NSString stringWithFormat:@"com.ReactiveCocoa.%@.anonymousScheduler", self.class]; } else { _name = [name copy]; } return self; } #pragma mark Schedulers + (instancetype)immediateScheduler { static dispatch_once_t onceToken; static RACScheduler *immediateScheduler; dispatch_once(&onceToken, ^{ immediateScheduler = [[RACImmediateScheduler alloc] init]; }); return immediateScheduler; } + (instancetype)mainThreadScheduler { static dispatch_once_t onceToken; static RACScheduler *mainThreadScheduler; dispatch_once(&onceToken, ^{ mainThreadScheduler = [[RACTargetQueueScheduler alloc] initWithName:@"com.ReactiveCocoa.RACScheduler.mainThreadScheduler" targetQueue:dispatch_get_main_queue()]; }); return mainThreadScheduler; } + (instancetype)schedulerWithPriority:(RACSchedulerPriority)priority name:(NSString *)name { return [[RACTargetQueueScheduler alloc] initWithName:name targetQueue:dispatch_get_global_queue(priority, 0)]; } + (instancetype)schedulerWithPriority:(RACSchedulerPriority)priority { return [self schedulerWithPriority:priority name:@"com.ReactiveCocoa.RACScheduler.backgroundScheduler"]; } + (instancetype)scheduler { return [self schedulerWithPriority:RACSchedulerPriorityDefault]; } + (instancetype)subscriptionScheduler { static dispatch_once_t onceToken; static RACScheduler *subscriptionScheduler; dispatch_once(&onceToken, ^{ subscriptionScheduler = [[RACSubscriptionScheduler alloc] init]; }); return subscriptionScheduler; } + (BOOL)isOnMainThread { return [NSOperationQueue.currentQueue isEqual:NSOperationQueue.mainQueue] || [NSThread isMainThread]; } + (instancetype)currentScheduler { RACScheduler *scheduler = NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey]; if (scheduler != nil) return scheduler; if ([self.class isOnMainThread]) return RACScheduler.mainThreadScheduler; return nil; } #pragma mark Scheduling - (RACDisposable *)schedule:(void (^)(void))block { NSCAssert(NO, @"%@ must be implemented by subclasses.", NSStringFromSelector(_cmd)); return nil; } - (RACDisposable *)after:(NSDate *)date schedule:(void (^)(void))block { NSCAssert(NO, @"%@ must be implemented by subclasses.", NSStringFromSelector(_cmd)); return nil; } - (RACDisposable *)afterDelay:(NSTimeInterval)delay schedule:(void (^)(void))block { return [self after:[NSDate dateWithTimeIntervalSinceNow:delay] schedule:block]; } - (RACDisposable *)after:(NSDate *)date repeatingEvery:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway schedule:(void (^)(void))block { NSCAssert(NO, @"%@ must be implemented by subclasses.", NSStringFromSelector(_cmd)); return nil; } - (RACDisposable *)scheduleRecursiveBlock:(RACSchedulerRecursiveBlock)recursiveBlock { RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable]; [self scheduleRecursiveBlock:[recursiveBlock copy] addingToDisposable:disposable]; return disposable; } - (void)scheduleRecursiveBlock:(RACSchedulerRecursiveBlock)recursiveBlock addingToDisposable:(RACCompoundDisposable *)disposable { @autoreleasepool { RACCompoundDisposable *selfDisposable = [RACCompoundDisposable compoundDisposable]; [disposable addDisposable:selfDisposable]; __weak RACDisposable *weakSelfDisposable = selfDisposable; RACDisposable *schedulingDisposable = [self schedule:^{ @autoreleasepool { // At this point, we've been invoked, so our disposable is now useless. [disposable removeDisposable:weakSelfDisposable]; } if (disposable.disposed) return; void (^reallyReschedule)(void) = ^{ if (disposable.disposed) return; [self scheduleRecursiveBlock:recursiveBlock addingToDisposable:disposable]; }; // Protects the variables below. // // This doesn't actually need to be __block qualified, but Clang // complains otherwise. :C __block NSLock *lock = [[NSLock alloc] init]; lock.name = [NSString stringWithFormat:@"%@ %s", self, sel_getName(_cmd)]; __block NSUInteger rescheduleCount = 0; // Set to YES once synchronous execution has finished. Further // rescheduling should occur immediately (rather than being // flattened). __block BOOL rescheduleImmediately = NO; @autoreleasepool { recursiveBlock(^{ [lock lock]; BOOL immediate = rescheduleImmediately; if (!immediate) ++rescheduleCount; [lock unlock]; if (immediate) reallyReschedule(); }); } [lock lock]; NSUInteger synchronousCount = rescheduleCount; rescheduleImmediately = YES; [lock unlock]; for (NSUInteger i = 0; i < synchronousCount; i++) { reallyReschedule(); } }]; [selfDisposable addDisposable:schedulingDisposable]; } } - (void)performAsCurrentScheduler:(void (^)(void))block { NSCParameterAssert(block != NULL); // If we're using a concurrent queue, we could end up in here concurrently, // in which case we *don't* want to clear the current scheduler immediately // after our block is done executing, but only *after* all our concurrent // invocations are done. RACScheduler *previousScheduler = RACScheduler.currentScheduler; NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey] = self; @autoreleasepool { block(); } if (previousScheduler != nil) { NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey] = previousScheduler; } else { [NSThread.currentThread.threadDictionary removeObjectForKey:RACSchedulerCurrentSchedulerKey]; } } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACScopedDisposable.h ================================================ // // RACScopedDisposable.h // ReactiveCocoa // // Created by Josh Abernathy on 3/28/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACDisposable.h" /// A disposable that calls its own -dispose when it is dealloc'd. @interface RACScopedDisposable : RACDisposable /// Creates a new scoped disposable that will also dispose of the given /// disposable when it is dealloc'd. + (instancetype)scopedDisposableWithDisposable:(RACDisposable *)disposable; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACScopedDisposable.m ================================================ // // RACScopedDisposable.m // ReactiveCocoa // // Created by Josh Abernathy on 3/28/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACScopedDisposable.h" @implementation RACScopedDisposable #pragma mark Lifecycle + (instancetype)scopedDisposableWithDisposable:(RACDisposable *)disposable { return [self disposableWithBlock:^{ [disposable dispose]; }]; } - (void)dealloc { [self dispose]; } #pragma mark RACDisposable - (RACScopedDisposable *)asScopedDisposable { // totally already are return self; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSequence.h ================================================ // // RACSequence.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import #import "RACStream.h" @class RACScheduler; @class RACSignal; /// Represents an immutable sequence of values. Unless otherwise specified, the /// sequences' values are evaluated lazily on demand. Like Cocoa collections, /// sequences cannot contain nil. /// /// Most inherited RACStream methods that accept a block will execute the block /// _at most_ once for each value that is evaluated in the returned sequence. /// Side effects are subject to the behavior described in /// +sequenceWithHeadBlock:tailBlock:. /// /// Implemented as a class cluster. A minimal implementation for a subclass /// consists simply of -head and -tail. @interface RACSequence : RACStream /// The first object in the sequence, or nil if the sequence is empty. /// /// Subclasses must provide an implementation of this method. @property (nonatomic, strong, readonly) id head; /// All but the first object in the sequence, or nil if the sequence is empty. /// /// Subclasses must provide an implementation of this method. @property (nonatomic, strong, readonly) RACSequence *tail; /// Evaluates the full sequence to produce an equivalently-sized array. @property (nonatomic, copy, readonly) NSArray *array; /// Returns an enumerator of all objects in the sequence. @property (nonatomic, copy, readonly) NSEnumerator *objectEnumerator; /// Converts a sequence into an eager sequence. /// /// An eager sequence fully evaluates all of its values immediately. Sequences /// derived from an eager sequence will also be eager. /// /// Returns a new eager sequence, or the receiver if the sequence is already /// eager. @property (nonatomic, copy, readonly) RACSequence *eagerSequence; /// Converts a sequence into a lazy sequence. /// /// A lazy sequence evaluates its values on demand, as they are accessed. /// Sequences derived from a lazy sequence will also be lazy. /// /// Returns a new lazy sequence, or the receiver if the sequence is already lazy. @property (nonatomic, copy, readonly) RACSequence *lazySequence; /// Invokes -signalWithScheduler: with a new RACScheduler. - (RACSignal *)signal; /// Evaluates the full sequence on the given scheduler. /// /// Each item is evaluated in its own scheduled block, such that control of the /// scheduler is yielded between each value. /// /// Returns a signal which sends the receiver's values on the given scheduler as /// they're evaluated. - (RACSignal *)signalWithScheduler:(RACScheduler *)scheduler; /// Applies a left fold to the sequence. /// /// This is the same as iterating the sequence along with a provided start value. /// This uses a constant amount of memory. A left fold is left-associative so in /// the sequence [1,2,3] the block would applied in the following order: /// reduce(reduce(reduce(start, 1), 2), 3) /// /// start - The starting value for the fold. Used as `accumulator` for the /// first fold. /// reduce - The block used to combine the accumulated value and the next value. /// Cannot be nil. /// /// Returns a reduced value. - (id)foldLeftWithStart:(id)start reduce:(id (^)(id accumulator, id value))reduce; /// Applies a right fold to the sequence. /// /// A right fold is equivalent to recursion on the list. The block is evaluated /// from the right to the left in list. It is right associative so it's applied /// to the rightmost elements first. For example, in the sequence [1,2,3] the /// block is applied in the order: /// reduce(1, reduce(2, reduce(3, start))) /// /// start - The starting value for the fold. /// reduce - The block used to combine the accumulated value and the next head. /// The block is given the accumulated value and the value of the rest /// of the computation (result of the recursion). This is computed when /// you retrieve its value using `rest.head`. This allows you to /// prevent unnecessary computation by not accessing `rest.head` if you /// don't need to. /// /// Returns a reduced value. - (id)foldRightWithStart:(id)start reduce:(id (^)(id first, RACSequence *rest))reduce; /// Check if any value in sequence passes the block. /// /// block - The block predicate used to check each item. Cannot be nil. /// /// Returns a boolean indiciating if any value in the sequence passed. - (BOOL)any:(BOOL (^)(id value))block; /// Check if all values in the sequence pass the block. /// /// block - The block predicate used to check each item. Cannot be nil. /// /// Returns a boolean indicating if all values in the sequence passed. - (BOOL)all:(BOOL (^)(id value))block; /// Returns the first object that passes the block. /// /// block - The block predicate used to check each item. Cannot be nil. /// /// Returns an object that passes the block or nil if no objects passed. - (id)objectPassingTest:(BOOL (^)(id value))block; /// Creates a sequence that dynamically generates its values. /// /// headBlock - Invoked the first time -head is accessed. /// tailBlock - Invoked the first time -tail is accessed. /// /// The results from each block are memoized, so each block will be invoked at /// most once, no matter how many times the head and tail properties of the /// sequence are accessed. /// /// Any side effects in `headBlock` or `tailBlock` should be thread-safe, since /// the sequence may be evaluated at any time from any thread. Not only that, but /// -tail may be accessed before -head, or both may be accessed simultaneously. /// As noted above, side effects will only be triggered the _first_ time -head or /// -tail is invoked. /// /// Returns a sequence that lazily invokes the given blocks to provide head and /// tail. `headBlock` must not be nil. + (RACSequence *)sequenceWithHeadBlock:(id (^)(void))headBlock tailBlock:(RACSequence *(^)(void))tailBlock; @end @interface RACSequence (Unavailable) - (id)foldLeftWithStart:(id)start combine:(id (^)(id accumulator, id value))combine __attribute__((unavailable("Renamed to -foldLeftWithStart:reduce:"))); - (id)foldRightWithStart:(id)start combine:(id (^)(id first, RACSequence *rest))combine __attribute__((unavailable("Renamed to -foldRightWithStart:reduce:"))); @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSequence.m ================================================ // // RACSequence.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import "RACSequence.h" #import "RACArraySequence.h" #import "RACDynamicSequence.h" #import "RACEagerSequence.h" #import "RACEmptySequence.h" #import "RACScheduler.h" #import "RACSignal.h" #import "RACSubscriber.h" #import "RACTuple.h" #import "RACUnarySequence.h" // An enumerator over sequences. @interface RACSequenceEnumerator : NSEnumerator // The sequence the enumerator is enumerating. // // This will change as the enumerator is exhausted. This property should only be // accessed while synchronized on self. @property (nonatomic, strong) RACSequence *sequence; @end @interface RACSequence () // Performs one iteration of lazy binding, passing through values from `current` // until the sequence is exhausted, then recursively binding the remaining // values in the receiver. // // Returns a new sequence which contains `current`, followed by the combined // result of all applications of `block` to the remaining values in the receiver. - (instancetype)bind:(RACStreamBindBlock)block passingThroughValuesFromSequence:(RACSequence *)current; @end @implementation RACSequenceEnumerator - (id)nextObject { id object = nil; @synchronized (self) { object = self.sequence.head; self.sequence = self.sequence.tail; } return object; } @end @implementation RACSequence #pragma mark Lifecycle + (RACSequence *)sequenceWithHeadBlock:(id (^)(void))headBlock tailBlock:(RACSequence *(^)(void))tailBlock { return [[RACDynamicSequence sequenceWithHeadBlock:headBlock tailBlock:tailBlock] setNameWithFormat:@"+sequenceWithHeadBlock:tailBlock:"]; } #pragma mark Class cluster primitives - (id)head { NSCAssert(NO, @"%s must be overridden by subclasses", __func__); return nil; } - (RACSequence *)tail { NSCAssert(NO, @"%s must be overridden by subclasses", __func__); return nil; } #pragma mark RACStream + (instancetype)empty { return RACEmptySequence.empty; } + (instancetype)return:(id)value { return [RACUnarySequence return:value]; } - (instancetype)bind:(RACStreamBindBlock (^)(void))block { RACStreamBindBlock bindBlock = block(); return [[self bind:bindBlock passingThroughValuesFromSequence:nil] setNameWithFormat:@"[%@] -bind:", self.name]; } - (instancetype)bind:(RACStreamBindBlock)bindBlock passingThroughValuesFromSequence:(RACSequence *)passthroughSequence { // Store values calculated in the dependency here instead, avoiding any kind // of temporary collection and boxing. // // This relies on the implementation of RACDynamicSequence synchronizing // access to its head, tail, and dependency, and we're only doing it because // we really need the performance. __block RACSequence *valuesSeq = self; __block RACSequence *current = passthroughSequence; __block BOOL stop = NO; RACSequence *sequence = [RACDynamicSequence sequenceWithLazyDependency:^ id { while (current.head == nil) { if (stop) return nil; // We've exhausted the current sequence, create a sequence from the // next value. id value = valuesSeq.head; if (value == nil) { // We've exhausted all the sequences. stop = YES; return nil; } current = (id)bindBlock(value, &stop); if (current == nil) { stop = YES; return nil; } valuesSeq = valuesSeq.tail; } NSCAssert([current isKindOfClass:RACSequence.class], @"-bind: block returned an object that is not a sequence: %@", current); return nil; } headBlock:^(id _) { return current.head; } tailBlock:^ id (id _) { if (stop) return nil; return [valuesSeq bind:bindBlock passingThroughValuesFromSequence:current.tail]; }]; sequence.name = self.name; return sequence; } - (instancetype)concat:(RACStream *)stream { NSCParameterAssert(stream != nil); return [[[RACArraySequence sequenceWithArray:@[ self, stream ] offset:0] flatten] setNameWithFormat:@"[%@] -concat: %@", self.name, stream]; } - (instancetype)zipWith:(RACSequence *)sequence { NSCParameterAssert(sequence != nil); return [[RACSequence sequenceWithHeadBlock:^ id { if (self.head == nil || sequence.head == nil) return nil; return RACTuplePack(self.head, sequence.head); } tailBlock:^ id { if (self.tail == nil || [[RACSequence empty] isEqual:self.tail]) return nil; if (sequence.tail == nil || [[RACSequence empty] isEqual:sequence.tail]) return nil; return [self.tail zipWith:sequence.tail]; }] setNameWithFormat:@"[%@] -zipWith: %@", self.name, sequence]; } #pragma mark Extended methods - (NSArray *)array { NSMutableArray *array = [NSMutableArray array]; for (id obj in self) { [array addObject:obj]; } return [array copy]; } - (NSEnumerator *)objectEnumerator { RACSequenceEnumerator *enumerator = [[RACSequenceEnumerator alloc] init]; enumerator.sequence = self; return enumerator; } - (RACSignal *)signal { return [[self signalWithScheduler:[RACScheduler scheduler]] setNameWithFormat:@"[%@] -signal", self.name]; } - (RACSignal *)signalWithScheduler:(RACScheduler *)scheduler { return [[RACSignal createSignal:^(id subscriber) { __block RACSequence *sequence = self; return [scheduler scheduleRecursiveBlock:^(void (^reschedule)(void)) { if (sequence.head == nil) { [subscriber sendCompleted]; return; } [subscriber sendNext:sequence.head]; sequence = sequence.tail; reschedule(); }]; }] setNameWithFormat:@"[%@] -signalWithScheduler: %@", self.name, scheduler]; } - (id)foldLeftWithStart:(id)start reduce:(id (^)(id, id))reduce { NSCParameterAssert(reduce != NULL); if (self.head == nil) return start; for (id value in self) { start = reduce(start, value); } return start; } - (id)foldRightWithStart:(id)start reduce:(id (^)(id, RACSequence *))reduce { NSCParameterAssert(reduce != NULL); if (self.head == nil) return start; RACSequence *rest = [RACSequence sequenceWithHeadBlock:^{ return [self.tail foldRightWithStart:start reduce:reduce]; } tailBlock:nil]; return reduce(self.head, rest); } - (BOOL)any:(BOOL (^)(id))block { NSCParameterAssert(block != NULL); return [self objectPassingTest:block] != nil; } - (BOOL)all:(BOOL (^)(id))block { NSCParameterAssert(block != NULL); NSNumber *result = [self foldLeftWithStart:@YES reduce:^(NSNumber *accumulator, id value) { return @(accumulator.boolValue && block(value)); }]; return result.boolValue; } - (id)objectPassingTest:(BOOL (^)(id))block { NSCParameterAssert(block != NULL); return [self filter:block].head; } - (RACSequence *)eagerSequence { return [RACEagerSequence sequenceWithArray:self.array offset:0]; } - (RACSequence *)lazySequence { return self; } #pragma mark NSCopying - (id)copyWithZone:(NSZone *)zone { return self; } #pragma mark NSCoding - (Class)classForCoder { // Most sequences should be archived as RACArraySequences. return RACArraySequence.class; } - (id)initWithCoder:(NSCoder *)coder { if (![self isKindOfClass:RACArraySequence.class]) return [[RACArraySequence alloc] initWithCoder:coder]; // Decoding is handled in RACArraySequence. return [super init]; } - (void)encodeWithCoder:(NSCoder *)coder { [coder encodeObject:self.array forKey:@"array"]; } #pragma mark NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(__unsafe_unretained id *)stackbuf count:(NSUInteger)len { if (state->state == ULONG_MAX) { // Enumeration has completed. return 0; } // We need to traverse the sequence itself on repeated calls to this // method, so use the 'state' field to track the current head. RACSequence *(^getSequence)(void) = ^{ return (__bridge RACSequence *)(void *)state->state; }; void (^setSequence)(RACSequence *) = ^(RACSequence *sequence) { // Release the old sequence and retain the new one. CFBridgingRelease((void *)state->state); state->state = (unsigned long)CFBridgingRetain(sequence); }; void (^complete)(void) = ^{ // Release any stored sequence. setSequence(nil); state->state = ULONG_MAX; }; if (state->state == 0) { // Since a sequence doesn't mutate, this just needs to be set to // something non-NULL. state->mutationsPtr = state->extra; setSequence(self); } state->itemsPtr = stackbuf; NSUInteger enumeratedCount = 0; while (enumeratedCount < len) { RACSequence *seq = getSequence(); // Because the objects in a sequence may be generated lazily, we want to // prevent them from being released until the enumerator's used them. __autoreleasing id obj = seq.head; if (obj == nil) { complete(); break; } stackbuf[enumeratedCount++] = obj; if (seq.tail == nil) { complete(); break; } setSequence(seq.tail); } return enumeratedCount; } #pragma mark NSObject - (NSUInteger)hash { return [self.head hash]; } - (BOOL)isEqual:(RACSequence *)seq { if (self == seq) return YES; if (![seq isKindOfClass:RACSequence.class]) return NO; for (id selfObj in self) { id seqObj = seq.head; // Handles the nil case too. if (![seqObj isEqual:selfObj]) return NO; seq = seq.tail; } // self is now depleted -- the argument should be too. return (seq.head == nil); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSerialDisposable.h ================================================ // // RACSerialDisposable.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-07-22. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACDisposable.h" /// A disposable that contains exactly one other disposable and allows it to be /// swapped out atomically. @interface RACSerialDisposable : RACDisposable /// The inner disposable managed by the serial disposable. /// /// This property is thread-safe for reading and writing. However, if you want to /// read the current value _and_ write a new one atomically, use /// -swapInDisposable: instead. /// /// Disposing of the receiver will also dispose of the current disposable set for /// this property, then set the property to nil. If any new disposable is set /// after the receiver is disposed, it will be disposed immediately and this /// property will remain set to nil. @property (atomic, strong) RACDisposable *disposable; /// Creates a serial disposable which will wrap the given disposable. /// /// disposable - The value to set for `disposable`. This may be nil. /// /// Returns a RACSerialDisposable, or nil if an error occurs. + (instancetype)serialDisposableWithDisposable:(RACDisposable *)disposable; /// Atomically swaps the receiver's `disposable` for `newDisposable`. /// /// newDisposable - The new value for `disposable`. If the receiver has already /// been disposed, this disposable will be too, and `disposable` /// will remain set to nil. This argument may be nil. /// /// Returns the previous value for the `disposable` property. - (RACDisposable *)swapInDisposable:(RACDisposable *)newDisposable; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSerialDisposable.m ================================================ // // RACSerialDisposable.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-07-22. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACSerialDisposable.h" #import @interface RACSerialDisposable () { // The receiver's `disposable`. This variable must only be referenced while // _spinLock is held. RACDisposable * _disposable; // YES if the receiver has been disposed. This variable must only be modified // while _spinLock is held. BOOL _disposed; // A spinlock to protect access to _disposable and _disposed. // // It must be used when _disposable is mutated or retained and when _disposed // is mutated. OSSpinLock _spinLock; } @end @implementation RACSerialDisposable #pragma mark Properties - (BOOL)isDisposed { return _disposed; } - (RACDisposable *)disposable { RACDisposable *result; OSSpinLockLock(&_spinLock); result = _disposable; OSSpinLockUnlock(&_spinLock); return result; } - (void)setDisposable:(RACDisposable *)disposable { [self swapInDisposable:disposable]; } #pragma mark Lifecycle + (instancetype)serialDisposableWithDisposable:(RACDisposable *)disposable { RACSerialDisposable *serialDisposable = [[self alloc] init]; serialDisposable.disposable = disposable; return serialDisposable; } - (id)initWithBlock:(void (^)(void))block { self = [self init]; if (self == nil) return nil; self.disposable = [RACDisposable disposableWithBlock:block]; return self; } #pragma mark Inner Disposable - (RACDisposable *)swapInDisposable:(RACDisposable *)newDisposable { RACDisposable *existingDisposable; BOOL alreadyDisposed; OSSpinLockLock(&_spinLock); alreadyDisposed = _disposed; if (!alreadyDisposed) { existingDisposable = _disposable; _disposable = newDisposable; } OSSpinLockUnlock(&_spinLock); if (alreadyDisposed) { [newDisposable dispose]; return nil; } return existingDisposable; } #pragma mark Disposal - (void)dispose { RACDisposable *existingDisposable; OSSpinLockLock(&_spinLock); if (!_disposed) { existingDisposable = _disposable; _disposed = YES; _disposable = nil; } OSSpinLockUnlock(&_spinLock); [existingDisposable dispose]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSignal+Operations.h ================================================ // // RACSignal+Operations.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-09-06. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import "RACSignal.h" /// The domain for errors originating in RACSignal operations. extern NSString * const RACSignalErrorDomain; /// The error code used with -timeout:. extern const NSInteger RACSignalErrorTimedOut; /// The error code used when a value passed into +switch:cases:default: does not /// match any of the cases, and no default was given. extern const NSInteger RACSignalErrorNoMatchingCase; @class RACCommand; @class RACDisposable; @class RACMulticastConnection; @class RACScheduler; @class RACSequence; @class RACSubject; @class RACTuple; @protocol RACSubscriber; @interface RACSignal (Operations) /// Do the given block on `next`. This should be used to inject side effects into /// the signal. - (RACSignal *)doNext:(void (^)(id x))block; /// Do the given block on `error`. This should be used to inject side effects /// into the signal. - (RACSignal *)doError:(void (^)(NSError *error))block; /// Do the given block on `completed`. This should be used to inject side effects /// into the signal. - (RACSignal *)doCompleted:(void (^)(void))block; /// Sends `next`s only if we don't receive another `next` in `interval` seconds. /// /// If a `next` is received, and then another `next` is received before /// `interval` seconds have passed, the first value is discarded. /// /// After `interval` seconds have passed since the most recent `next` was sent, /// the most recent `next` is forwarded on the scheduler that the value was /// originally received on. If +[RACScheduler currentScheduler] was nil at the /// time, a private background scheduler is used. /// /// Returns a signal which sends throttled and delayed `next` events. Completion /// and errors are always forwarded immediately. - (RACSignal *)throttle:(NSTimeInterval)interval; /// Throttles `next`s for which `predicate` returns YES. /// /// When `predicate` returns YES for a `next`: /// /// 1. If another `next` is received before `interval` seconds have passed, the /// prior value is discarded. This happens regardless of whether the new /// value will be throttled. /// 2. After `interval` seconds have passed since the value was originally /// received, it will be forwarded on the scheduler that it was received /// upon. If +[RACScheduler currentScheduler] was nil at the time, a private /// background scheduler is used. /// /// When `predicate` returns NO for a `next`, it is forwarded immediately, /// without any throttling. /// /// interval - The number of seconds for which to buffer the latest value that /// passes `predicate`. /// predicate - Passed each `next` from the receiver, this block returns /// whether the given value should be throttled. This argument must /// not be nil. /// /// Returns a signal which sends `next` events, throttled when `predicate` /// returns YES. Completion and errors are always forwarded immediately. - (RACSignal *)throttle:(NSTimeInterval)interval valuesPassingTest:(BOOL (^)(id next))predicate; /// Forwards `next` and `completed` events after delaying for `interval` seconds /// on the current scheduler (on which the events were delivered). /// /// If +[RACScheduler currentScheduler] is nil when `next` or `completed` is /// received, a private background scheduler is used. /// /// Returns a signal which sends delayed `next` and `completed` events. Errors /// are always forwarded immediately. - (RACSignal *)delay:(NSTimeInterval)interval; /// Resubscribes when the signal completes. - (RACSignal *)repeat; /// Executes the given block each time a subscription is created. /// /// block - A block which defines the subscription side effects. Cannot be `nil`. /// /// Example: /// /// // Write new file, with backup. /// [[[[fileManager /// rac_createFileAtPath:path contents:data] /// initially:^{ /// // 2. Second, backup current file /// [fileManager moveItemAtPath:path toPath:backupPath error:nil]; /// }] /// initially:^{ /// // 1. First, acquire write lock. /// [writeLock lock]; /// }] /// finally:^{ /// [writeLock unlock]; /// }]; /// /// Returns a signal that passes through all events of the receiver, plus /// introduces side effects which occur prior to any subscription side effects /// of the receiver. - (RACSignal *)initially:(void (^)(void))block; /// Executes the given block when the signal completes or errors. - (RACSignal *)finally:(void (^)(void))block; /// Divides the receiver's `next`s into buffers which deliver every `interval` /// seconds. /// /// interval - The interval in which values are grouped into one buffer. /// scheduler - The scheduler upon which the returned signal will deliver its /// values. This must not be nil or +[RACScheduler /// immediateScheduler]. /// /// Returns a signal which sends RACTuples of the buffered values at each /// interval on `scheduler`. When the receiver completes, any currently-buffered /// values will be sent immediately. - (RACSignal *)bufferWithTime:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler; /// Collects all receiver's `next`s into a NSArray. Nil values will be converted /// to NSNull. /// /// This corresponds to the `ToArray` method in Rx. /// /// Returns a signal which sends a single NSArray when the receiver completes /// successfully. - (RACSignal *)collect; /// Takes the last `count` `next`s after the receiving signal completes. - (RACSignal *)takeLast:(NSUInteger)count; /// Combines the latest values from the receiver and the given signal into /// RACTuples, once both have sent at least one `next`. /// /// Any additional `next`s will result in a new RACTuple with the latest values /// from both signals. /// /// signal - The signal to combine with. This argument must not be nil. /// /// Returns a signal which sends RACTuples of the combined values, forwards any /// `error` events, and completes when both input signals complete. - (RACSignal *)combineLatestWith:(RACSignal *)signal; /// Combines the latest values from the given signals into RACTuples, once all /// the signals have sent at least one `next`. /// /// Any additional `next`s will result in a new RACTuple with the latest values /// from all signals. /// /// signals - The signals to combine. If this collection is empty, the returned /// signal will immediately complete upon subscription. /// /// Returns a signal which sends RACTuples of the combined values, forwards any /// `error` events, and completes when all input signals complete. + (RACSignal *)combineLatest:(id)signals; /// Combines signals using +combineLatest:, then reduces the resulting tuples /// into a single value using -reduceEach:. /// /// signals - The signals to combine. If this collection is empty, the /// returned signal will immediately complete upon subscription. /// reduceBlock - The block which reduces the latest values from all the /// signals into one value. It must take as many arguments as the /// number of signals given. Each argument will be an object /// argument. The return value must be an object. This argument /// must not be nil. /// /// Example: /// /// [RACSignal combineLatest:@[ stringSignal, intSignal ] reduce:^(NSString *string, NSNumber *number) { /// return [NSString stringWithFormat:@"%@: %@", string, number]; /// }]; /// /// Returns a signal which sends the results from each invocation of /// `reduceBlock`. + (RACSignal *)combineLatest:(id)signals reduce:(id (^)())reduceBlock; /// Merges the receiver and the given signal with `+merge:` and returns the /// resulting signal. - (RACSignal *)merge:(RACSignal *)signal; /// Sends the latest `next` from any of the signals. /// /// Returns a signal that passes through values from each of the given signals, /// and sends `completed` when all of them complete. If any signal sends an error, /// the returned signal sends `error` immediately. + (RACSignal *)merge:(id)signals; /// Merges the signals sent by the receiver into a flattened signal, but only /// subscribes to `maxConcurrent` number of signals at a time. New signals are /// queued and subscribed to as other signals complete. /// /// If an error occurs on any of the signals, it is sent on the returned signal. /// It completes only after the receiver and all sent signals have completed. /// /// This corresponds to `Merge(IObservable>, Int32)` /// in Rx. /// /// maxConcurrent - the maximum number of signals to subscribe to at a /// time. If 0, it subscribes to an unlimited number of /// signals. - (RACSignal *)flatten:(NSUInteger)maxConcurrent; /// Ignores all `next`s from the receiver, waits for the receiver to complete, /// then subscribes to a new signal. /// /// block - A block which will create or obtain a new signal to subscribe to, /// executed only after the receiver completes. This block must not be /// nil, and it must not return a nil signal. /// /// Returns a signal which will pass through the events of the signal created in /// `block`. If the receiver errors out, the returned signal will error as well. - (RACSignal *)then:(RACSignal * (^)(void))block; /// Concats the inner signals of a signal of signals. - (RACSignal *)concat; /// Aggregates the `next` values of the receiver into a single combined value. /// /// The algorithm proceeds as follows: /// /// 1. `start` is passed into the block as the `running` value, and the first /// element of the receiver is passed into the block as the `next` value. /// 2. The result of the invocation (`running`) and the next element of the /// receiver (`next`) is passed into `reduceBlock`. /// 3. Steps 2 and 3 are repeated until all values have been processed. /// 4. The last result of `reduceBlock` is sent on the returned signal. /// /// This method is similar to -scanWithStart:reduce:, except that only the /// final result is sent on the returned signal. /// /// start - The value to be combined with the first element of the /// receiver. This value may be `nil`. /// reduceBlock - The block that describes how to combine values of the /// receiver. If the receiver is empty, this block will never be /// invoked. Cannot be nil. /// /// Returns a signal that will send the aggregated value when the receiver /// completes, then itself complete. If the receiver never sends any values, /// `start` will be sent instead. - (RACSignal *)aggregateWithStart:(id)start reduce:(id (^)(id running, id next))reduceBlock; /// Aggregates the `next` values of the receiver into a single combined value. /// This is indexed version of -aggregateWithStart:reduce:. /// /// start - The value to be combined with the first element of the /// receiver. This value may be `nil`. /// reduceBlock - The block that describes how to combine values of the /// receiver. This block takes zero-based index value as the last /// parameter. If the receiver is empty, this block will never be /// invoked. Cannot be nil. /// /// Returns a signal that will send the aggregated value when the receiver /// completes, then itself complete. If the receiver never sends any values, /// `start` will be sent instead. - (RACSignal *)aggregateWithStart:(id)start reduceWithIndex:(id (^)(id running, id next, NSUInteger index))reduceBlock; /// Aggregates the `next` values of the receiver into a single combined value. /// /// This invokes `startFactory` block on each subscription, then calls /// -aggregateWithStart:reduce: with the return value of the block as start value. /// /// startFactory - The block that returns start value which will be combined /// with the first element of the receiver. Cannot be nil. /// reduceBlock - The block that describes how to combine values of the /// receiver. If the receiver is empty, this block will never be /// invoked. Cannot be nil. /// /// Returns a signal that will send the aggregated value when the receiver /// completes, then itself complete. If the receiver never sends any values, /// the return value of `startFactory` will be sent instead. - (RACSignal *)aggregateWithStartFactory:(id (^)(void))startFactory reduce:(id (^)(id running, id next))reduceBlock; /// Invokes -setKeyPath:onObject:nilValue: with `nil` for the nil value. /// /// WARNING: Under certain conditions, this method is known to be thread-unsafe. /// See the description in -setKeyPath:onObject:nilValue:. - (RACDisposable *)setKeyPath:(NSString *)keyPath onObject:(NSObject *)object; /// Binds the receiver to an object, automatically setting the given key path on /// every `next`. When the signal completes, the binding is automatically /// disposed of. /// /// WARNING: Under certain conditions, this method is known to be thread-unsafe. /// A crash can result if `object` is deallocated concurrently on /// another thread within a window of time between a value being sent /// on this signal and immediately prior to the invocation of /// -setValue:forKeyPath:, which sets the property. To prevent this, /// ensure `object` is deallocated on the same thread the receiver /// sends on, or ensure that the returned disposable is disposed of /// before `object` deallocates. /// See https://github.com/ReactiveCocoa/ReactiveCocoa/pull/1184 /// /// Sending an error on the signal is considered undefined behavior, and will /// generate an assertion failure in Debug builds. /// /// A given key on an object should only have one active signal bound to it at any /// given time. Binding more than one signal to the same property is considered /// undefined behavior. /// /// keyPath - The key path to update with `next`s from the receiver. /// object - The object that `keyPath` is relative to. /// nilValue - The value to set at the key path whenever `nil` is sent by the /// receiver. This may be nil when binding to object properties, but /// an NSValue should be used for primitive properties, to avoid an /// exception if `nil` is sent (which might occur if an intermediate /// object is set to `nil`). /// /// Returns a disposable which can be used to terminate the binding. - (RACDisposable *)setKeyPath:(NSString *)keyPath onObject:(NSObject *)object nilValue:(id)nilValue; /// Sends NSDate.date every `interval` seconds. /// /// interval - The time interval in seconds at which the current time is sent. /// scheduler - The scheduler upon which the current NSDate should be sent. This /// must not be nil or +[RACScheduler immediateScheduler]. /// /// Returns a signal that sends the current date/time every `interval` on /// `scheduler`. + (RACSignal *)interval:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler; /// Sends NSDate.date at intervals of at least `interval` seconds, up to /// approximately `interval` + `leeway` seconds. /// /// The created signal will defer sending each `next` for at least `interval` /// seconds, and for an additional amount of time up to `leeway` seconds in the /// interest of performance or power consumption. Note that some additional /// latency is to be expected, even when specifying a `leeway` of 0. /// /// interval - The base interval between `next`s. /// scheduler - The scheduler upon which the current NSDate should be sent. This /// must not be nil or +[RACScheduler immediateScheduler]. /// leeway - The maximum amount of additional time the `next` can be deferred. /// /// Returns a signal that sends the current date/time at intervals of at least /// `interval seconds` up to approximately `interval` + `leeway` seconds on /// `scheduler`. + (RACSignal *)interval:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler withLeeway:(NSTimeInterval)leeway; /// Takes `next`s until the `signalTrigger` sends `next` or `completed`. /// /// Returns a signal which passes through all events from the receiver until /// `signalTrigger` sends `next` or `completed`, at which point the returned signal /// will send `completed`. - (RACSignal *)takeUntil:(RACSignal *)signalTrigger; /// Takes `next`s until the `replacement` sends an event. /// /// replacement - The signal which replaces the receiver as soon as it sends an /// event. /// /// Returns a signal which passes through `next`s and `error` from the receiver /// until `replacement` sends an event, at which point the returned signal will /// send that event and switch to passing through events from `replacement` /// instead, regardless of whether the receiver has sent events already. - (RACSignal *)takeUntilReplacement:(RACSignal *)replacement; /// Subscribes to the returned signal when an error occurs. - (RACSignal *)catch:(RACSignal * (^)(NSError *error))catchBlock; /// Subscribes to the given signal when an error occurs. - (RACSignal *)catchTo:(RACSignal *)signal; /// Returns a signal that will either immediately send the return value of /// `tryBlock` and complete, or error using the `NSError` passed out from the /// block. /// /// tryBlock - An action that performs some computation that could fail. If the /// block returns nil, the block must return an error via the /// `errorPtr` parameter. /// /// Example: /// /// [RACSignal try:^(NSError **error) { /// return [NSJSONSerialization JSONObjectWithData:someJSONData options:0 error:error]; /// }]; + (RACSignal *)try:(id (^)(NSError **errorPtr))tryBlock; /// Runs `tryBlock` against each of the receiver's values, passing values /// until `tryBlock` returns NO, or the receiver completes. /// /// tryBlock - An action to run against each of the receiver's values. /// The block should return YES to indicate that the action was /// successful. This block must not be nil. /// /// Example: /// /// // The returned signal will send an error if data values cannot be /// // written to `someFileURL`. /// [signal try:^(NSData *data, NSError **errorPtr) { /// return [data writeToURL:someFileURL options:NSDataWritingAtomic error:errorPtr]; /// }]; /// /// Returns a signal which passes through all the values of the receiver. If /// `tryBlock` fails for any value, the returned signal will error using the /// `NSError` passed out from the block. - (RACSignal *)try:(BOOL (^)(id value, NSError **errorPtr))tryBlock; /// Runs `mapBlock` against each of the receiver's values, mapping values until /// `mapBlock` returns nil, or the receiver completes. /// /// mapBlock - An action to map each of the receiver's values. The block should /// return a non-nil value to indicate that the action was successful. /// This block must not be nil. /// /// Example: /// /// // The returned signal will send an error if data cannot be read from /// // `fileURL`. /// [signal tryMap:^(NSURL *fileURL, NSError **errorPtr) { /// return [NSData dataWithContentsOfURL:fileURL options:0 error:errorPtr]; /// }]; /// /// Returns a signal which transforms all the values of the receiver. If /// `mapBlock` returns nil for any value, the returned signal will error using /// the `NSError` passed out from the block. - (RACSignal *)tryMap:(id (^)(id value, NSError **errorPtr))mapBlock; /// Returns the first `next`. Note that this is a blocking call. - (id)first; /// Returns the first `next` or `defaultValue` if the signal completes or errors /// without sending a `next`. Note that this is a blocking call. - (id)firstOrDefault:(id)defaultValue; /// Returns the first `next` or `defaultValue` if the signal completes or errors /// without sending a `next`. If an error occurs success will be NO and error /// will be populated. Note that this is a blocking call. /// /// Both success and error may be NULL. - (id)firstOrDefault:(id)defaultValue success:(BOOL *)success error:(NSError **)error; /// Blocks the caller and waits for the signal to complete. /// /// error - If not NULL, set to any error that occurs. /// /// Returns whether the signal completed successfully. If NO, `error` will be set /// to the error that occurred. - (BOOL)waitUntilCompleted:(NSError **)error; /// Defers creation of a signal until the signal's actually subscribed to. /// /// This can be used to effectively turn a hot signal into a cold signal. + (RACSignal *)defer:(RACSignal * (^)(void))block; /// Every time the receiver sends a new RACSignal, subscribes and sends `next`s and /// `error`s only for that signal. /// /// The receiver must be a signal of signals. /// /// Returns a signal which passes through `next`s and `error`s from the latest /// signal sent by the receiver, and sends `completed` when both the receiver and /// the last sent signal complete. - (RACSignal *)switchToLatest; /// Switches between the signals in `cases` as well as `defaultSignal` based on /// the latest value sent by `signal`. /// /// signal - A signal of objects used as keys in the `cases` dictionary. /// This argument must not be nil. /// cases - A dictionary that has signals as values. This argument must /// not be nil. A RACTupleNil key in this dictionary will match /// nil `next` events that are received on `signal`. /// defaultSignal - The signal to pass through after `signal` sends a value for /// which `cases` does not contain a signal. If nil, any /// unmatched values will result in /// a RACSignalErrorNoMatchingCase error. /// /// Returns a signal which passes through `next`s and `error`s from one of the /// the signals in `cases` or `defaultSignal`, and sends `completed` when both /// `signal` and the last used signal complete. If no `defaultSignal` is given, /// an unmatched `next` will result in an error on the returned signal. + (RACSignal *)switch:(RACSignal *)signal cases:(NSDictionary *)cases default:(RACSignal *)defaultSignal; /// Switches between `trueSignal` and `falseSignal` based on the latest value /// sent by `boolSignal`. /// /// boolSignal - A signal of BOOLs determining whether `trueSignal` or /// `falseSignal` should be active. This argument must not be nil. /// trueSignal - The signal to pass through after `boolSignal` has sent YES. /// This argument must not be nil. /// falseSignal - The signal to pass through after `boolSignal` has sent NO. This /// argument must not be nil. /// /// Returns a signal which passes through `next`s and `error`s from `trueSignal` /// and/or `falseSignal`, and sends `completed` when both `boolSignal` and the /// last switched signal complete. + (RACSignal *)if:(RACSignal *)boolSignal then:(RACSignal *)trueSignal else:(RACSignal *)falseSignal; /// Adds every `next` to an array. Nils are represented by NSNulls. Note that /// this is a blocking call. /// /// **This is not the same as the `ToArray` method in Rx.** See -collect for /// that behavior instead. /// /// Returns the array of `next` values, or nil if an error occurs. - (NSArray *)toArray; /// Adds every `next` to a sequence. Nils are represented by NSNulls. /// /// This corresponds to the `ToEnumerable` method in Rx. /// /// Returns a sequence which provides values from the signal as they're sent. /// Trying to retrieve a value from the sequence which has not yet been sent will /// block. @property (nonatomic, strong, readonly) RACSequence *sequence; /// Creates and returns a multicast connection. This allows you to share a single /// subscription to the underlying signal. - (RACMulticastConnection *)publish; /// Creates and returns a multicast connection that pushes values into the given /// subject. This allows you to share a single subscription to the underlying /// signal. - (RACMulticastConnection *)multicast:(RACSubject *)subject; /// Multicasts the signal to a RACReplaySubject of unlimited capacity, and /// immediately connects to the resulting RACMulticastConnection. /// /// Returns the connected, multicasted signal. - (RACSignal *)replay; /// Multicasts the signal to a RACReplaySubject of capacity 1, and immediately /// connects to the resulting RACMulticastConnection. /// /// Returns the connected, multicasted signal. - (RACSignal *)replayLast; /// Multicasts the signal to a RACReplaySubject of unlimited capacity, and /// lazily connects to the resulting RACMulticastConnection. /// /// This means the returned signal will subscribe to the multicasted signal only /// when the former receives its first subscription. /// /// Returns the lazily connected, multicasted signal. - (RACSignal *)replayLazily; /// Sends an error after `interval` seconds if the source doesn't complete /// before then. /// /// The error will be in the RACSignalErrorDomain and have a code of /// RACSignalErrorTimedOut. /// /// interval - The number of seconds after which the signal should error out. /// scheduler - The scheduler upon which any timeout error should be sent. This /// must not be nil or +[RACScheduler immediateScheduler]. /// /// Returns a signal that passes through the receiver's events, until the stream /// finishes or times out, at which point an error will be sent on `scheduler`. - (RACSignal *)timeout:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler; /// Creates and returns a signal that delivers its events on the given scheduler. /// Any side effects of the receiver will still be performed on the original /// thread. /// /// This is ideal when the signal already performs its work on the desired /// thread, but you want to handle its events elsewhere. /// /// This corresponds to the `ObserveOn` method in Rx. - (RACSignal *)deliverOn:(RACScheduler *)scheduler; /// Creates and returns a signal that executes its side effects and delivers its /// events on the given scheduler. /// /// Use of this operator should be avoided whenever possible, because the /// receiver's side effects may not be safe to run on another thread. If you just /// want to receive the signal's events on `scheduler`, use -deliverOn: instead. - (RACSignal *)subscribeOn:(RACScheduler *)scheduler; /// Creates and returns a signal that delivers its events on the main thread. /// If events are already being sent on the main thread, they may be passed on /// without delay. An event will instead be queued for later delivery on the main /// thread if sent on another thread, or if a previous event is already being /// processed, or has been queued. /// /// Any side effects of the receiver will still be performed on the original /// thread. /// /// This can be used when a signal will cause UI updates, to avoid potential /// flicker caused by delayed delivery of events, such as the first event from /// a RACObserve at view instantiation. - (RACSignal *)deliverOnMainThread; /// Groups each received object into a group, as determined by calling `keyBlock` /// with that object. The object sent is transformed by calling `transformBlock` /// with the object. If `transformBlock` is nil, it sends the original object. /// /// The returned signal is a signal of RACGroupedSignal. - (RACSignal *)groupBy:(id (^)(id object))keyBlock transform:(id (^)(id object))transformBlock; /// Calls -[RACSignal groupBy:keyBlock transform:nil]. - (RACSignal *)groupBy:(id (^)(id object))keyBlock; /// Sends an [NSNumber numberWithBool:YES] if the receiving signal sends any /// objects. - (RACSignal *)any; /// Sends an [NSNumber numberWithBool:YES] if the receiving signal sends any /// objects that pass `predicateBlock`. /// /// predicateBlock - cannot be nil. - (RACSignal *)any:(BOOL (^)(id object))predicateBlock; /// Sends an [NSNumber numberWithBool:YES] if all the objects the receiving /// signal sends pass `predicateBlock`. /// /// predicateBlock - cannot be nil. - (RACSignal *)all:(BOOL (^)(id object))predicateBlock; /// Resubscribes to the receiving signal if an error occurs, up until it has /// retried the given number of times. /// /// retryCount - if 0, it keeps retrying until it completes. - (RACSignal *)retry:(NSInteger)retryCount; /// Resubscribes to the receiving signal if an error occurs. - (RACSignal *)retry; /// Sends the latest value from the receiver only when `sampler` sends a value. /// The returned signal could repeat values if `sampler` fires more often than /// the receiver. Values from `sampler` are ignored before the receiver sends /// its first value. /// /// sampler - The signal that controls when the latest value from the receiver /// is sent. Cannot be nil. - (RACSignal *)sample:(RACSignal *)sampler; /// Ignores all `next`s from the receiver. /// /// Returns a signal which only passes through `error` or `completed` events from /// the receiver. - (RACSignal *)ignoreValues; /// Converts each of the receiver's events into a RACEvent object. /// /// Returns a signal which sends the receiver's events as RACEvents, and /// completes after the receiver sends `completed` or `error`. - (RACSignal *)materialize; /// Converts each RACEvent in the receiver back into "real" RACSignal events. /// /// Returns a signal which sends `next` for each value RACEvent, `error` for each /// error RACEvent, and `completed` for each completed RACEvent. - (RACSignal *)dematerialize; /// Inverts each NSNumber-wrapped BOOL sent by the receiver. It will assert if /// the receiver sends anything other than NSNumbers. /// /// Returns a signal of inverted NSNumber-wrapped BOOLs. - (RACSignal *)not; /// Performs a boolean AND on all of the RACTuple of NSNumbers in sent by the receiver. /// /// Asserts if the receiver sends anything other than a RACTuple of one or more NSNumbers. /// /// Returns a signal that applies AND to each NSNumber in the tuple. - (RACSignal *)and; /// Performs a boolean OR on all of the RACTuple of NSNumbers in sent by the receiver. /// /// Asserts if the receiver sends anything other than a RACTuple of one or more NSNumbers. /// /// Returns a signal that applies OR to each NSNumber in the tuple. - (RACSignal *)or; /// Sends the result of calling the block with arguments as packed in each RACTuple /// sent by the receiver. /// /// The receiver must send tuple values, where the first element of the tuple is /// a block, taking a number of parameters equal to the count of the remaining /// elements of the tuple, and returning an object. Each block must take at least /// one argument, so each tuple must contain at least 2 elements. /// /// Example: /// /// RACSignal *adder = [RACSignal return:^(NSNumber *a, NSNumber *b) { /// return @(a.intValue + b.intValue); /// }]; /// RACSignal *sums = [[RACSignal /// combineLatest:@[ adder, as, bs ]] /// reduceApply]; /// /// Returns a signal of the result of applying the first element of each tuple /// to the remaining elements. - (RACSignal *)reduceApply; @end @interface RACSignal (UnavailableOperations) - (RACSignal *)windowWithStart:(RACSignal *)openSignal close:(RACSignal * (^)(RACSignal *start))closeBlock __attribute__((unavailable("See https://github.com/ReactiveCocoa/ReactiveCocoa/issues/587"))); - (RACSignal *)buffer:(NSUInteger)bufferCount __attribute__((unavailable("See https://github.com/ReactiveCocoa/ReactiveCocoa/issues/587"))); - (RACSignal *)let:(RACSignal * (^)(RACSignal *sharedSignal))letBlock __attribute__((unavailable("Use -publish instead"))); + (RACSignal *)interval:(NSTimeInterval)interval __attribute__((unavailable("Use +interval:onScheduler: instead"))); + (RACSignal *)interval:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway __attribute__((unavailable("Use +interval:onScheduler:withLeeway: instead"))); - (RACSignal *)bufferWithTime:(NSTimeInterval)interval __attribute__((unavailable("Use -bufferWithTime:onScheduler: instead"))); - (RACSignal *)timeout:(NSTimeInterval)interval __attribute__((unavailable("Use -timeout:onScheduler: instead"))); - (RACDisposable *)toProperty:(NSString *)keyPath onObject:(NSObject *)object __attribute__((unavailable("Renamed to -setKeyPath:onObject:"))); - (RACSignal *)ignoreElements __attribute__((unavailable("Renamed to -ignoreValues"))); - (RACSignal *)sequenceNext:(RACSignal * (^)(void))block __attribute__((unavailable("Renamed to -then:"))); - (RACSignal *)aggregateWithStart:(id)start combine:(id (^)(id running, id next))combineBlock __attribute__((unavailable("Renamed to -aggregateWithStart:reduce:"))); - (RACSignal *)aggregateWithStartFactory:(id (^)(void))startFactory combine:(id (^)(id running, id next))combineBlock __attribute__((unavailable("Renamed to -aggregateWithStartFactory:reduce:"))); - (RACDisposable *)executeCommand:(RACCommand *)command __attribute__((unavailable("Use -flattenMap: or -subscribeNext: instead"))); @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSignal+Operations.m ================================================ // // RACSignal+Operations.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-09-06. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACSignal+Operations.h" #import "NSObject+RACDeallocating.h" #import "NSObject+RACDescription.h" #import "RACBlockTrampoline.h" #import "RACCommand.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACEvent.h" #import "RACGroupedSignal.h" #import "RACMulticastConnection+Private.h" #import "RACReplaySubject.h" #import "RACScheduler.h" #import "RACSerialDisposable.h" #import "RACSignalSequence.h" #import "RACStream+Private.h" #import "RACSubject.h" #import "RACSubscriber+Private.h" #import "RACSubscriber.h" #import "RACTuple.h" #import "RACUnit.h" #import #import NSString * const RACSignalErrorDomain = @"RACSignalErrorDomain"; const NSInteger RACSignalErrorTimedOut = 1; const NSInteger RACSignalErrorNoMatchingCase = 2; // Subscribes to the given signal with the given blocks. // // If the signal errors or completes, the corresponding block is invoked. If the // disposable passed to the block is _not_ disposed, then the signal is // subscribed to again. static RACDisposable *subscribeForever (RACSignal *signal, void (^next)(id), void (^error)(NSError *, RACDisposable *), void (^completed)(RACDisposable *)) { next = [next copy]; error = [error copy]; completed = [completed copy]; RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable]; RACSchedulerRecursiveBlock recursiveBlock = ^(void (^recurse)(void)) { RACCompoundDisposable *selfDisposable = [RACCompoundDisposable compoundDisposable]; [compoundDisposable addDisposable:selfDisposable]; __weak RACDisposable *weakSelfDisposable = selfDisposable; RACDisposable *subscriptionDisposable = [signal subscribeNext:next error:^(NSError *e) { @autoreleasepool { error(e, compoundDisposable); [compoundDisposable removeDisposable:weakSelfDisposable]; } recurse(); } completed:^{ @autoreleasepool { completed(compoundDisposable); [compoundDisposable removeDisposable:weakSelfDisposable]; } recurse(); }]; [selfDisposable addDisposable:subscriptionDisposable]; }; // Subscribe once immediately, and then use recursive scheduling for any // further resubscriptions. recursiveBlock(^{ RACScheduler *recursiveScheduler = RACScheduler.currentScheduler ?: [RACScheduler scheduler]; RACDisposable *schedulingDisposable = [recursiveScheduler scheduleRecursiveBlock:recursiveBlock]; [compoundDisposable addDisposable:schedulingDisposable]; }); return compoundDisposable; } @implementation RACSignal (Operations) - (RACSignal *)doNext:(void (^)(id x))block { NSCParameterAssert(block != NULL); return [[RACSignal createSignal:^(id subscriber) { return [self subscribeNext:^(id x) { block(x); [subscriber sendNext:x]; } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ [subscriber sendCompleted]; }]; }] setNameWithFormat:@"[%@] -doNext:", self.name]; } - (RACSignal *)doError:(void (^)(NSError *error))block { NSCParameterAssert(block != NULL); return [[RACSignal createSignal:^(id subscriber) { return [self subscribeNext:^(id x) { [subscriber sendNext:x]; } error:^(NSError *error) { block(error); [subscriber sendError:error]; } completed:^{ [subscriber sendCompleted]; }]; }] setNameWithFormat:@"[%@] -doError:", self.name]; } - (RACSignal *)doCompleted:(void (^)(void))block { NSCParameterAssert(block != NULL); return [[RACSignal createSignal:^(id subscriber) { return [self subscribeNext:^(id x) { [subscriber sendNext:x]; } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ block(); [subscriber sendCompleted]; }]; }] setNameWithFormat:@"[%@] -doCompleted:", self.name]; } - (RACSignal *)throttle:(NSTimeInterval)interval { return [[self throttle:interval valuesPassingTest:^(id _) { return YES; }] setNameWithFormat:@"[%@] -throttle: %f", self.name, (double)interval]; } - (RACSignal *)throttle:(NSTimeInterval)interval valuesPassingTest:(BOOL (^)(id next))predicate { NSCParameterAssert(interval >= 0); NSCParameterAssert(predicate != nil); return [[RACSignal createSignal:^(id subscriber) { RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable]; // We may never use this scheduler, but we need to set it up ahead of // time so that our scheduled blocks are run serially if we do. RACScheduler *scheduler = [RACScheduler scheduler]; // Information about any currently-buffered `next` event. __block id nextValue = nil; __block BOOL hasNextValue = NO; RACSerialDisposable *nextDisposable = [[RACSerialDisposable alloc] init]; void (^flushNext)(BOOL send) = ^(BOOL send) { @synchronized (compoundDisposable) { [nextDisposable.disposable dispose]; if (!hasNextValue) return; if (send) [subscriber sendNext:nextValue]; nextValue = nil; hasNextValue = NO; } }; RACDisposable *subscriptionDisposable = [self subscribeNext:^(id x) { RACScheduler *delayScheduler = RACScheduler.currentScheduler ?: scheduler; BOOL shouldThrottle = predicate(x); @synchronized (compoundDisposable) { flushNext(NO); if (!shouldThrottle) { [subscriber sendNext:x]; return; } nextValue = x; hasNextValue = YES; nextDisposable.disposable = [delayScheduler afterDelay:interval schedule:^{ flushNext(YES); }]; } } error:^(NSError *error) { [compoundDisposable dispose]; [subscriber sendError:error]; } completed:^{ flushNext(YES); [subscriber sendCompleted]; }]; [compoundDisposable addDisposable:subscriptionDisposable]; return compoundDisposable; }] setNameWithFormat:@"[%@] -throttle: %f valuesPassingTest:", self.name, (double)interval]; } - (RACSignal *)delay:(NSTimeInterval)interval { return [[RACSignal createSignal:^(id subscriber) { RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable]; // We may never use this scheduler, but we need to set it up ahead of // time so that our scheduled blocks are run serially if we do. RACScheduler *scheduler = [RACScheduler scheduler]; void (^schedule)(dispatch_block_t) = ^(dispatch_block_t block) { RACScheduler *delayScheduler = RACScheduler.currentScheduler ?: scheduler; RACDisposable *schedulerDisposable = [delayScheduler afterDelay:interval schedule:block]; [disposable addDisposable:schedulerDisposable]; }; RACDisposable *subscriptionDisposable = [self subscribeNext:^(id x) { schedule(^{ [subscriber sendNext:x]; }); } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ schedule(^{ [subscriber sendCompleted]; }); }]; [disposable addDisposable:subscriptionDisposable]; return disposable; }] setNameWithFormat:@"[%@] -delay: %f", self.name, (double)interval]; } - (RACSignal *)repeat { return [[RACSignal createSignal:^(id subscriber) { return subscribeForever(self, ^(id x) { [subscriber sendNext:x]; }, ^(NSError *error, RACDisposable *disposable) { [disposable dispose]; [subscriber sendError:error]; }, ^(RACDisposable *disposable) { // Resubscribe. }); }] setNameWithFormat:@"[%@] -repeat", self.name]; } - (RACSignal *)catch:(RACSignal * (^)(NSError *error))catchBlock { NSCParameterAssert(catchBlock != NULL); return [[RACSignal createSignal:^(id subscriber) { RACSerialDisposable *catchDisposable = [[RACSerialDisposable alloc] init]; RACDisposable *subscriptionDisposable = [self subscribeNext:^(id x) { [subscriber sendNext:x]; } error:^(NSError *error) { RACSignal *signal = catchBlock(error); NSCAssert(signal != nil, @"Expected non-nil signal from catch block on %@", self); catchDisposable.disposable = [signal subscribe:subscriber]; } completed:^{ [subscriber sendCompleted]; }]; return [RACDisposable disposableWithBlock:^{ [catchDisposable dispose]; [subscriptionDisposable dispose]; }]; }] setNameWithFormat:@"[%@] -catch:", self.name]; } - (RACSignal *)catchTo:(RACSignal *)signal { return [[self catch:^(NSError *error) { return signal; }] setNameWithFormat:@"[%@] -catchTo: %@", self.name, signal]; } + (RACSignal *)try:(id (^)(NSError **errorPtr))tryBlock { NSCParameterAssert(tryBlock != NULL); return [[RACSignal createSignal:^(id subscriber) { NSError *error; id value = tryBlock(&error); RACSignal *signal = (value == nil ? [RACSignal error:error] : [RACSignal return:value]); return [signal subscribe:subscriber]; }] setNameWithFormat:@"+try:"]; } - (RACSignal *)try:(BOOL (^)(id value, NSError **errorPtr))tryBlock { NSCParameterAssert(tryBlock != NULL); return [[self flattenMap:^(id value) { NSError *error = nil; BOOL passed = tryBlock(value, &error); return (passed ? [RACSignal return:value] : [RACSignal error:error]); }] setNameWithFormat:@"[%@] -try:", self.name]; } - (RACSignal *)tryMap:(id (^)(id value, NSError **errorPtr))mapBlock { NSCParameterAssert(mapBlock != NULL); return [[self flattenMap:^(id value) { NSError *error = nil; id mappedValue = mapBlock(value, &error); return (mappedValue == nil ? [RACSignal error:error] : [RACSignal return:mappedValue]); }] setNameWithFormat:@"[%@] -tryMap:", self.name]; } - (RACSignal *)initially:(void (^)(void))block { NSCParameterAssert(block != NULL); return [[RACSignal defer:^{ block(); return self; }] setNameWithFormat:@"[%@] -initially:", self.name]; } - (RACSignal *)finally:(void (^)(void))block { NSCParameterAssert(block != NULL); return [[[self doError:^(NSError *error) { block(); }] doCompleted:^{ block(); }] setNameWithFormat:@"[%@] -finally:", self.name]; } - (RACSignal *)bufferWithTime:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler { NSCParameterAssert(scheduler != nil); NSCParameterAssert(scheduler != RACScheduler.immediateScheduler); return [[RACSignal createSignal:^(id subscriber) { RACSerialDisposable *timerDisposable = [[RACSerialDisposable alloc] init]; NSMutableArray *values = [NSMutableArray array]; void (^flushValues)() = ^{ @synchronized (values) { [timerDisposable.disposable dispose]; if (values.count == 0) return; RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:values]; [values removeAllObjects]; [subscriber sendNext:tuple]; } }; RACDisposable *selfDisposable = [self subscribeNext:^(id x) { @synchronized (values) { if (values.count == 0) { timerDisposable.disposable = [scheduler afterDelay:interval schedule:flushValues]; } [values addObject:x ?: RACTupleNil.tupleNil]; } } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ flushValues(); [subscriber sendCompleted]; }]; return [RACDisposable disposableWithBlock:^{ [selfDisposable dispose]; [timerDisposable dispose]; }]; }] setNameWithFormat:@"[%@] -bufferWithTime: %f onScheduler: %@", self.name, (double)interval, scheduler]; } - (RACSignal *)collect { return [[self aggregateWithStartFactory:^{ return [[NSMutableArray alloc] init]; } reduce:^(NSMutableArray *collectedValues, id x) { [collectedValues addObject:(x ?: NSNull.null)]; return collectedValues; }] setNameWithFormat:@"[%@] -collect", self.name]; } - (RACSignal *)takeLast:(NSUInteger)count { return [[RACSignal createSignal:^(id subscriber) { NSMutableArray *valuesTaken = [NSMutableArray arrayWithCapacity:count]; return [self subscribeNext:^(id x) { [valuesTaken addObject:x ? : RACTupleNil.tupleNil]; while (valuesTaken.count > count) { [valuesTaken removeObjectAtIndex:0]; } } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ for (id value in valuesTaken) { [subscriber sendNext:value == RACTupleNil.tupleNil ? nil : value]; } [subscriber sendCompleted]; }]; }] setNameWithFormat:@"[%@] -takeLast: %lu", self.name, (unsigned long)count]; } - (RACSignal *)combineLatestWith:(RACSignal *)signal { NSCParameterAssert(signal != nil); return [[RACSignal createSignal:^(id subscriber) { RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable]; __block id lastSelfValue = nil; __block BOOL selfCompleted = NO; __block id lastOtherValue = nil; __block BOOL otherCompleted = NO; void (^sendNext)(void) = ^{ @synchronized (disposable) { if (lastSelfValue == nil || lastOtherValue == nil) return; [subscriber sendNext:RACTuplePack(lastSelfValue, lastOtherValue)]; } }; RACDisposable *selfDisposable = [self subscribeNext:^(id x) { @synchronized (disposable) { lastSelfValue = x ?: RACTupleNil.tupleNil; sendNext(); } } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ @synchronized (disposable) { selfCompleted = YES; if (otherCompleted) [subscriber sendCompleted]; } }]; [disposable addDisposable:selfDisposable]; RACDisposable *otherDisposable = [signal subscribeNext:^(id x) { @synchronized (disposable) { lastOtherValue = x ?: RACTupleNil.tupleNil; sendNext(); } } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ @synchronized (disposable) { otherCompleted = YES; if (selfCompleted) [subscriber sendCompleted]; } }]; [disposable addDisposable:otherDisposable]; return disposable; }] setNameWithFormat:@"[%@] -combineLatestWith: %@", self.name, signal]; } + (RACSignal *)combineLatest:(id)signals { return [[self join:signals block:^(RACSignal *left, RACSignal *right) { return [left combineLatestWith:right]; }] setNameWithFormat:@"+combineLatest: %@", signals]; } + (RACSignal *)combineLatest:(id)signals reduce:(id (^)())reduceBlock { NSCParameterAssert(reduceBlock != nil); RACSignal *result = [self combineLatest:signals]; // Although we assert this condition above, older versions of this method // supported this argument being nil. Avoid crashing Release builds of // apps that depended on that. if (reduceBlock != nil) result = [result reduceEach:reduceBlock]; return [result setNameWithFormat:@"+combineLatest: %@ reduce:", signals]; } - (RACSignal *)merge:(RACSignal *)signal { return [[RACSignal merge:@[ self, signal ]] setNameWithFormat:@"[%@] -merge: %@", self.name, signal]; } + (RACSignal *)merge:(id)signals { NSMutableArray *copiedSignals = [[NSMutableArray alloc] init]; for (RACSignal *signal in signals) { [copiedSignals addObject:signal]; } return [[[RACSignal createSignal:^ RACDisposable * (id subscriber) { for (RACSignal *signal in copiedSignals) { [subscriber sendNext:signal]; } [subscriber sendCompleted]; return nil; }] flatten] setNameWithFormat:@"+merge: %@", copiedSignals]; } - (RACSignal *)flatten:(NSUInteger)maxConcurrent { return [[RACSignal createSignal:^(id subscriber) { RACCompoundDisposable *compoundDisposable = [[RACCompoundDisposable alloc] init]; // Contains disposables for the currently active subscriptions. // // This should only be used while synchronized on `subscriber`. NSMutableArray *activeDisposables = [[NSMutableArray alloc] initWithCapacity:maxConcurrent]; // Whether the signal-of-signals has completed yet. // // This should only be used while synchronized on `subscriber`. __block BOOL selfCompleted = NO; // Subscribes to the given signal. __block void (^subscribeToSignal)(RACSignal *); // Weak reference to the above, to avoid a leak. __weak __block void (^recur)(RACSignal *); // Sends completed to the subscriber if all signals are finished. // // This should only be used while synchronized on `subscriber`. void (^completeIfAllowed)(void) = ^{ if (selfCompleted && activeDisposables.count == 0) { [subscriber sendCompleted]; } }; // The signals waiting to be started. // // This array should only be used while synchronized on `subscriber`. NSMutableArray *queuedSignals = [NSMutableArray array]; recur = subscribeToSignal = ^(RACSignal *signal) { RACSerialDisposable *serialDisposable = [[RACSerialDisposable alloc] init]; @synchronized (subscriber) { [compoundDisposable addDisposable:serialDisposable]; [activeDisposables addObject:serialDisposable]; } serialDisposable.disposable = [signal subscribeNext:^(id x) { [subscriber sendNext:x]; } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ __strong void (^subscribeToSignal)(RACSignal *) = recur; RACSignal *nextSignal; @synchronized (subscriber) { [compoundDisposable removeDisposable:serialDisposable]; [activeDisposables removeObjectIdenticalTo:serialDisposable]; if (queuedSignals.count == 0) { completeIfAllowed(); return; } nextSignal = queuedSignals[0]; [queuedSignals removeObjectAtIndex:0]; } subscribeToSignal(nextSignal); }]; }; [compoundDisposable addDisposable:[self subscribeNext:^(RACSignal *signal) { if (signal == nil) return; NSCAssert([signal isKindOfClass:RACSignal.class], @"Expected a RACSignal, got %@", signal); @synchronized (subscriber) { if (maxConcurrent > 0 && activeDisposables.count >= maxConcurrent) { [queuedSignals addObject:signal]; // If we need to wait, skip subscribing to this // signal. return; } } subscribeToSignal(signal); } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ @synchronized (subscriber) { selfCompleted = YES; completeIfAllowed(); } }]]; [compoundDisposable addDisposable:[RACDisposable disposableWithBlock:^{ // A strong reference is held to `subscribeToSignal` until we're // done, preventing it from deallocating early. subscribeToSignal = nil; }]]; return compoundDisposable; }] setNameWithFormat:@"[%@] -flatten: %lu", self.name, (unsigned long)maxConcurrent]; } - (RACSignal *)then:(RACSignal * (^)(void))block { NSCParameterAssert(block != nil); return [[[self ignoreValues] concat:[RACSignal defer:block]] setNameWithFormat:@"[%@] -then:", self.name]; } - (RACSignal *)concat { return [[self flatten:1] setNameWithFormat:@"[%@] -concat", self.name]; } - (RACSignal *)aggregateWithStartFactory:(id (^)(void))startFactory reduce:(id (^)(id running, id next))reduceBlock { NSCParameterAssert(startFactory != NULL); NSCParameterAssert(reduceBlock != NULL); return [[RACSignal defer:^{ return [self aggregateWithStart:startFactory() reduce:reduceBlock]; }] setNameWithFormat:@"[%@] -aggregateWithStartFactory:reduce:", self.name]; } - (RACSignal *)aggregateWithStart:(id)start reduce:(id (^)(id running, id next))reduceBlock { return [[self aggregateWithStart:start reduceWithIndex:^(id running, id next, NSUInteger index) { return reduceBlock(running, next); }] setNameWithFormat:@"[%@] -aggregateWithStart: %@ reduce:", self.name, RACDescription(start)]; } - (RACSignal *)aggregateWithStart:(id)start reduceWithIndex:(id (^)(id, id, NSUInteger))reduceBlock { return [[[[self scanWithStart:start reduceWithIndex:reduceBlock] startWith:start] takeLast:1] setNameWithFormat:@"[%@] -aggregateWithStart: %@ reduceWithIndex:", self.name, RACDescription(start)]; } - (RACDisposable *)setKeyPath:(NSString *)keyPath onObject:(NSObject *)object { return [self setKeyPath:keyPath onObject:object nilValue:nil]; } - (RACDisposable *)setKeyPath:(NSString *)keyPath onObject:(NSObject *)object nilValue:(id)nilValue { NSCParameterAssert(keyPath != nil); NSCParameterAssert(object != nil); keyPath = [keyPath copy]; RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable]; // Purposely not retaining 'object', since we want to tear down the binding // when it deallocates normally. __block void * volatile objectPtr = (__bridge void *)object; RACDisposable *subscriptionDisposable = [self subscribeNext:^(id x) { // Possibly spec, possibly compiler bug, but this __bridge cast does not // result in a retain here, effectively an invisible __unsafe_unretained // qualifier. Using objc_precise_lifetime gives the __strong reference // desired. The explicit use of __strong is strictly defensive. __strong NSObject *object __attribute__((objc_precise_lifetime)) = (__bridge __strong id)objectPtr; [object setValue:x ?: nilValue forKeyPath:keyPath]; } error:^(NSError *error) { __strong NSObject *object __attribute__((objc_precise_lifetime)) = (__bridge __strong id)objectPtr; NSCAssert(NO, @"Received error from %@ in binding for key path \"%@\" on %@: %@", self, keyPath, object, error); // Log the error if we're running with assertions disabled. NSLog(@"Received error from %@ in binding for key path \"%@\" on %@: %@", self, keyPath, object, error); [disposable dispose]; } completed:^{ [disposable dispose]; }]; [disposable addDisposable:subscriptionDisposable]; #if DEBUG static void *bindingsKey = &bindingsKey; NSMutableDictionary *bindings; @synchronized (object) { bindings = objc_getAssociatedObject(object, bindingsKey); if (bindings == nil) { bindings = [NSMutableDictionary dictionary]; objc_setAssociatedObject(object, bindingsKey, bindings, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } } @synchronized (bindings) { NSCAssert(bindings[keyPath] == nil, @"Signal %@ is already bound to key path \"%@\" on object %@, adding signal %@ is undefined behavior", [bindings[keyPath] nonretainedObjectValue], keyPath, object, self); bindings[keyPath] = [NSValue valueWithNonretainedObject:self]; } #endif RACDisposable *clearPointerDisposable = [RACDisposable disposableWithBlock:^{ #if DEBUG @synchronized (bindings) { [bindings removeObjectForKey:keyPath]; } #endif while (YES) { void *ptr = objectPtr; if (OSAtomicCompareAndSwapPtrBarrier(ptr, NULL, &objectPtr)) { break; } } }]; [disposable addDisposable:clearPointerDisposable]; [object.rac_deallocDisposable addDisposable:disposable]; RACCompoundDisposable *objectDisposable = object.rac_deallocDisposable; return [RACDisposable disposableWithBlock:^{ [objectDisposable removeDisposable:disposable]; [disposable dispose]; }]; } + (RACSignal *)interval:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler { return [[RACSignal interval:interval onScheduler:scheduler withLeeway:0.0] setNameWithFormat:@"+interval: %f onScheduler: %@", (double)interval, scheduler]; } + (RACSignal *)interval:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler withLeeway:(NSTimeInterval)leeway { NSCParameterAssert(scheduler != nil); NSCParameterAssert(scheduler != RACScheduler.immediateScheduler); return [[RACSignal createSignal:^(id subscriber) { return [scheduler after:[NSDate dateWithTimeIntervalSinceNow:interval] repeatingEvery:interval withLeeway:leeway schedule:^{ [subscriber sendNext:[NSDate date]]; }]; }] setNameWithFormat:@"+interval: %f onScheduler: %@ withLeeway: %f", (double)interval, scheduler, (double)leeway]; } - (RACSignal *)takeUntil:(RACSignal *)signalTrigger { return [[RACSignal createSignal:^(id subscriber) { RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable]; void (^triggerCompletion)(void) = ^{ [disposable dispose]; [subscriber sendCompleted]; }; RACDisposable *triggerDisposable = [signalTrigger subscribeNext:^(id _) { triggerCompletion(); } completed:^{ triggerCompletion(); }]; [disposable addDisposable:triggerDisposable]; if (!disposable.disposed) { RACDisposable *selfDisposable = [self subscribeNext:^(id x) { [subscriber sendNext:x]; } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ [disposable dispose]; [subscriber sendCompleted]; }]; [disposable addDisposable:selfDisposable]; } return disposable; }] setNameWithFormat:@"[%@] -takeUntil: %@", self.name, signalTrigger]; } - (RACSignal *)takeUntilReplacement:(RACSignal *)replacement { return [RACSignal createSignal:^(id subscriber) { RACSerialDisposable *selfDisposable = [[RACSerialDisposable alloc] init]; RACDisposable *replacementDisposable = [replacement subscribeNext:^(id x) { [selfDisposable dispose]; [subscriber sendNext:x]; } error:^(NSError *error) { [selfDisposable dispose]; [subscriber sendError:error]; } completed:^{ [selfDisposable dispose]; [subscriber sendCompleted]; }]; if (!selfDisposable.disposed) { selfDisposable.disposable = [[self concat:[RACSignal never]] subscribe:subscriber]; } return [RACDisposable disposableWithBlock:^{ [selfDisposable dispose]; [replacementDisposable dispose]; }]; }]; } - (RACSignal *)switchToLatest { return [[RACSignal createSignal:^(id subscriber) { RACMulticastConnection *connection = [self publish]; RACDisposable *subscriptionDisposable = [[connection.signal flattenMap:^(RACSignal *x) { NSCAssert(x == nil || [x isKindOfClass:RACSignal.class], @"-switchToLatest requires that the source signal (%@) send signals. Instead we got: %@", self, x); // -concat:[RACSignal never] prevents completion of the receiver from // prematurely terminating the inner signal. return [x takeUntil:[connection.signal concat:[RACSignal never]]]; }] subscribe:subscriber]; RACDisposable *connectionDisposable = [connection connect]; return [RACDisposable disposableWithBlock:^{ [subscriptionDisposable dispose]; [connectionDisposable dispose]; }]; }] setNameWithFormat:@"[%@] -switchToLatest", self.name]; } + (RACSignal *)switch:(RACSignal *)signal cases:(NSDictionary *)cases default:(RACSignal *)defaultSignal { NSCParameterAssert(signal != nil); NSCParameterAssert(cases != nil); for (id key in cases) { id value __attribute__((unused)) = cases[key]; NSCAssert([value isKindOfClass:RACSignal.class], @"Expected all cases to be RACSignals, %@ isn't", value); } NSDictionary *copy = [cases copy]; return [[[signal map:^(id key) { if (key == nil) key = RACTupleNil.tupleNil; RACSignal *signal = copy[key] ?: defaultSignal; if (signal == nil) { NSString *description = [NSString stringWithFormat:NSLocalizedString(@"No matching signal found for value %@", @""), key]; return [RACSignal error:[NSError errorWithDomain:RACSignalErrorDomain code:RACSignalErrorNoMatchingCase userInfo:@{ NSLocalizedDescriptionKey: description }]]; } return signal; }] switchToLatest] setNameWithFormat:@"+switch: %@ cases: %@ default: %@", signal, cases, defaultSignal]; } + (RACSignal *)if:(RACSignal *)boolSignal then:(RACSignal *)trueSignal else:(RACSignal *)falseSignal { NSCParameterAssert(boolSignal != nil); NSCParameterAssert(trueSignal != nil); NSCParameterAssert(falseSignal != nil); return [[[boolSignal map:^(NSNumber *value) { NSCAssert([value isKindOfClass:NSNumber.class], @"Expected %@ to send BOOLs, not %@", boolSignal, value); return (value.boolValue ? trueSignal : falseSignal); }] switchToLatest] setNameWithFormat:@"+if: %@ then: %@ else: %@", boolSignal, trueSignal, falseSignal]; } - (id)first { return [self firstOrDefault:nil]; } - (id)firstOrDefault:(id)defaultValue { return [self firstOrDefault:defaultValue success:NULL error:NULL]; } - (id)firstOrDefault:(id)defaultValue success:(BOOL *)success error:(NSError **)error { NSCondition *condition = [[NSCondition alloc] init]; condition.name = [NSString stringWithFormat:@"[%@] -firstOrDefault: %@ success:error:", self.name, defaultValue]; __block id value = defaultValue; __block BOOL done = NO; // Ensures that we don't pass values across thread boundaries by reference. __block NSError *localError; __block BOOL localSuccess; [[self take:1] subscribeNext:^(id x) { [condition lock]; value = x; localSuccess = YES; done = YES; [condition broadcast]; [condition unlock]; } error:^(NSError *e) { [condition lock]; if (!done) { localSuccess = NO; localError = e; done = YES; [condition broadcast]; } [condition unlock]; } completed:^{ [condition lock]; localSuccess = YES; done = YES; [condition broadcast]; [condition unlock]; }]; [condition lock]; while (!done) { [condition wait]; } if (success != NULL) *success = localSuccess; if (error != NULL) *error = localError; [condition unlock]; return value; } - (BOOL)waitUntilCompleted:(NSError **)error { BOOL success = NO; [[[self ignoreValues] setNameWithFormat:@"[%@] -waitUntilCompleted:", self.name] firstOrDefault:nil success:&success error:error]; return success; } + (RACSignal *)defer:(RACSignal * (^)(void))block { NSCParameterAssert(block != NULL); return [[RACSignal createSignal:^(id subscriber) { return [block() subscribe:subscriber]; }] setNameWithFormat:@"+defer:"]; } - (NSArray *)toArray { return [[[self collect] first] copy]; } - (RACSequence *)sequence { return [[RACSignalSequence sequenceWithSignal:self] setNameWithFormat:@"[%@] -sequence", self.name]; } - (RACMulticastConnection *)publish { RACSubject *subject = [[RACSubject subject] setNameWithFormat:@"[%@] -publish", self.name]; RACMulticastConnection *connection = [self multicast:subject]; return connection; } - (RACMulticastConnection *)multicast:(RACSubject *)subject { [subject setNameWithFormat:@"[%@] -multicast: %@", self.name, subject.name]; RACMulticastConnection *connection = [[RACMulticastConnection alloc] initWithSourceSignal:self subject:subject]; return connection; } - (RACSignal *)replay { RACReplaySubject *subject = [[RACReplaySubject subject] setNameWithFormat:@"[%@] -replay", self.name]; RACMulticastConnection *connection = [self multicast:subject]; [connection connect]; return connection.signal; } - (RACSignal *)replayLast { RACReplaySubject *subject = [[RACReplaySubject replaySubjectWithCapacity:1] setNameWithFormat:@"[%@] -replayLast", self.name]; RACMulticastConnection *connection = [self multicast:subject]; [connection connect]; return connection.signal; } - (RACSignal *)replayLazily { RACMulticastConnection *connection = [self multicast:[RACReplaySubject subject]]; return [[RACSignal defer:^{ [connection connect]; return connection.signal; }] setNameWithFormat:@"[%@] -replayLazily", self.name]; } - (RACSignal *)timeout:(NSTimeInterval)interval onScheduler:(RACScheduler *)scheduler { NSCParameterAssert(scheduler != nil); NSCParameterAssert(scheduler != RACScheduler.immediateScheduler); return [[RACSignal createSignal:^(id subscriber) { RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable]; RACDisposable *timeoutDisposable = [scheduler afterDelay:interval schedule:^{ [disposable dispose]; [subscriber sendError:[NSError errorWithDomain:RACSignalErrorDomain code:RACSignalErrorTimedOut userInfo:nil]]; }]; [disposable addDisposable:timeoutDisposable]; RACDisposable *subscriptionDisposable = [self subscribeNext:^(id x) { [subscriber sendNext:x]; } error:^(NSError *error) { [disposable dispose]; [subscriber sendError:error]; } completed:^{ [disposable dispose]; [subscriber sendCompleted]; }]; [disposable addDisposable:subscriptionDisposable]; return disposable; }] setNameWithFormat:@"[%@] -timeout: %f onScheduler: %@", self.name, (double)interval, scheduler]; } - (RACSignal *)deliverOn:(RACScheduler *)scheduler { return [[RACSignal createSignal:^(id subscriber) { return [self subscribeNext:^(id x) { [scheduler schedule:^{ [subscriber sendNext:x]; }]; } error:^(NSError *error) { [scheduler schedule:^{ [subscriber sendError:error]; }]; } completed:^{ [scheduler schedule:^{ [subscriber sendCompleted]; }]; }]; }] setNameWithFormat:@"[%@] -deliverOn: %@", self.name, scheduler]; } - (RACSignal *)subscribeOn:(RACScheduler *)scheduler { return [[RACSignal createSignal:^(id subscriber) { RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable]; RACDisposable *schedulingDisposable = [scheduler schedule:^{ RACDisposable *subscriptionDisposable = [self subscribe:subscriber]; [disposable addDisposable:subscriptionDisposable]; }]; [disposable addDisposable:schedulingDisposable]; return disposable; }] setNameWithFormat:@"[%@] -subscribeOn: %@", self.name, scheduler]; } - (RACSignal *)deliverOnMainThread { return [[RACSignal createSignal:^(id subscriber) { __block volatile int32_t queueLength = 0; void (^performOnMainThread)(dispatch_block_t) = ^(dispatch_block_t block) { int32_t queued = OSAtomicIncrement32(&queueLength); if (NSThread.isMainThread && queued == 1) { block(); OSAtomicDecrement32(&queueLength); } else { dispatch_async(dispatch_get_main_queue(), ^{ block(); OSAtomicDecrement32(&queueLength); }); } }; return [self subscribeNext:^(id x) { performOnMainThread(^{ [subscriber sendNext:x]; }); } error:^(NSError *error) { performOnMainThread(^{ [subscriber sendError:error]; }); } completed:^{ performOnMainThread(^{ [subscriber sendCompleted]; }); }]; }] setNameWithFormat:@"[%@] -deliverOnMainThread", self.name]; } - (RACSignal *)groupBy:(id (^)(id object))keyBlock transform:(id (^)(id object))transformBlock { NSCParameterAssert(keyBlock != NULL); return [[RACSignal createSignal:^(id subscriber) { NSMutableDictionary *groups = [NSMutableDictionary dictionary]; NSMutableArray *orderedGroups = [NSMutableArray array]; return [self subscribeNext:^(id x) { id key = keyBlock(x); RACGroupedSignal *groupSubject = nil; @synchronized(groups) { groupSubject = groups[key]; if (groupSubject == nil) { groupSubject = [RACGroupedSignal signalWithKey:key]; groups[key] = groupSubject; [orderedGroups addObject:groupSubject]; [subscriber sendNext:groupSubject]; } } [groupSubject sendNext:transformBlock != NULL ? transformBlock(x) : x]; } error:^(NSError *error) { [subscriber sendError:error]; [orderedGroups makeObjectsPerformSelector:@selector(sendError:) withObject:error]; } completed:^{ [subscriber sendCompleted]; [orderedGroups makeObjectsPerformSelector:@selector(sendCompleted)]; }]; }] setNameWithFormat:@"[%@] -groupBy:transform:", self.name]; } - (RACSignal *)groupBy:(id (^)(id object))keyBlock { return [[self groupBy:keyBlock transform:nil] setNameWithFormat:@"[%@] -groupBy:", self.name]; } - (RACSignal *)any { return [[self any:^(id x) { return YES; }] setNameWithFormat:@"[%@] -any", self.name]; } - (RACSignal *)any:(BOOL (^)(id object))predicateBlock { NSCParameterAssert(predicateBlock != NULL); return [[[self materialize] bind:^{ return ^(RACEvent *event, BOOL *stop) { if (event.finished) { *stop = YES; return [RACSignal return:@NO]; } if (predicateBlock(event.value)) { *stop = YES; return [RACSignal return:@YES]; } return [RACSignal empty]; }; }] setNameWithFormat:@"[%@] -any:", self.name]; } - (RACSignal *)all:(BOOL (^)(id object))predicateBlock { NSCParameterAssert(predicateBlock != NULL); return [[[self materialize] bind:^{ return ^(RACEvent *event, BOOL *stop) { if (event.eventType == RACEventTypeCompleted) { *stop = YES; return [RACSignal return:@YES]; } if (event.eventType == RACEventTypeError || !predicateBlock(event.value)) { *stop = YES; return [RACSignal return:@NO]; } return [RACSignal empty]; }; }] setNameWithFormat:@"[%@] -all:", self.name]; } - (RACSignal *)retry:(NSInteger)retryCount { return [[RACSignal createSignal:^(id subscriber) { __block NSInteger currentRetryCount = 0; return subscribeForever(self, ^(id x) { [subscriber sendNext:x]; }, ^(NSError *error, RACDisposable *disposable) { if (retryCount == 0 || currentRetryCount < retryCount) { // Resubscribe. currentRetryCount++; return; } [disposable dispose]; [subscriber sendError:error]; }, ^(RACDisposable *disposable) { [disposable dispose]; [subscriber sendCompleted]; }); }] setNameWithFormat:@"[%@] -retry: %lu", self.name, (unsigned long)retryCount]; } - (RACSignal *)retry { return [[self retry:0] setNameWithFormat:@"[%@] -retry", self.name]; } - (RACSignal *)sample:(RACSignal *)sampler { NSCParameterAssert(sampler != nil); return [[RACSignal createSignal:^(id subscriber) { NSLock *lock = [[NSLock alloc] init]; __block id lastValue; __block BOOL hasValue = NO; RACSerialDisposable *samplerDisposable = [[RACSerialDisposable alloc] init]; RACDisposable *sourceDisposable = [self subscribeNext:^(id x) { [lock lock]; hasValue = YES; lastValue = x; [lock unlock]; } error:^(NSError *error) { [samplerDisposable dispose]; [subscriber sendError:error]; } completed:^{ [samplerDisposable dispose]; [subscriber sendCompleted]; }]; samplerDisposable.disposable = [sampler subscribeNext:^(id _) { BOOL shouldSend = NO; id value; [lock lock]; shouldSend = hasValue; value = lastValue; [lock unlock]; if (shouldSend) { [subscriber sendNext:value]; } } error:^(NSError *error) { [sourceDisposable dispose]; [subscriber sendError:error]; } completed:^{ [sourceDisposable dispose]; [subscriber sendCompleted]; }]; return [RACDisposable disposableWithBlock:^{ [samplerDisposable dispose]; [sourceDisposable dispose]; }]; }] setNameWithFormat:@"[%@] -sample: %@", self.name, sampler]; } - (RACSignal *)ignoreValues { return [[self filter:^(id _) { return NO; }] setNameWithFormat:@"[%@] -ignoreValues", self.name]; } - (RACSignal *)materialize { return [[RACSignal createSignal:^(id subscriber) { return [self subscribeNext:^(id x) { [subscriber sendNext:[RACEvent eventWithValue:x]]; } error:^(NSError *error) { [subscriber sendNext:[RACEvent eventWithError:error]]; [subscriber sendCompleted]; } completed:^{ [subscriber sendNext:RACEvent.completedEvent]; [subscriber sendCompleted]; }]; }] setNameWithFormat:@"[%@] -materialize", self.name]; } - (RACSignal *)dematerialize { return [[self bind:^{ return ^(RACEvent *event, BOOL *stop) { switch (event.eventType) { case RACEventTypeCompleted: *stop = YES; return [RACSignal empty]; case RACEventTypeError: *stop = YES; return [RACSignal error:event.error]; case RACEventTypeNext: return [RACSignal return:event.value]; } }; }] setNameWithFormat:@"[%@] -dematerialize", self.name]; } - (RACSignal *)not { return [[self map:^(NSNumber *value) { NSCAssert([value isKindOfClass:NSNumber.class], @"-not must only be used on a signal of NSNumbers. Instead, got: %@", value); return @(!value.boolValue); }] setNameWithFormat:@"[%@] -not", self.name]; } - (RACSignal *)and { return [[self map:^(RACTuple *tuple) { NSCAssert([tuple isKindOfClass:RACTuple.class], @"-and must only be used on a signal of RACTuples of NSNumbers. Instead, received: %@", tuple); NSCAssert(tuple.count > 0, @"-and must only be used on a signal of RACTuples of NSNumbers, with at least 1 value in the tuple"); return @([tuple.rac_sequence all:^(NSNumber *number) { NSCAssert([number isKindOfClass:NSNumber.class], @"-and must only be used on a signal of RACTuples of NSNumbers. Instead, tuple contains a non-NSNumber value: %@", tuple); return number.boolValue; }]); }] setNameWithFormat:@"[%@] -and", self.name]; } - (RACSignal *)or { return [[self map:^(RACTuple *tuple) { NSCAssert([tuple isKindOfClass:RACTuple.class], @"-or must only be used on a signal of RACTuples of NSNumbers. Instead, received: %@", tuple); NSCAssert(tuple.count > 0, @"-or must only be used on a signal of RACTuples of NSNumbers, with at least 1 value in the tuple"); return @([tuple.rac_sequence any:^(NSNumber *number) { NSCAssert([number isKindOfClass:NSNumber.class], @"-or must only be used on a signal of RACTuples of NSNumbers. Instead, tuple contains a non-NSNumber value: %@", tuple); return number.boolValue; }]); }] setNameWithFormat:@"[%@] -or", self.name]; } - (RACSignal *)reduceApply { return [[self map:^(RACTuple *tuple) { NSCAssert([tuple isKindOfClass:RACTuple.class], @"-reduceApply must only be used on a signal of RACTuples. Instead, received: %@", tuple); NSCAssert(tuple.count > 1, @"-reduceApply must only be used on a signal of RACTuples, with at least a block in tuple[0] and its first argument in tuple[1]"); // We can't use -array, because we need to preserve RACTupleNil NSMutableArray *tupleArray = [NSMutableArray arrayWithCapacity:tuple.count]; for (id val in tuple) { [tupleArray addObject:val]; } RACTuple *arguments = [RACTuple tupleWithObjectsFromArray:[tupleArray subarrayWithRange:NSMakeRange(1, tupleArray.count - 1)]]; return [RACBlockTrampoline invokeBlock:tuple[0] withArguments:arguments]; }] setNameWithFormat:@"[%@] -reduceApply", self.name]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSignal.h ================================================ // // RACSignal.h // ReactiveCocoa // // Created by Josh Abernathy on 3/1/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import "RACStream.h" @class RACDisposable; @class RACScheduler; @class RACSubject; @protocol RACSubscriber; @interface RACSignal : RACStream /// Creates a new signal. This is the preferred way to create a new signal /// operation or behavior. /// /// Events can be sent to new subscribers immediately in the `didSubscribe` /// block, but the subscriber will not be able to dispose of the signal until /// a RACDisposable is returned from `didSubscribe`. In the case of infinite /// signals, this won't _ever_ happen if events are sent immediately. /// /// To ensure that the signal is disposable, events can be scheduled on the /// +[RACScheduler currentScheduler] (so that they're deferred, not sent /// immediately), or they can be sent in the background. The RACDisposable /// returned by the `didSubscribe` block should cancel any such scheduling or /// asynchronous work. /// /// didSubscribe - Called when the signal is subscribed to. The new subscriber is /// passed in. You can then manually control the by /// sending it -sendNext:, -sendError:, and -sendCompleted, /// as defined by the operation you're implementing. This block /// should return a RACDisposable which cancels any ongoing work /// triggered by the subscription, and cleans up any resources or /// disposables created as part of it. When the disposable is /// disposed of, the signal must not send any more events to the /// `subscriber`. If no cleanup is necessary, return nil. /// /// **Note:** The `didSubscribe` block is called every time a new subscriber /// subscribes. Any side effects within the block will thus execute once for each /// subscription, not necessarily on one thread, and possibly even /// simultaneously! + (RACSignal *)createSignal:(RACDisposable * (^)(id subscriber))didSubscribe; /// Returns a signal that immediately sends the given error. + (RACSignal *)error:(NSError *)error; /// Returns a signal that never completes. + (RACSignal *)never; /// Immediately schedules the given block on the given scheduler. The block is /// given a subscriber to which it can send events. /// /// scheduler - The scheduler on which `block` will be scheduled and results /// delivered. Cannot be nil. /// block - The block to invoke. Cannot be NULL. /// /// Returns a signal which will send all events sent on the subscriber given to /// `block`. All events will be sent on `scheduler` and it will replay any missed /// events to new subscribers. + (RACSignal *)startEagerlyWithScheduler:(RACScheduler *)scheduler block:(void (^)(id subscriber))block; /// Invokes the given block only on the first subscription. The block is given a /// subscriber to which it can send events. /// /// Note that disposing of the subscription to the returned signal will *not* /// dispose of the underlying subscription. If you need that behavior, see /// -[RACMulticastConnection autoconnect]. The underlying subscription will never /// be disposed of. Because of this, `block` should never return an infinite /// signal since there would be no way of ending it. /// /// scheduler - The scheduler on which the block should be scheduled. Note that /// if given +[RACScheduler immediateScheduler], the block will be /// invoked synchronously on the first subscription. Cannot be nil. /// block - The block to invoke on the first subscription. Cannot be NULL. /// /// Returns a signal which will pass through the events sent to the subscriber /// given to `block` and replay any missed events to new subscribers. + (RACSignal *)startLazilyWithScheduler:(RACScheduler *)scheduler block:(void (^)(id subscriber))block; @end @interface RACSignal (RACStream) /// Returns a signal that immediately sends the given value and then completes. + (RACSignal *)return:(id)value; /// Returns a signal that immediately completes. + (RACSignal *)empty; /// Subscribes to `signal` when the source signal completes. - (RACSignal *)concat:(RACSignal *)signal; /// Zips the values in the receiver with those of the given signal to create /// RACTuples. /// /// The first `next` of each stream will be combined, then the second `next`, and /// so forth, until either signal completes or errors. /// /// signal - The signal to zip with. This must not be `nil`. /// /// Returns a new signal of RACTuples, representing the combined values of the /// two signals. Any error from one of the original signals will be forwarded on /// the returned signal. - (RACSignal *)zipWith:(RACSignal *)signal; @end @interface RACSignal (Subscription) /// Subscribes `subscriber` to changes on the receiver. The receiver defines which /// events it actually sends and in what situations the events are sent. /// /// Subscription will always happen on a valid RACScheduler. If the /// +[RACScheduler currentScheduler] cannot be determined at the time of /// subscription (e.g., because the calling code is running on a GCD queue or /// NSOperationQueue), subscription will occur on a private background scheduler. /// On the main thread, subscriptions will always occur immediately, with a /// +[RACScheduler currentScheduler] of +[RACScheduler mainThreadScheduler]. /// /// This method must be overridden by any subclasses. /// /// Returns nil or a disposable. You can call -[RACDisposable dispose] if you /// need to end your subscription before it would "naturally" end, either by /// completing or erroring. Once the disposable has been disposed, the subscriber /// won't receive any more events from the subscription. - (RACDisposable *)subscribe:(id)subscriber; /// Convenience method to subscribe to the `next` event. /// /// This corresponds to `IObserver.OnNext` in Rx. - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock; /// Convenience method to subscribe to the `next` and `completed` events. - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock completed:(void (^)(void))completedBlock; /// Convenience method to subscribe to the `next`, `completed`, and `error` events. - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock; /// Convenience method to subscribe to `error` events. /// /// This corresponds to the `IObserver.OnError` in Rx. - (RACDisposable *)subscribeError:(void (^)(NSError *error))errorBlock; /// Convenience method to subscribe to `completed` events. /// /// This corresponds to the `IObserver.OnCompleted` in Rx. - (RACDisposable *)subscribeCompleted:(void (^)(void))completedBlock; /// Convenience method to subscribe to `next` and `error` events. - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock; /// Convenience method to subscribe to `error` and `completed` events. - (RACDisposable *)subscribeError:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock; @end /// Additional methods to assist with debugging. @interface RACSignal (Debugging) /// Logs all events that the receiver sends. - (RACSignal *)logAll; /// Logs each `next` that the receiver sends. - (RACSignal *)logNext; /// Logs any error that the receiver sends. - (RACSignal *)logError; /// Logs any `completed` event that the receiver sends. - (RACSignal *)logCompleted; @end /// Additional methods to assist with unit testing. /// /// **These methods should never ship in production code.** @interface RACSignal (Testing) /// Spins the main run loop for a short while, waiting for the receiver to send a `next`. /// /// **Because this method executes the run loop recursively, it should only be used /// on the main thread, and only from a unit test.** /// /// defaultValue - Returned if the receiver completes or errors before sending /// a `next`, or if the method times out. This argument may be /// nil. /// success - If not NULL, set to whether the receiver completed /// successfully. /// error - If not NULL, set to any error that occurred. /// /// Returns the first value received, or `defaultValue` if no value is received /// before the signal finishes or the method times out. - (id)asynchronousFirstOrDefault:(id)defaultValue success:(BOOL *)success error:(NSError **)error; /// Spins the main run loop for a short while, waiting for the receiver to complete. /// /// **Because this method executes the run loop recursively, it should only be used /// on the main thread, and only from a unit test.** /// /// error - If not NULL, set to any error that occurs. /// /// Returns whether the signal completed successfully before timing out. If NO, /// `error` will be set to any error that occurred. - (BOOL)asynchronouslyWaitUntilCompleted:(NSError **)error; @end @interface RACSignal (Unavailable) + (RACSignal *)start:(id (^)(BOOL *success, NSError **error))block __attribute__((unavailable("Use +startEagerlyWithScheduler:block: instead"))); + (RACSignal *)startWithScheduler:(RACScheduler *)scheduler subjectBlock:(void (^)(RACSubject *subject))block __attribute__((unavailable("Use +startEagerlyWithScheduler:block: instead"))); + (RACSignal *)startWithScheduler:(RACScheduler *)scheduler block:(id (^)(BOOL *success, NSError **error))block __attribute__((unavailable("Use +startEagerlyWithScheduler:block: instead"))); @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSignal.m ================================================ // // RACSignal.m // ReactiveCocoa // // Created by Josh Abernathy on 3/15/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACSignal.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACDynamicSignal.h" #import "RACEmptySignal.h" #import "RACErrorSignal.h" #import "RACMulticastConnection.h" #import "RACReplaySubject.h" #import "RACReturnSignal.h" #import "RACScheduler.h" #import "RACSerialDisposable.h" #import "RACSignal+Operations.h" #import "RACSubject.h" #import "RACSubscriber+Private.h" #import "RACTuple.h" @implementation RACSignal #pragma mark Lifecycle + (RACSignal *)createSignal:(RACDisposable * (^)(id subscriber))didSubscribe { return [RACDynamicSignal createSignal:didSubscribe]; } + (RACSignal *)error:(NSError *)error { return [RACErrorSignal error:error]; } + (RACSignal *)never { return [[self createSignal:^ RACDisposable * (id subscriber) { return nil; }] setNameWithFormat:@"+never"]; } + (RACSignal *)startEagerlyWithScheduler:(RACScheduler *)scheduler block:(void (^)(id subscriber))block { NSCParameterAssert(scheduler != nil); NSCParameterAssert(block != NULL); RACSignal *signal = [self startLazilyWithScheduler:scheduler block:block]; // Subscribe to force the lazy signal to call its block. [[signal publish] connect]; return [signal setNameWithFormat:@"+startEagerlyWithScheduler: %@ block:", scheduler]; } + (RACSignal *)startLazilyWithScheduler:(RACScheduler *)scheduler block:(void (^)(id subscriber))block { NSCParameterAssert(scheduler != nil); NSCParameterAssert(block != NULL); RACMulticastConnection *connection = [[RACSignal createSignal:^ id (id subscriber) { block(subscriber); return nil; }] multicast:[RACReplaySubject subject]]; return [[[RACSignal createSignal:^ id (id subscriber) { [connection.signal subscribe:subscriber]; [connection connect]; return nil; }] subscribeOn:scheduler] setNameWithFormat:@"+startLazilyWithScheduler: %@ block:", scheduler]; } #pragma mark NSObject - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p> name: %@", self.class, self, self.name]; } @end @implementation RACSignal (RACStream) + (RACSignal *)empty { return [RACEmptySignal empty]; } + (RACSignal *)return:(id)value { return [RACReturnSignal return:value]; } - (RACSignal *)bind:(RACStreamBindBlock (^)(void))block { NSCParameterAssert(block != NULL); /* * -bind: should: * * 1. Subscribe to the original signal of values. * 2. Any time the original signal sends a value, transform it using the binding block. * 3. If the binding block returns a signal, subscribe to it, and pass all of its values through to the subscriber as they're received. * 4. If the binding block asks the bind to terminate, complete the _original_ signal. * 5. When _all_ signals complete, send completed to the subscriber. * * If any signal sends an error at any point, send that to the subscriber. */ return [[RACSignal createSignal:^(id subscriber) { RACStreamBindBlock bindingBlock = block(); NSMutableArray *signals = [NSMutableArray arrayWithObject:self]; RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable]; void (^completeSignal)(RACSignal *, RACDisposable *) = ^(RACSignal *signal, RACDisposable *finishedDisposable) { BOOL removeDisposable = NO; @synchronized (signals) { [signals removeObject:signal]; if (signals.count == 0) { [subscriber sendCompleted]; [compoundDisposable dispose]; } else { removeDisposable = YES; } } if (removeDisposable) [compoundDisposable removeDisposable:finishedDisposable]; }; void (^addSignal)(RACSignal *) = ^(RACSignal *signal) { @synchronized (signals) { [signals addObject:signal]; } RACSerialDisposable *selfDisposable = [[RACSerialDisposable alloc] init]; [compoundDisposable addDisposable:selfDisposable]; RACDisposable *disposable = [signal subscribeNext:^(id x) { [subscriber sendNext:x]; } error:^(NSError *error) { [compoundDisposable dispose]; [subscriber sendError:error]; } completed:^{ @autoreleasepool { completeSignal(signal, selfDisposable); } }]; selfDisposable.disposable = disposable; }; @autoreleasepool { RACSerialDisposable *selfDisposable = [[RACSerialDisposable alloc] init]; [compoundDisposable addDisposable:selfDisposable]; RACDisposable *bindingDisposable = [self subscribeNext:^(id x) { // Manually check disposal to handle synchronous errors. if (compoundDisposable.disposed) return; BOOL stop = NO; id signal = bindingBlock(x, &stop); @autoreleasepool { if (signal != nil) addSignal(signal); if (signal == nil || stop) { [selfDisposable dispose]; completeSignal(self, selfDisposable); } } } error:^(NSError *error) { [compoundDisposable dispose]; [subscriber sendError:error]; } completed:^{ @autoreleasepool { completeSignal(self, selfDisposable); } }]; selfDisposable.disposable = bindingDisposable; } return compoundDisposable; }] setNameWithFormat:@"[%@] -bind:", self.name]; } - (RACSignal *)concat:(RACSignal *)signal { return [[RACSignal createSignal:^(id subscriber) { RACCompoundDisposable *compoundDisposable = [[RACCompoundDisposable alloc] init]; RACDisposable *sourceDisposable = [self subscribeNext:^(id x) { [subscriber sendNext:x]; } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ RACDisposable *concattedDisposable = [signal subscribe:subscriber]; [compoundDisposable addDisposable:concattedDisposable]; }]; [compoundDisposable addDisposable:sourceDisposable]; return compoundDisposable; }] setNameWithFormat:@"[%@] -concat: %@", self.name, signal]; } - (RACSignal *)zipWith:(RACSignal *)signal { NSCParameterAssert(signal != nil); return [[RACSignal createSignal:^(id subscriber) { __block BOOL selfCompleted = NO; NSMutableArray *selfValues = [NSMutableArray array]; __block BOOL otherCompleted = NO; NSMutableArray *otherValues = [NSMutableArray array]; void (^sendCompletedIfNecessary)(void) = ^{ @synchronized (selfValues) { BOOL selfEmpty = (selfCompleted && selfValues.count == 0); BOOL otherEmpty = (otherCompleted && otherValues.count == 0); if (selfEmpty || otherEmpty) [subscriber sendCompleted]; } }; void (^sendNext)(void) = ^{ @synchronized (selfValues) { if (selfValues.count == 0) return; if (otherValues.count == 0) return; RACTuple *tuple = RACTuplePack(selfValues[0], otherValues[0]); [selfValues removeObjectAtIndex:0]; [otherValues removeObjectAtIndex:0]; [subscriber sendNext:tuple]; sendCompletedIfNecessary(); } }; RACDisposable *selfDisposable = [self subscribeNext:^(id x) { @synchronized (selfValues) { [selfValues addObject:x ?: RACTupleNil.tupleNil]; sendNext(); } } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ @synchronized (selfValues) { selfCompleted = YES; sendCompletedIfNecessary(); } }]; RACDisposable *otherDisposable = [signal subscribeNext:^(id x) { @synchronized (selfValues) { [otherValues addObject:x ?: RACTupleNil.tupleNil]; sendNext(); } } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ @synchronized (selfValues) { otherCompleted = YES; sendCompletedIfNecessary(); } }]; return [RACDisposable disposableWithBlock:^{ [selfDisposable dispose]; [otherDisposable dispose]; }]; }] setNameWithFormat:@"[%@] -zipWith: %@", self.name, signal]; } @end @implementation RACSignal (Subscription) - (RACDisposable *)subscribe:(id)subscriber { NSCAssert(NO, @"This method must be overridden by subclasses"); return nil; } - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock { NSCParameterAssert(nextBlock != NULL); RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL]; return [self subscribe:o]; } - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock completed:(void (^)(void))completedBlock { NSCParameterAssert(nextBlock != NULL); NSCParameterAssert(completedBlock != NULL); RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:completedBlock]; return [self subscribe:o]; } - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock { NSCParameterAssert(nextBlock != NULL); NSCParameterAssert(errorBlock != NULL); NSCParameterAssert(completedBlock != NULL); RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:errorBlock completed:completedBlock]; return [self subscribe:o]; } - (RACDisposable *)subscribeError:(void (^)(NSError *error))errorBlock { NSCParameterAssert(errorBlock != NULL); RACSubscriber *o = [RACSubscriber subscriberWithNext:NULL error:errorBlock completed:NULL]; return [self subscribe:o]; } - (RACDisposable *)subscribeCompleted:(void (^)(void))completedBlock { NSCParameterAssert(completedBlock != NULL); RACSubscriber *o = [RACSubscriber subscriberWithNext:NULL error:NULL completed:completedBlock]; return [self subscribe:o]; } - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock { NSCParameterAssert(nextBlock != NULL); NSCParameterAssert(errorBlock != NULL); RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:errorBlock completed:NULL]; return [self subscribe:o]; } - (RACDisposable *)subscribeError:(void (^)(NSError *))errorBlock completed:(void (^)(void))completedBlock { NSCParameterAssert(completedBlock != NULL); NSCParameterAssert(errorBlock != NULL); RACSubscriber *o = [RACSubscriber subscriberWithNext:NULL error:errorBlock completed:completedBlock]; return [self subscribe:o]; } @end @implementation RACSignal (Debugging) - (RACSignal *)logAll { return [[[self logNext] logError] logCompleted]; } - (RACSignal *)logNext { return [[self doNext:^(id x) { NSLog(@"%@ next: %@", self, x); }] setNameWithFormat:@"%@", self.name]; } - (RACSignal *)logError { return [[self doError:^(NSError *error) { NSLog(@"%@ error: %@", self, error); }] setNameWithFormat:@"%@", self.name]; } - (RACSignal *)logCompleted { return [[self doCompleted:^{ NSLog(@"%@ completed", self); }] setNameWithFormat:@"%@", self.name]; } @end @implementation RACSignal (Testing) static const NSTimeInterval RACSignalAsynchronousWaitTimeout = 10; - (id)asynchronousFirstOrDefault:(id)defaultValue success:(BOOL *)success error:(NSError **)error { NSCAssert([NSThread isMainThread], @"%s should only be used from the main thread", __func__); __block id result = defaultValue; __block BOOL done = NO; // Ensures that we don't pass values across thread boundaries by reference. __block NSError *localError; __block BOOL localSuccess = YES; [[[[self take:1] timeout:RACSignalAsynchronousWaitTimeout onScheduler:[RACScheduler scheduler]] deliverOn:RACScheduler.mainThreadScheduler] subscribeNext:^(id x) { result = x; done = YES; } error:^(NSError *e) { if (!done) { localSuccess = NO; localError = e; done = YES; } } completed:^{ done = YES; }]; do { [NSRunLoop.mainRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; } while (!done); if (success != NULL) *success = localSuccess; if (error != NULL) *error = localError; return result; } - (BOOL)asynchronouslyWaitUntilCompleted:(NSError **)error { BOOL success = NO; [[self ignoreValues] asynchronousFirstOrDefault:nil success:&success error:error]; return success; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSignalProvider.d ================================================ provider RACSignal { probe next(char *signal, char *subscriber, char *valueDescription); probe completed(char *signal, char *subscriber); probe error(char *signal, char *subscriber, char *errorDescription); }; ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSignalSequence.h ================================================ // // RACSignalSequence.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-11-09. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACSequence.h" @class RACSignal; // Private class that adapts a RACSignal to the RACSequence interface. @interface RACSignalSequence : RACSequence // Returns a sequence for enumerating over the given signal. + (RACSequence *)sequenceWithSignal:(RACSignal *)signal; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSignalSequence.m ================================================ // // RACSignalSequence.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-11-09. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACSignalSequence.h" #import "RACDisposable.h" #import "RACReplaySubject.h" #import "RACSignal+Operations.h" @interface RACSignalSequence () // Replays the signal given on initialization. @property (nonatomic, strong, readonly) RACReplaySubject *subject; @end @implementation RACSignalSequence #pragma mark Lifecycle + (RACSequence *)sequenceWithSignal:(RACSignal *)signal { RACSignalSequence *seq = [[self alloc] init]; RACReplaySubject *subject = [RACReplaySubject subject]; [signal subscribeNext:^(id value) { [subject sendNext:value]; } error:^(NSError *error) { [subject sendError:error]; } completed:^{ [subject sendCompleted]; }]; seq->_subject = subject; return seq; } #pragma mark RACSequence - (id)head { id value = [self.subject firstOrDefault:self]; if (value == self) { return nil; } else { return value ?: NSNull.null; } } - (RACSequence *)tail { RACSequence *sequence = [self.class sequenceWithSignal:[self.subject skip:1]]; sequence.name = self.name; return sequence; } - (NSArray *)array { return self.subject.toArray; } #pragma mark NSObject - (NSString *)description { // Synchronously accumulate the values that have been sent so far. NSMutableArray *values = [NSMutableArray array]; RACDisposable *disposable = [self.subject subscribeNext:^(id value) { @synchronized (values) { [values addObject:value ?: NSNull.null]; } }]; [disposable dispose]; return [NSString stringWithFormat:@"<%@: %p>{ name = %@, values = %@ … }", self.class, self, self.name, values]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACStream+Private.h ================================================ // // RACStream+Private.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-07-22. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACStream.h" @interface RACStream () // Combines a list of streams using the logic of the given block. // // streams - The streams to combine. // block - An operator that combines two streams and returns a new one. The // returned stream should contain 2-tuples of the streams' combined // values. // // Returns a combined stream. + (instancetype)join:(id)streams block:(RACStream * (^)(id, id))block; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACStream.h ================================================ // // RACStream.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-31. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import @class RACStream; /// A block which accepts a value from a RACStream and returns a new instance /// of the same stream class. /// /// Setting `stop` to `YES` will cause the bind to terminate after the returned /// value. Returning `nil` will result in immediate termination. typedef RACStream * (^RACStreamBindBlock)(id value, BOOL *stop); /// An abstract class representing any stream of values. /// /// This class represents a monad, upon which many stream-based operations can /// be built. /// /// When subclassing RACStream, only the methods in the main @interface body need /// to be overridden. @interface RACStream : NSObject /// Returns an empty stream. + (instancetype)empty; /// Lifts `value` into the stream monad. /// /// Returns a stream containing only the given value. + (instancetype)return:(id)value; /// Lazily binds a block to the values in the receiver. /// /// This should only be used if you need to terminate the bind early, or close /// over some state. -flattenMap: is more appropriate for all other cases. /// /// block - A block returning a RACStreamBindBlock. This block will be invoked /// each time the bound stream is re-evaluated. This block must not be /// nil or return nil. /// /// Returns a new stream which represents the combined result of all lazy /// applications of `block`. - (instancetype)bind:(RACStreamBindBlock (^)(void))block; /// Appends the values of `stream` to the values in the receiver. /// /// stream - A stream to concatenate. This must be an instance of the same /// concrete class as the receiver, and should not be `nil`. /// /// Returns a new stream representing the receiver followed by `stream`. - (instancetype)concat:(RACStream *)stream; /// Zips the values in the receiver with those of the given stream to create /// RACTuples. /// /// The first value of each stream will be combined, then the second value, and /// so forth, until at least one of the streams is exhausted. /// /// stream - The stream to zip with. This must be an instance of the same /// concrete class as the receiver, and should not be `nil`. /// /// Returns a new stream of RACTuples, representing the zipped values of the /// two streams. - (instancetype)zipWith:(RACStream *)stream; @end /// This extension contains functionality to support naming streams for /// debugging. /// /// Subclasses do not need to override the methods here. @interface RACStream () /// The name of the stream. This is for debugging/human purposes only. @property (copy) NSString *name; /// Sets the name of the receiver to the given format string. /// /// This is for debugging purposes only, and won't do anything unless the /// RAC_DEBUG_SIGNAL_NAMES environment variable is set. /// /// Returns the receiver, for easy method chaining. - (instancetype)setNameWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2); @end /// Operations built on the RACStream primitives. /// /// These methods do not need to be overridden, although subclasses may /// occasionally gain better performance from doing so. @interface RACStream (Operations) /// Maps `block` across the values in the receiver and flattens the result. /// /// Note that operators applied _after_ -flattenMap: behave differently from /// operators _within_ -flattenMap:. See the Examples section below. /// /// This corresponds to the `SelectMany` method in Rx. /// /// block - A block which accepts the values in the receiver and returns a new /// instance of the receiver's class. Returning `nil` from this block is /// equivalent to returning an empty signal. /// /// Examples /// /// [signal flattenMap:^(id x) { /// // Logs each time a returned signal completes. /// return [[RACSignal return:x] logCompleted]; /// }]; /// /// [[signal /// flattenMap:^(id x) { /// return [RACSignal return:x]; /// }] /// // Logs only once, when all of the signals complete. /// logCompleted]; /// /// Returns a new stream which represents the combined streams resulting from /// mapping `block`. - (instancetype)flattenMap:(RACStream * (^)(id value))block; /// Flattens a stream of streams. /// /// This corresponds to the `Merge` method in Rx. /// /// Returns a stream consisting of the combined streams obtained from the /// receiver. - (instancetype)flatten; /// Maps `block` across the values in the receiver. /// /// This corresponds to the `Select` method in Rx. /// /// Returns a new stream with the mapped values. - (instancetype)map:(id (^)(id value))block; /// Replaces each value in the receiver with the given object. /// /// Returns a new stream which includes the given object once for each value in /// the receiver. - (instancetype)mapReplace:(id)object; /// Filters out values in the receiver that don't pass the given test. /// /// This corresponds to the `Where` method in Rx. /// /// Returns a new stream with only those values that passed. - (instancetype)filter:(BOOL (^)(id value))block; /// Filters out values in the receiver that equal (via -isEqual:) the provided value. /// /// value - The value can be `nil`, in which case it ignores `nil` values. /// /// Returns a new stream containing only the values which did not compare equal /// to `value`. - (instancetype)ignore:(id)value; /// Unpacks each RACTuple in the receiver and maps the values to a new value. /// /// reduceBlock - The block which reduces each RACTuple's values into one value. /// It must take as many arguments as the number of tuple elements /// to process. Each argument will be an object argument. The /// return value must be an object. This argument cannot be nil. /// /// Returns a new stream of reduced tuple values. - (instancetype)reduceEach:(id (^)())reduceBlock; /// Returns a stream consisting of `value`, followed by the values in the /// receiver. - (instancetype)startWith:(id)value; /// Skips the first `skipCount` values in the receiver. /// /// Returns the receiver after skipping the first `skipCount` values. If /// `skipCount` is greater than the number of values in the stream, an empty /// stream is returned. - (instancetype)skip:(NSUInteger)skipCount; /// Returns a stream of the first `count` values in the receiver. If `count` is /// greater than or equal to the number of values in the stream, a stream /// equivalent to the receiver is returned. - (instancetype)take:(NSUInteger)count; /// Zips the values in the given streams to create RACTuples. /// /// The first value of each stream will be combined, then the second value, and /// so forth, until at least one of the streams is exhausted. /// /// streams - The streams to combine. These must all be instances of the same /// concrete class implementing the protocol. If this collection is /// empty, the returned stream will be empty. /// /// Returns a new stream containing RACTuples of the zipped values from the /// streams. + (instancetype)zip:(id)streams; /// Zips streams using +zip:, then reduces the resulting tuples into a single /// value using -reduceEach: /// /// streams - The streams to combine. These must all be instances of the /// same concrete class implementing the protocol. If this /// collection is empty, the returned stream will be empty. /// reduceBlock - The block which reduces the values from all the streams /// into one value. It must take as many arguments as the /// number of streams given. Each argument will be an object /// argument. The return value must be an object. This argument /// must not be nil. /// /// Example: /// /// [RACStream zip:@[ stringSignal, intSignal ] reduce:^(NSString *string, NSNumber *number) { /// return [NSString stringWithFormat:@"%@: %@", string, number]; /// }]; /// /// Returns a new stream containing the results from each invocation of /// `reduceBlock`. + (instancetype)zip:(id)streams reduce:(id (^)())reduceBlock; /// Returns a stream obtained by concatenating `streams` in order. + (instancetype)concat:(id)streams; /// Combines values in the receiver from left to right using the given block. /// /// The algorithm proceeds as follows: /// /// 1. `startingValue` is passed into the block as the `running` value, and the /// first element of the receiver is passed into the block as the `next` value. /// 2. The result of the invocation is added to the returned stream. /// 3. The result of the invocation (`running`) and the next element of the /// receiver (`next`) is passed into `block`. /// 4. Steps 2 and 3 are repeated until all values have been processed. /// /// startingValue - The value to be combined with the first element of the /// receiver. This value may be `nil`. /// reduceBlock - The block that describes how to combine values of the /// receiver. If the receiver is empty, this block will never be /// invoked. Cannot be nil. /// /// Examples /// /// RACSequence *numbers = @[ @1, @2, @3, @4 ].rac_sequence; /// /// // Contains 1, 3, 6, 10 /// RACSequence *sums = [numbers scanWithStart:@0 reduce:^(NSNumber *sum, NSNumber *next) { /// return @(sum.integerValue + next.integerValue); /// }]; /// /// Returns a new stream that consists of each application of `reduceBlock`. If the /// receiver is empty, an empty stream is returned. - (instancetype)scanWithStart:(id)startingValue reduce:(id (^)(id running, id next))reduceBlock; /// Combines values in the receiver from left to right using the given block /// which also takes zero-based index of the values. /// /// startingValue - The value to be combined with the first element of the /// receiver. This value may be `nil`. /// reduceBlock - The block that describes how to combine values of the /// receiver. This block takes zero-based index value as the last /// parameter. If the receiver is empty, this block will never /// be invoked. Cannot be nil. /// /// Returns a new stream that consists of each application of `reduceBlock`. If the /// receiver is empty, an empty stream is returned. - (instancetype)scanWithStart:(id)startingValue reduceWithIndex:(id (^)(id running, id next, NSUInteger index))reduceBlock; /// Combines each previous and current value into one object. /// /// This method is similar to -scanWithStart:reduce:, but only ever operates on /// the previous and current values (instead of the whole stream), and does not /// pass the return value of `reduceBlock` into the next invocation of it. /// /// start - The value passed into `reduceBlock` as `previous` for the /// first value. /// reduceBlock - The block that combines the previous value and the current /// value to create the reduced value. Cannot be nil. /// /// Examples /// /// RACSequence *numbers = @[ @1, @2, @3, @4 ].rac_sequence; /// /// // Contains 1, 3, 5, 7 /// RACSequence *sums = [numbers combinePreviousWithStart:@0 reduce:^(NSNumber *previous, NSNumber *next) { /// return @(previous.integerValue + next.integerValue); /// }]; /// /// Returns a new stream consisting of the return values from each application of /// `reduceBlock`. - (instancetype)combinePreviousWithStart:(id)start reduce:(id (^)(id previous, id current))reduceBlock; /// Takes values until the given block returns `YES`. /// /// Returns a stream of the initial values in the receiver that fail `predicate`. /// If `predicate` never returns `YES`, a stream equivalent to the receiver is /// returned. - (instancetype)takeUntilBlock:(BOOL (^)(id x))predicate; /// Takes values until the given block returns `NO`. /// /// Returns a stream of the initial values in the receiver that pass `predicate`. /// If `predicate` never returns `NO`, a stream equivalent to the receiver is /// returned. - (instancetype)takeWhileBlock:(BOOL (^)(id x))predicate; /// Skips values until the given block returns `YES`. /// /// Returns a stream containing the values of the receiver that follow any /// initial values failing `predicate`. If `predicate` never returns `YES`, /// an empty stream is returned. - (instancetype)skipUntilBlock:(BOOL (^)(id x))predicate; /// Skips values until the given block returns `NO`. /// /// Returns a stream containing the values of the receiver that follow any /// initial values passing `predicate`. If `predicate` never returns `NO`, an /// empty stream is returned. - (instancetype)skipWhileBlock:(BOOL (^)(id x))predicate; /// Returns a stream of values for which -isEqual: returns NO when compared to the /// previous value. - (instancetype)distinctUntilChanged; @end @interface RACStream (Unavailable) - (instancetype)sequenceMany:(RACStream * (^)(void))block __attribute__((unavailable("Use -flattenMap: instead"))); - (instancetype)scanWithStart:(id)startingValue combine:(id (^)(id running, id next))block __attribute__((unavailable("Renamed to -scanWithStart:reduce:"))); - (instancetype)mapPreviousWithStart:(id)start reduce:(id (^)(id previous, id current))combineBlock __attribute__((unavailable("Renamed to -combinePreviousWithStart:reduce:"))); @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACStream.m ================================================ // // RACStream.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-31. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACStream.h" #import "NSObject+RACDescription.h" #import "RACBlockTrampoline.h" #import "RACTuple.h" @implementation RACStream #pragma mark Lifecycle - (id)init { self = [super init]; if (self == nil) return nil; self.name = @""; return self; } #pragma mark Abstract methods + (instancetype)empty { return nil; } - (instancetype)bind:(RACStreamBindBlock (^)(void))block { return nil; } + (instancetype)return:(id)value { return nil; } - (instancetype)concat:(RACStream *)stream { return nil; } - (instancetype)zipWith:(RACStream *)stream { return nil; } #pragma mark Naming - (instancetype)setNameWithFormat:(NSString *)format, ... { if (getenv("RAC_DEBUG_SIGNAL_NAMES") == NULL) return self; NSCParameterAssert(format != nil); va_list args; va_start(args, format); NSString *str = [[NSString alloc] initWithFormat:format arguments:args]; va_end(args); self.name = str; return self; } @end @implementation RACStream (Operations) - (instancetype)flattenMap:(RACStream * (^)(id value))block { Class class = self.class; return [[self bind:^{ return ^(id value, BOOL *stop) { id stream = block(value) ?: [class empty]; NSCAssert([stream isKindOfClass:RACStream.class], @"Value returned from -flattenMap: is not a stream: %@", stream); return stream; }; }] setNameWithFormat:@"[%@] -flattenMap:", self.name]; } - (instancetype)flatten { __weak RACStream *stream __attribute__((unused)) = self; return [[self flattenMap:^(id value) { return value; }] setNameWithFormat:@"[%@] -flatten", self.name]; } - (instancetype)map:(id (^)(id value))block { NSCParameterAssert(block != nil); Class class = self.class; return [[self flattenMap:^(id value) { return [class return:block(value)]; }] setNameWithFormat:@"[%@] -map:", self.name]; } - (instancetype)mapReplace:(id)object { return [[self map:^(id _) { return object; }] setNameWithFormat:@"[%@] -mapReplace: %@", self.name, RACDescription(object)]; } - (instancetype)combinePreviousWithStart:(id)start reduce:(id (^)(id previous, id next))reduceBlock { NSCParameterAssert(reduceBlock != NULL); return [[[self scanWithStart:RACTuplePack(start) reduce:^(RACTuple *previousTuple, id next) { id value = reduceBlock(previousTuple[0], next); return RACTuplePack(next, value); }] map:^(RACTuple *tuple) { return tuple[1]; }] setNameWithFormat:@"[%@] -combinePreviousWithStart: %@ reduce:", self.name, RACDescription(start)]; } - (instancetype)filter:(BOOL (^)(id value))block { NSCParameterAssert(block != nil); Class class = self.class; return [[self flattenMap:^ id (id value) { if (block(value)) { return [class return:value]; } else { return class.empty; } }] setNameWithFormat:@"[%@] -filter:", self.name]; } - (instancetype)ignore:(id)value { return [[self filter:^ BOOL (id innerValue) { return innerValue != value && ![innerValue isEqual:value]; }] setNameWithFormat:@"[%@] -ignore: %@", self.name, RACDescription(value)]; } - (instancetype)reduceEach:(id (^)())reduceBlock { NSCParameterAssert(reduceBlock != nil); __weak RACStream *stream __attribute__((unused)) = self; return [[self map:^(RACTuple *t) { NSCAssert([t isKindOfClass:RACTuple.class], @"Value from stream %@ is not a tuple: %@", stream, t); return [RACBlockTrampoline invokeBlock:reduceBlock withArguments:t]; }] setNameWithFormat:@"[%@] -reduceEach:", self.name]; } - (instancetype)startWith:(id)value { return [[[self.class return:value] concat:self] setNameWithFormat:@"[%@] -startWith: %@", self.name, RACDescription(value)]; } - (instancetype)skip:(NSUInteger)skipCount { Class class = self.class; return [[self bind:^{ __block NSUInteger skipped = 0; return ^(id value, BOOL *stop) { if (skipped >= skipCount) return [class return:value]; skipped++; return class.empty; }; }] setNameWithFormat:@"[%@] -skip: %lu", self.name, (unsigned long)skipCount]; } - (instancetype)take:(NSUInteger)count { Class class = self.class; if (count == 0) return class.empty; return [[self bind:^{ __block NSUInteger taken = 0; return ^ id (id value, BOOL *stop) { if (taken < count) { ++taken; if (taken == count) *stop = YES; return [class return:value]; } else { return nil; } }; }] setNameWithFormat:@"[%@] -take: %lu", self.name, (unsigned long)count]; } + (instancetype)join:(id)streams block:(RACStream * (^)(id, id))block { RACStream *current = nil; // Creates streams of successively larger tuples by combining the input // streams one-by-one. for (RACStream *stream in streams) { // For the first stream, just wrap its values in a RACTuple. That way, // if only one stream is given, the result is still a stream of tuples. if (current == nil) { current = [stream map:^(id x) { return RACTuplePack(x); }]; continue; } current = block(current, stream); } if (current == nil) return [self empty]; return [current map:^(RACTuple *xs) { // Right now, each value is contained in its own tuple, sorta like: // // (((1), 2), 3) // // We need to unwrap all the layers and create a tuple out of the result. NSMutableArray *values = [[NSMutableArray alloc] init]; while (xs != nil) { [values insertObject:xs.last ?: RACTupleNil.tupleNil atIndex:0]; xs = (xs.count > 1 ? xs.first : nil); } return [RACTuple tupleWithObjectsFromArray:values]; }]; } + (instancetype)zip:(id)streams { return [[self join:streams block:^(RACStream *left, RACStream *right) { return [left zipWith:right]; }] setNameWithFormat:@"+zip: %@", streams]; } + (instancetype)zip:(id)streams reduce:(id (^)())reduceBlock { NSCParameterAssert(reduceBlock != nil); RACStream *result = [self zip:streams]; // Although we assert this condition above, older versions of this method // supported this argument being nil. Avoid crashing Release builds of // apps that depended on that. if (reduceBlock != nil) result = [result reduceEach:reduceBlock]; return [result setNameWithFormat:@"+zip: %@ reduce:", streams]; } + (instancetype)concat:(id)streams { RACStream *result = self.empty; for (RACStream *stream in streams) { result = [result concat:stream]; } return [result setNameWithFormat:@"+concat: %@", streams]; } - (instancetype)scanWithStart:(id)startingValue reduce:(id (^)(id running, id next))reduceBlock { NSCParameterAssert(reduceBlock != nil); return [[self scanWithStart:startingValue reduceWithIndex:^(id running, id next, NSUInteger index) { return reduceBlock(running, next); }] setNameWithFormat:@"[%@] -scanWithStart: %@ reduce:", self.name, RACDescription(startingValue)]; } - (instancetype)scanWithStart:(id)startingValue reduceWithIndex:(id (^)(id, id, NSUInteger))reduceBlock { NSCParameterAssert(reduceBlock != nil); Class class = self.class; return [[self bind:^{ __block id running = startingValue; __block NSUInteger index = 0; return ^(id value, BOOL *stop) { running = reduceBlock(running, value, index++); return [class return:running]; }; }] setNameWithFormat:@"[%@] -scanWithStart: %@ reduceWithIndex:", self.name, RACDescription(startingValue)]; } - (instancetype)takeUntilBlock:(BOOL (^)(id x))predicate { NSCParameterAssert(predicate != nil); Class class = self.class; return [[self bind:^{ return ^ id (id value, BOOL *stop) { if (predicate(value)) return nil; return [class return:value]; }; }] setNameWithFormat:@"[%@] -takeUntilBlock:", self.name]; } - (instancetype)takeWhileBlock:(BOOL (^)(id x))predicate { NSCParameterAssert(predicate != nil); return [[self takeUntilBlock:^ BOOL (id x) { return !predicate(x); }] setNameWithFormat:@"[%@] -takeWhileBlock:", self.name]; } - (instancetype)skipUntilBlock:(BOOL (^)(id x))predicate { NSCParameterAssert(predicate != nil); Class class = self.class; return [[self bind:^{ __block BOOL skipping = YES; return ^ id (id value, BOOL *stop) { if (skipping) { if (predicate(value)) { skipping = NO; } else { return class.empty; } } return [class return:value]; }; }] setNameWithFormat:@"[%@] -skipUntilBlock:", self.name]; } - (instancetype)skipWhileBlock:(BOOL (^)(id x))predicate { NSCParameterAssert(predicate != nil); return [[self skipUntilBlock:^ BOOL (id x) { return !predicate(x); }] setNameWithFormat:@"[%@] -skipWhileBlock:", self.name]; } - (instancetype)distinctUntilChanged { Class class = self.class; return [[self bind:^{ __block id lastValue = nil; __block BOOL initial = YES; return ^(id x, BOOL *stop) { if (!initial && (lastValue == x || [x isEqual:lastValue])) return [class empty]; initial = NO; lastValue = x; return [class return:x]; }; }] setNameWithFormat:@"[%@] -distinctUntilChanged", self.name]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACStringSequence.h ================================================ // // RACStringSequence.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import "RACSequence.h" // Private class that adapts a string to the RACSequence interface. @interface RACStringSequence : RACSequence // Returns a sequence for enumerating over the given string, starting from the // given character offset. The string will be copied to prevent mutation. + (RACSequence *)sequenceWithString:(NSString *)string offset:(NSUInteger)offset; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACStringSequence.m ================================================ // // RACStringSequence.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-10-29. // Copyright (c) 2012 GitHub. All rights reserved. // #import "RACStringSequence.h" @interface RACStringSequence () // The string being sequenced. @property (nonatomic, copy, readonly) NSString *string; // The index in the string from which the sequence starts. @property (nonatomic, assign, readonly) NSUInteger offset; @end @implementation RACStringSequence #pragma mark Lifecycle + (RACSequence *)sequenceWithString:(NSString *)string offset:(NSUInteger)offset { NSCParameterAssert(offset <= string.length); if (offset == string.length) return self.empty; RACStringSequence *seq = [[self alloc] init]; seq->_string = [string copy]; seq->_offset = offset; return seq; } #pragma mark RACSequence - (id)head { return [self.string substringWithRange:NSMakeRange(self.offset, 1)]; } - (RACSequence *)tail { RACSequence *sequence = [self.class sequenceWithString:self.string offset:self.offset + 1]; sequence.name = self.name; return sequence; } - (NSArray *)array { NSUInteger substringLength = self.string.length - self.offset; NSMutableArray *array = [NSMutableArray arrayWithCapacity:substringLength]; [self.string enumerateSubstringsInRange:NSMakeRange(self.offset, substringLength) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) { [array addObject:substring]; }]; return [array copy]; } #pragma mark NSObject - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p>{ name = %@, string = %@ }", self.class, self, self.name, [self.string substringFromIndex:self.offset]]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSubject.h ================================================ // // RACSubject.h // ReactiveCocoa // // Created by Josh Abernathy on 3/9/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACSignal.h" #import "RACSubscriber.h" /// A subject can be thought of as a signal that you can manually control by /// sending next, completed, and error. /// /// They're most helpful in bridging the non-RAC world to RAC, since they let you /// manually control the sending of events. @interface RACSubject : RACSignal /// Returns a new subject. + (instancetype)subject; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSubject.m ================================================ // // RACSubject.m // ReactiveCocoa // // Created by Josh Abernathy on 3/9/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACSubject.h" #import #import "RACCompoundDisposable.h" #import "RACPassthroughSubscriber.h" @interface RACSubject () // Contains all current subscribers to the receiver. // // This should only be used while synchronized on `self`. @property (nonatomic, strong, readonly) NSMutableArray *subscribers; // Contains all of the receiver's subscriptions to other signals. @property (nonatomic, strong, readonly) RACCompoundDisposable *disposable; // Enumerates over each of the receiver's `subscribers` and invokes `block` for // each. - (void)enumerateSubscribersUsingBlock:(void (^)(id subscriber))block; @end @implementation RACSubject #pragma mark Lifecycle + (instancetype)subject { return [[self alloc] init]; } - (id)init { self = [super init]; if (self == nil) return nil; _disposable = [RACCompoundDisposable compoundDisposable]; _subscribers = [[NSMutableArray alloc] initWithCapacity:1]; return self; } - (void)dealloc { [self.disposable dispose]; } #pragma mark Subscription - (RACDisposable *)subscribe:(id)subscriber { NSCParameterAssert(subscriber != nil); RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable]; subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable]; NSMutableArray *subscribers = self.subscribers; @synchronized (subscribers) { [subscribers addObject:subscriber]; } return [RACDisposable disposableWithBlock:^{ @synchronized (subscribers) { // Since newer subscribers are generally shorter-lived, search // starting from the end of the list. NSUInteger index = [subscribers indexOfObjectWithOptions:NSEnumerationReverse passingTest:^ BOOL (id obj, NSUInteger index, BOOL *stop) { return obj == subscriber; }]; if (index != NSNotFound) [subscribers removeObjectAtIndex:index]; } }]; } - (void)enumerateSubscribersUsingBlock:(void (^)(id subscriber))block { NSArray *subscribers; @synchronized (self.subscribers) { subscribers = [self.subscribers copy]; } for (id subscriber in subscribers) { block(subscriber); } } #pragma mark RACSubscriber - (void)sendNext:(id)value { [self enumerateSubscribersUsingBlock:^(id subscriber) { [subscriber sendNext:value]; }]; } - (void)sendError:(NSError *)error { [self.disposable dispose]; [self enumerateSubscribersUsingBlock:^(id subscriber) { [subscriber sendError:error]; }]; } - (void)sendCompleted { [self.disposable dispose]; [self enumerateSubscribersUsingBlock:^(id subscriber) { [subscriber sendCompleted]; }]; } - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)d { if (d.disposed) return; [self.disposable addDisposable:d]; @weakify(self, d); [d addDisposable:[RACDisposable disposableWithBlock:^{ @strongify(self, d); [self.disposable removeDisposable:d]; }]]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSubscriber+Private.h ================================================ // // RACSubscriber+Private.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-06-13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACSubscriber.h" // A simple block-based subscriber. @interface RACSubscriber : NSObject // Creates a new subscriber with the given blocks. + (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSubscriber.h ================================================ // // RACSubscriber.h // ReactiveCocoa // // Created by Josh Abernathy on 3/1/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import @class RACCompoundDisposable; /// Represents any object which can directly receive values from a RACSignal. /// /// You generally shouldn't need to implement this protocol. +[RACSignal /// createSignal:], RACSignal's subscription methods, or RACSubject should work /// for most uses. /// /// Implementors of this protocol may receive messages and values from multiple /// threads simultaneously, and so should be thread-safe. Subscribers will also /// be weakly referenced so implementations must allow that. @protocol RACSubscriber @required /// Sends the next value to subscribers. /// /// value - The value to send. This can be `nil`. - (void)sendNext:(id)value; /// Sends the error to subscribers. /// /// error - The error to send. This can be `nil`. /// /// This terminates the subscription, and invalidates the subscriber (such that /// it cannot subscribe to anything else in the future). - (void)sendError:(NSError *)error; /// Sends completed to subscribers. /// /// This terminates the subscription, and invalidates the subscriber (such that /// it cannot subscribe to anything else in the future). - (void)sendCompleted; /// Sends the subscriber a disposable that represents one of its subscriptions. /// /// A subscriber may receive multiple disposables if it gets subscribed to /// multiple signals; however, any error or completed events must terminate _all_ /// subscriptions. - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSubscriber.m ================================================ // // RACSubscriber.m // ReactiveCocoa // // Created by Josh Abernathy on 3/1/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACSubscriber.h" #import "RACSubscriber+Private.h" #import #import "RACCompoundDisposable.h" @interface RACSubscriber () // These callbacks should only be accessed while synchronized on self. @property (nonatomic, copy) void (^next)(id value); @property (nonatomic, copy) void (^error)(NSError *error); @property (nonatomic, copy) void (^completed)(void); @property (nonatomic, strong, readonly) RACCompoundDisposable *disposable; @end @implementation RACSubscriber #pragma mark Lifecycle + (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed { RACSubscriber *subscriber = [[self alloc] init]; subscriber->_next = [next copy]; subscriber->_error = [error copy]; subscriber->_completed = [completed copy]; return subscriber; } - (id)init { self = [super init]; if (self == nil) return nil; @unsafeify(self); RACDisposable *selfDisposable = [RACDisposable disposableWithBlock:^{ @strongify(self); @synchronized (self) { self.next = nil; self.error = nil; self.completed = nil; } }]; _disposable = [RACCompoundDisposable compoundDisposable]; [_disposable addDisposable:selfDisposable]; return self; } - (void)dealloc { [self.disposable dispose]; } #pragma mark RACSubscriber - (void)sendNext:(id)value { @synchronized (self) { void (^nextBlock)(id) = [self.next copy]; if (nextBlock == nil) return; nextBlock(value); } } - (void)sendError:(NSError *)e { @synchronized (self) { void (^errorBlock)(NSError *) = [self.error copy]; [self.disposable dispose]; if (errorBlock == nil) return; errorBlock(e); } } - (void)sendCompleted { @synchronized (self) { void (^completedBlock)(void) = [self.completed copy]; [self.disposable dispose]; if (completedBlock == nil) return; completedBlock(); } } - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)otherDisposable { if (otherDisposable.disposed) return; RACCompoundDisposable *selfDisposable = self.disposable; [selfDisposable addDisposable:otherDisposable]; @unsafeify(otherDisposable); // If this subscription terminates, purge its disposable to avoid unbounded // memory growth. [otherDisposable addDisposable:[RACDisposable disposableWithBlock:^{ @strongify(otherDisposable); [selfDisposable removeDisposable:otherDisposable]; }]]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSubscriptingAssignmentTrampoline.h ================================================ // // RACSubscriptingAssignmentTrampoline.h // ReactiveCocoa // // Created by Josh Abernathy on 9/24/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import @class RACSignal; /// Assigns a signal to an object property, automatically setting the given key /// path on every `next`. When the signal completes, the binding is automatically /// disposed of. /// /// There are two different versions of this macro: /// /// - RAC(TARGET, KEYPATH, NILVALUE) will bind the `KEYPATH` of `TARGET` to the /// given signal. If the signal ever sends a `nil` value, the property will be /// set to `NILVALUE` instead. `NILVALUE` may itself be `nil` for object /// properties, but an NSValue should be used for primitive properties, to /// avoid an exception if `nil` is sent (which might occur if an intermediate /// object is set to `nil`). /// - RAC(TARGET, KEYPATH) is the same as the above, but `NILVALUE` defaults to /// `nil`. /// /// See -[RACSignal setKeyPath:onObject:nilValue:] for more information about the /// binding's semantics. /// /// Examples /// /// RAC(self, objectProperty) = objectSignal; /// RAC(self, stringProperty, @"foobar") = stringSignal; /// RAC(self, integerProperty, @42) = integerSignal; /// /// WARNING: Under certain conditions, use of this macro can be thread-unsafe. /// See the documentation of -setKeyPath:onObject:nilValue:. #define RAC(TARGET, ...) \ metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__)) \ (RAC_(TARGET, __VA_ARGS__, nil)) \ (RAC_(TARGET, __VA_ARGS__)) /// Do not use this directly. Use the RAC macro above. #define RAC_(TARGET, KEYPATH, NILVALUE) \ [[RACSubscriptingAssignmentTrampoline alloc] initWithTarget:(TARGET) nilValue:(NILVALUE)][@keypath(TARGET, KEYPATH)] @interface RACSubscriptingAssignmentTrampoline : NSObject - (id)initWithTarget:(id)target nilValue:(id)nilValue; - (void)setObject:(RACSignal *)signal forKeyedSubscript:(NSString *)keyPath; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSubscriptingAssignmentTrampoline.m ================================================ // // RACSubscriptingAssignmentTrampoline.m // ReactiveCocoa // // Created by Josh Abernathy on 9/24/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACSubscriptingAssignmentTrampoline.h" #import "RACSignal+Operations.h" @interface RACSubscriptingAssignmentTrampoline () // The object to bind to. @property (nonatomic, strong, readonly) id target; // A value to use when `nil` is sent on the bound signal. @property (nonatomic, strong, readonly) id nilValue; @end @implementation RACSubscriptingAssignmentTrampoline - (id)initWithTarget:(id)target nilValue:(id)nilValue { // This is often a programmer error, but this prevents crashes if the target // object has unexpectedly deallocated. if (target == nil) return nil; self = [super init]; if (self == nil) return nil; _target = target; _nilValue = nilValue; return self; } - (void)setObject:(RACSignal *)signal forKeyedSubscript:(NSString *)keyPath { [signal setKeyPath:keyPath onObject:self.target nilValue:self.nilValue]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSubscriptionScheduler.h ================================================ // // RACSubscriptionScheduler.h // ReactiveCocoa // // Created by Josh Abernathy on 11/30/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACScheduler.h" // A private scheduler used only for subscriptions. See the private // +[RACScheduler subscriptionScheduler] method for more information. @interface RACSubscriptionScheduler : RACScheduler @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACSubscriptionScheduler.m ================================================ // // RACSubscriptionScheduler.m // ReactiveCocoa // // Created by Josh Abernathy on 11/30/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACSubscriptionScheduler.h" #import "RACScheduler+Private.h" @interface RACSubscriptionScheduler () // A private background scheduler on which to subscribe if the +currentScheduler // is unknown. @property (nonatomic, strong, readonly) RACScheduler *backgroundScheduler; @end @implementation RACSubscriptionScheduler #pragma mark Lifecycle - (id)init { self = [super initWithName:@"com.ReactiveCocoa.RACScheduler.subscriptionScheduler"]; if (self == nil) return nil; _backgroundScheduler = [RACScheduler scheduler]; return self; } #pragma mark RACScheduler - (RACDisposable *)schedule:(void (^)(void))block { NSCParameterAssert(block != NULL); if (RACScheduler.currentScheduler == nil) return [self.backgroundScheduler schedule:block]; block(); return nil; } - (RACDisposable *)after:(NSDate *)date schedule:(void (^)(void))block { RACScheduler *scheduler = RACScheduler.currentScheduler ?: self.backgroundScheduler; return [scheduler after:date schedule:block]; } - (RACDisposable *)after:(NSDate *)date repeatingEvery:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway schedule:(void (^)(void))block { RACScheduler *scheduler = RACScheduler.currentScheduler ?: self.backgroundScheduler; return [scheduler after:date repeatingEvery:interval withLeeway:leeway schedule:block]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACTargetQueueScheduler.h ================================================ // // RACTargetQueueScheduler.h // ReactiveCocoa // // Created by Josh Abernathy on 6/6/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACQueueScheduler.h" /// A scheduler that enqueues blocks on a private serial queue, targeting an /// arbitrary GCD queue. @interface RACTargetQueueScheduler : RACQueueScheduler /// Initializes the receiver with a serial queue that will target the given /// `targetQueue`. /// /// name - The name of the scheduler. If nil, a default name will be used. /// targetQueue - The queue to target. Cannot be NULL. /// /// Returns the initialized object. - (id)initWithName:(NSString *)name targetQueue:(dispatch_queue_t)targetQueue; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACTargetQueueScheduler.m ================================================ // // RACTargetQueueScheduler.m // ReactiveCocoa // // Created by Josh Abernathy on 6/6/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACTargetQueueScheduler.h" #import "RACQueueScheduler+Subclass.h" @implementation RACTargetQueueScheduler #pragma mark Lifecycle - (id)initWithName:(NSString *)name targetQueue:(dispatch_queue_t)targetQueue { NSCParameterAssert(targetQueue != NULL); if (name == nil) { name = [NSString stringWithFormat:@"com.ReactiveCocoa.RACTargetQueueScheduler(%s)", dispatch_queue_get_label(targetQueue)]; } dispatch_queue_t queue = dispatch_queue_create(name.UTF8String, DISPATCH_QUEUE_SERIAL); if (queue == NULL) return nil; dispatch_set_target_queue(queue, targetQueue); return [super initWithName:name queue:queue]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACTestScheduler.h ================================================ // // RACTestScheduler.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-07-06. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACScheduler.h" /// A special kind of scheduler that steps through virtualized time. /// /// This scheduler class can be used in unit tests to verify asynchronous /// behaviors without spending significant time waiting. /// /// This class can be used from multiple threads, but only one thread can `step` /// through the enqueued actions at a time. Other threads will wait while the /// scheduled blocks are being executed. @interface RACTestScheduler : RACScheduler /// Initializes a new test scheduler. - (instancetype)init; /// Executes the next scheduled block, if any. /// /// This method will block until the scheduled action has completed. - (void)step; /// Executes up to the next `ticks` scheduled blocks. /// /// This method will block until the scheduled actions have completed. /// /// ticks - The number of scheduled blocks to execute. If there aren't this many /// blocks enqueued, all scheduled blocks are executed. - (void)step:(NSUInteger)ticks; /// Executes all of the scheduled blocks on the receiver. /// /// This method will block until the scheduled actions have completed. - (void)stepAll; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACTestScheduler.m ================================================ // // RACTestScheduler.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-07-06. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACTestScheduler.h" #import #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACScheduler+Private.h" @interface RACTestSchedulerAction : NSObject // The date at which the action should be executed. // // This absolute time will not actually be honored. This date is only used for // comparison, to determine which block should be run _next_. @property (nonatomic, copy, readonly) NSDate *date; // The scheduled block. @property (nonatomic, copy, readonly) void (^block)(void); // A disposable for this action. // // When disposed, the action should not start executing if it hasn't already. @property (nonatomic, strong, readonly) RACDisposable *disposable; // Initializes a new scheduler action. - (id)initWithDate:(NSDate *)date block:(void (^)(void))block; @end static CFComparisonResult RACCompareScheduledActions(const void *ptr1, const void *ptr2, void *info) { RACTestSchedulerAction *action1 = (__bridge id)ptr1; RACTestSchedulerAction *action2 = (__bridge id)ptr2; return CFDateCompare((__bridge CFDateRef)action1.date, (__bridge CFDateRef)action2.date, NULL); } static const void *RACRetainScheduledAction(CFAllocatorRef allocator, const void *ptr) { return CFRetain(ptr); } static void RACReleaseScheduledAction(CFAllocatorRef allocator, const void *ptr) { CFRelease(ptr); } @interface RACTestScheduler () // All of the RACTestSchedulerActions that have been enqueued and not yet // executed. // // The minimum value in the heap represents the action to execute next. // // This property should only be used while synchronized on self. @property (nonatomic, assign, readonly) CFBinaryHeapRef scheduledActions; // The number of blocks that have been directly enqueued with -schedule: so // far. // // This is used to ensure unique dates when two blocks are enqueued // simultaneously. // // This property should only be used while synchronized on self. @property (nonatomic, assign) NSUInteger numberOfDirectlyScheduledBlocks; @end @implementation RACTestScheduler #pragma mark Lifecycle - (instancetype)init { self = [super initWithName:@"org.reactivecocoa.ReactiveCocoa.RACTestScheduler"]; if (self == nil) return nil; CFBinaryHeapCallBacks callbacks = (CFBinaryHeapCallBacks){ .version = 0, .retain = &RACRetainScheduledAction, .release = &RACReleaseScheduledAction, .copyDescription = &CFCopyDescription, .compare = &RACCompareScheduledActions }; _scheduledActions = CFBinaryHeapCreate(NULL, 0, &callbacks, NULL); return self; } - (void)dealloc { [self stepAll]; if (_scheduledActions != NULL) { CFBridgingRelease(_scheduledActions); _scheduledActions = NULL; } } #pragma mark Execution - (void)step { [self step:1]; } - (void)step:(NSUInteger)ticks { @synchronized (self) { for (NSUInteger i = 0; i < ticks; i++) { const void *actionPtr = NULL; if (!CFBinaryHeapGetMinimumIfPresent(self.scheduledActions, &actionPtr)) break; RACTestSchedulerAction *action = (__bridge id)actionPtr; CFBinaryHeapRemoveMinimumValue(self.scheduledActions); if (action.disposable.disposed) continue; RACScheduler *previousScheduler = RACScheduler.currentScheduler; NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey] = self; action.block(); if (previousScheduler != nil) { NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey] = previousScheduler; } else { [NSThread.currentThread.threadDictionary removeObjectForKey:RACSchedulerCurrentSchedulerKey]; } } } } - (void)stepAll { [self step:NSUIntegerMax]; } #pragma mark RACScheduler - (RACDisposable *)schedule:(void (^)(void))block { NSCParameterAssert(block != nil); @synchronized (self) { NSDate *uniqueDate = [NSDate dateWithTimeIntervalSinceReferenceDate:self.numberOfDirectlyScheduledBlocks]; self.numberOfDirectlyScheduledBlocks++; RACTestSchedulerAction *action = [[RACTestSchedulerAction alloc] initWithDate:uniqueDate block:block]; CFBinaryHeapAddValue(self.scheduledActions, (__bridge void *)action); return action.disposable; } } - (RACDisposable *)after:(NSDate *)date schedule:(void (^)(void))block { NSCParameterAssert(date != nil); NSCParameterAssert(block != nil); @synchronized (self) { RACTestSchedulerAction *action = [[RACTestSchedulerAction alloc] initWithDate:date block:block]; CFBinaryHeapAddValue(self.scheduledActions, (__bridge void *)action); return action.disposable; } } - (RACDisposable *)after:(NSDate *)date repeatingEvery:(NSTimeInterval)interval withLeeway:(NSTimeInterval)leeway schedule:(void (^)(void))block { NSCParameterAssert(date != nil); NSCParameterAssert(block != nil); NSCParameterAssert(interval >= 0); NSCParameterAssert(leeway >= 0); RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable]; @weakify(self); @synchronized (self) { __block RACDisposable *thisDisposable = nil; void (^reschedulingBlock)(void) = ^{ @strongify(self); [compoundDisposable removeDisposable:thisDisposable]; // Schedule the next interval. RACDisposable *schedulingDisposable = [self after:[date dateByAddingTimeInterval:interval] repeatingEvery:interval withLeeway:leeway schedule:block]; [compoundDisposable addDisposable:schedulingDisposable]; block(); }; RACTestSchedulerAction *action = [[RACTestSchedulerAction alloc] initWithDate:date block:reschedulingBlock]; CFBinaryHeapAddValue(self.scheduledActions, (__bridge void *)action); thisDisposable = action.disposable; [compoundDisposable addDisposable:thisDisposable]; } return compoundDisposable; } @end @implementation RACTestSchedulerAction #pragma mark Lifecycle - (id)initWithDate:(NSDate *)date block:(void (^)(void))block { NSCParameterAssert(date != nil); NSCParameterAssert(block != nil); self = [super init]; if (self == nil) return nil; _date = [date copy]; _block = [block copy]; _disposable = [[RACDisposable alloc] init]; return self; } #pragma mark NSObject - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p>{ date: %@ }", self.class, self, self.date]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACTuple.h ================================================ // // RACTuple.h // ReactiveCocoa // // Created by Josh Abernathy on 4/12/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import "metamacros.h" @class RACSequence; /// Creates a new tuple with the given values. At least one value must be given. /// Values can be nil. #define RACTuplePack(...) \ RACTuplePack_(__VA_ARGS__) /// Declares new object variables and unpacks a RACTuple into them. /// /// This macro should be used on the left side of an assignment, with the /// tuple on the right side. Nothing else should appear on the same line, and the /// macro should not be the only statement in a conditional or loop body. /// /// If the tuple has more values than there are variables listed, the excess /// values are ignored. /// /// If the tuple has fewer values than there are variables listed, the excess /// variables are initialized to nil. /// /// Examples /// /// RACTupleUnpack(NSString *string, NSNumber *num) = [RACTuple tupleWithObjects:@"foo", @5, nil]; /// NSLog(@"string: %@", string); /// NSLog(@"num: %@", num); /// /// /* The above is equivalent to: */ /// RACTuple *t = [RACTuple tupleWithObjects:@"foo", @5, nil]; /// NSString *string = t[0]; /// NSNumber *num = t[1]; /// NSLog(@"string: %@", string); /// NSLog(@"num: %@", num); #define RACTupleUnpack(...) \ RACTupleUnpack_(__VA_ARGS__) /// A sentinel object that represents nils in the tuple. /// /// It should never be necessary to create a tuple nil yourself. Just use /// +tupleNil. @interface RACTupleNil : NSObject /// A singleton instance. + (RACTupleNil *)tupleNil; @end /// A tuple is an ordered collection of objects. It may contain nils, represented /// by RACTupleNil. @interface RACTuple : NSObject @property (nonatomic, readonly) NSUInteger count; /// These properties all return the object at that index or nil if the number of /// objects is less than the index. @property (nonatomic, readonly) id first; @property (nonatomic, readonly) id second; @property (nonatomic, readonly) id third; @property (nonatomic, readonly) id fourth; @property (nonatomic, readonly) id fifth; @property (nonatomic, readonly) id last; /// Creates a new tuple out of the array. Does not convert nulls to nils. + (instancetype)tupleWithObjectsFromArray:(NSArray *)array; /// Creates a new tuple out of the array. If `convert` is YES, it also converts /// every NSNull to RACTupleNil. + (instancetype)tupleWithObjectsFromArray:(NSArray *)array convertNullsToNils:(BOOL)convert; /// Creates a new tuple with the given objects. Use RACTupleNil to represent /// nils. + (instancetype)tupleWithObjects:(id)object, ... NS_REQUIRES_NIL_TERMINATION; /// Returns the object at `index` or nil if the object is a RACTupleNil. Unlike /// NSArray and friends, it's perfectly fine to ask for the object at an index /// past the tuple's count - 1. It will simply return nil. - (id)objectAtIndex:(NSUInteger)index; /// Returns an array of all the objects. RACTupleNils are converted to NSNulls. - (NSArray *)allObjects; /// Appends `obj` to the receiver. /// /// obj - The object to add to the tuple. This argument may be nil. /// /// Returns a new tuple. - (instancetype)tupleByAddingObject:(id)obj; @end @interface RACTuple (RACSequenceAdditions) /// Returns a sequence of all the objects. RACTupleNils are converted to NSNulls. @property (nonatomic, copy, readonly) RACSequence *rac_sequence; @end @interface RACTuple (ObjectSubscripting) /// Returns the object at that index or nil if the number of objects is less /// than the index. - (id)objectAtIndexedSubscript:(NSUInteger)idx; @end /// This and everything below is for internal use only. /// /// See RACTuplePack() and RACTupleUnpack() instead. #define RACTuplePack_(...) \ ([RACTuple tupleWithObjectsFromArray:@[ metamacro_foreach(RACTuplePack_object_or_ractuplenil,, __VA_ARGS__) ]]) #define RACTuplePack_object_or_ractuplenil(INDEX, ARG) \ (ARG) ?: RACTupleNil.tupleNil, #define RACTupleUnpack_(...) \ metamacro_foreach(RACTupleUnpack_decl,, __VA_ARGS__) \ \ int RACTupleUnpack_state = 0; \ \ RACTupleUnpack_after: \ ; \ metamacro_foreach(RACTupleUnpack_assign,, __VA_ARGS__) \ if (RACTupleUnpack_state != 0) RACTupleUnpack_state = 2; \ \ while (RACTupleUnpack_state != 2) \ if (RACTupleUnpack_state == 1) { \ goto RACTupleUnpack_after; \ } else \ for (; RACTupleUnpack_state != 1; RACTupleUnpack_state = 1) \ [RACTupleUnpackingTrampoline trampoline][ @[ metamacro_foreach(RACTupleUnpack_value,, __VA_ARGS__) ] ] #define RACTupleUnpack_state metamacro_concat(RACTupleUnpack_state, __LINE__) #define RACTupleUnpack_after metamacro_concat(RACTupleUnpack_after, __LINE__) #define RACTupleUnpack_loop metamacro_concat(RACTupleUnpack_loop, __LINE__) #define RACTupleUnpack_decl_name(INDEX) \ metamacro_concat(metamacro_concat(RACTupleUnpack, __LINE__), metamacro_concat(_var, INDEX)) #define RACTupleUnpack_decl(INDEX, ARG) \ __strong id RACTupleUnpack_decl_name(INDEX); #define RACTupleUnpack_assign(INDEX, ARG) \ __strong ARG = RACTupleUnpack_decl_name(INDEX); #define RACTupleUnpack_value(INDEX, ARG) \ [NSValue valueWithPointer:&RACTupleUnpack_decl_name(INDEX)], @interface RACTupleUnpackingTrampoline : NSObject + (instancetype)trampoline; - (void)setObject:(RACTuple *)tuple forKeyedSubscript:(NSArray *)variables; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACTuple.m ================================================ // // RACTuple.m // ReactiveCocoa // // Created by Josh Abernathy on 4/12/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACTuple.h" #import #import "RACTupleSequence.h" @implementation RACTupleNil + (RACTupleNil *)tupleNil { static dispatch_once_t onceToken; static RACTupleNil *tupleNil = nil; dispatch_once(&onceToken, ^{ tupleNil = [[self alloc] init]; }); return tupleNil; } #pragma mark NSCopying - (id)copyWithZone:(NSZone *)zone { return self; } #pragma mark NSCoding - (id)initWithCoder:(NSCoder *)coder { // Always return the singleton. return self.class.tupleNil; } - (void)encodeWithCoder:(NSCoder *)coder { } @end @interface RACTuple () @property (nonatomic, strong) NSArray *backingArray; @end @implementation RACTuple - (instancetype)init { self = [super init]; if (self == nil) return nil; self.backingArray = [NSArray array]; return self; } - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p> %@", self.class, self, self.allObjects]; } - (BOOL)isEqual:(RACTuple *)object { if (object == self) return YES; if (![object isKindOfClass:self.class]) return NO; return [self.backingArray isEqual:object.backingArray]; } - (NSUInteger)hash { return self.backingArray.hash; } #pragma mark NSFastEnumeration - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])buffer count:(NSUInteger)len { return [self.backingArray countByEnumeratingWithState:state objects:buffer count:len]; } #pragma mark NSCopying - (instancetype)copyWithZone:(NSZone *)zone { // we're immutable, bitches! return self; } #pragma mark NSCoding - (id)initWithCoder:(NSCoder *)coder { self = [self init]; if (self == nil) return nil; self.backingArray = [coder decodeObjectForKey:@keypath(self.backingArray)]; return self; } - (void)encodeWithCoder:(NSCoder *)coder { if (self.backingArray != nil) [coder encodeObject:self.backingArray forKey:@keypath(self.backingArray)]; } #pragma mark API + (instancetype)tupleWithObjectsFromArray:(NSArray *)array { return [self tupleWithObjectsFromArray:array convertNullsToNils:NO]; } + (instancetype)tupleWithObjectsFromArray:(NSArray *)array convertNullsToNils:(BOOL)convert { RACTuple *tuple = [[self alloc] init]; if (convert) { NSMutableArray *newArray = [NSMutableArray arrayWithCapacity:array.count]; for (id object in array) { [newArray addObject:(object == NSNull.null ? RACTupleNil.tupleNil : object)]; } tuple.backingArray = newArray; } else { tuple.backingArray = [array copy]; } return tuple; } + (instancetype)tupleWithObjects:(id)object, ... { RACTuple *tuple = [[self alloc] init]; va_list args; va_start(args, object); NSUInteger count = 0; for (id currentObject = object; currentObject != nil; currentObject = va_arg(args, id)) { ++count; } va_end(args); if (count == 0) { tuple.backingArray = @[]; return tuple; } NSMutableArray *objects = [[NSMutableArray alloc] initWithCapacity:count]; va_start(args, object); for (id currentObject = object; currentObject != nil; currentObject = va_arg(args, id)) { [objects addObject:currentObject]; } va_end(args); tuple.backingArray = objects; return tuple; } - (id)objectAtIndex:(NSUInteger)index { if (index >= self.count) return nil; id object = self.backingArray[index]; return (object == RACTupleNil.tupleNil ? nil : object); } - (NSArray *)allObjects { NSMutableArray *newArray = [NSMutableArray arrayWithCapacity:self.backingArray.count]; for (id object in self.backingArray) { [newArray addObject:(object == RACTupleNil.tupleNil ? NSNull.null : object)]; } return newArray; } - (instancetype)tupleByAddingObject:(id)obj { NSArray *newArray = [self.backingArray arrayByAddingObject:obj ?: RACTupleNil.tupleNil]; return [self.class tupleWithObjectsFromArray:newArray]; } - (NSUInteger)count { return self.backingArray.count; } - (id)first { return self[0]; } - (id)second { return self[1]; } - (id)third { return self[2]; } - (id)fourth { return self[3]; } - (id)fifth { return self[4]; } - (id)last { return self[self.count - 1]; } @end @implementation RACTuple (RACSequenceAdditions) - (RACSequence *)rac_sequence { return [RACTupleSequence sequenceWithTupleBackingArray:self.backingArray offset:0]; } @end @implementation RACTuple (ObjectSubscripting) - (id)objectAtIndexedSubscript:(NSUInteger)idx { return [self objectAtIndex:idx]; } @end @implementation RACTupleUnpackingTrampoline #pragma mark Lifecycle + (instancetype)trampoline { static dispatch_once_t onceToken; static id trampoline = nil; dispatch_once(&onceToken, ^{ trampoline = [[self alloc] init]; }); return trampoline; } - (void)setObject:(RACTuple *)tuple forKeyedSubscript:(NSArray *)variables { NSCParameterAssert(variables != nil); [variables enumerateObjectsUsingBlock:^(NSValue *value, NSUInteger index, BOOL *stop) { __strong id *ptr = (__strong id *)value.pointerValue; *ptr = tuple[index]; }]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACTupleSequence.h ================================================ // // RACTupleSequence.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-05-01. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACSequence.h" // Private class that adapts a RACTuple to the RACSequence interface. @interface RACTupleSequence : RACSequence // Returns a sequence for enumerating over the given backing array (from a // RACTuple), starting from the given offset. + (instancetype)sequenceWithTupleBackingArray:(NSArray *)backingArray offset:(NSUInteger)offset; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACTupleSequence.m ================================================ // // RACTupleSequence.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-05-01. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACTupleSequence.h" #import "RACTuple.h" @interface RACTupleSequence () // The array being sequenced, as taken from RACTuple.backingArray. @property (nonatomic, strong, readonly) NSArray *tupleBackingArray; // The index in the array from which the sequence starts. @property (nonatomic, assign, readonly) NSUInteger offset; @end @implementation RACTupleSequence #pragma mark Lifecycle + (instancetype)sequenceWithTupleBackingArray:(NSArray *)backingArray offset:(NSUInteger)offset { NSCParameterAssert(offset <= backingArray.count); if (offset == backingArray.count) return self.empty; RACTupleSequence *seq = [[self alloc] init]; seq->_tupleBackingArray = backingArray; seq->_offset = offset; return seq; } #pragma mark RACSequence - (id)head { id object = self.tupleBackingArray[self.offset]; return (object == RACTupleNil.tupleNil ? NSNull.null : object); } - (RACSequence *)tail { RACSequence *sequence = [self.class sequenceWithTupleBackingArray:self.tupleBackingArray offset:self.offset + 1]; sequence.name = self.name; return sequence; } - (NSArray *)array { NSRange range = NSMakeRange(self.offset, self.tupleBackingArray.count - self.offset); NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:range.length]; [self.tupleBackingArray enumerateObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range] options:0 usingBlock:^(id object, NSUInteger index, BOOL *stop) { id mappedObject = (object == RACTupleNil.tupleNil ? NSNull.null : object); [array addObject:mappedObject]; }]; return array; } #pragma mark NSObject - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p>{ name = %@, tuple = %@ }", self.class, self, self.name, self.tupleBackingArray]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACUnarySequence.h ================================================ // // RACUnarySequence.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-05-01. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACSequence.h" // Private class representing a sequence of exactly one value. @interface RACUnarySequence : RACSequence @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACUnarySequence.m ================================================ // // RACUnarySequence.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-05-01. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACUnarySequence.h" #import #import "NSObject+RACDescription.h" @interface RACUnarySequence () // The single value stored in this sequence. @property (nonatomic, strong, readwrite) id head; @end @implementation RACUnarySequence #pragma mark Properties @synthesize head = _head; #pragma mark Lifecycle + (instancetype)return:(id)value { RACUnarySequence *sequence = [[self alloc] init]; sequence.head = value; return [sequence setNameWithFormat:@"+return: %@", RACDescription(value)]; } #pragma mark RACSequence - (RACSequence *)tail { return nil; } - (instancetype)bind:(RACStreamBindBlock (^)(void))block { RACStreamBindBlock bindBlock = block(); BOOL stop = NO; RACSequence *result = (id)[bindBlock(self.head, &stop) setNameWithFormat:@"[%@] -bind:", self.name]; return result ?: self.class.empty; } #pragma mark NSCoding - (Class)classForCoder { // Unary sequences should be encoded as themselves, not array sequences. return self.class; } - (id)initWithCoder:(NSCoder *)coder { id value = [coder decodeObjectForKey:@keypath(self.head)]; return [self.class return:value]; } - (void)encodeWithCoder:(NSCoder *)coder { if (self.head != nil) [coder encodeObject:self.head forKey:@keypath(self.head)]; } #pragma mark NSObject - (NSString *)description { return [NSString stringWithFormat:@"<%@: %p>{ name = %@, head = %@ }", self.class, self, self.name, self.head]; } - (NSUInteger)hash { return [self.head hash]; } - (BOOL)isEqual:(RACUnarySequence *)seq { if (self == seq) return YES; if (![seq isKindOfClass:RACUnarySequence.class]) return NO; return self.head == seq.head || [(NSObject *)self.head isEqual:seq.head]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACUnit.h ================================================ // // RACUnit.h // ReactiveCocoa // // Created by Josh Abernathy on 3/27/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import /// A unit represents an empty value. /// /// It should never be necessary to create a unit yourself. Just use +defaultUnit. @interface RACUnit : NSObject /// A singleton instance. + (RACUnit *)defaultUnit; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACUnit.m ================================================ // // RACUnit.m // ReactiveCocoa // // Created by Josh Abernathy on 3/27/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACUnit.h" @implementation RACUnit #pragma mark API + (RACUnit *)defaultUnit { static dispatch_once_t onceToken; static RACUnit *defaultUnit = nil; dispatch_once(&onceToken, ^{ defaultUnit = [[self alloc] init]; }); return defaultUnit; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACValueTransformer.h ================================================ // // RACValueTransformer.h // ReactiveCocoa // // Created by Josh Abernathy on 3/6/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import // A private block based transformer. @interface RACValueTransformer : NSValueTransformer + (instancetype)transformerWithBlock:(id (^)(id value))block; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/RACValueTransformer.m ================================================ // // RACValueTransformer.m // ReactiveCocoa // // Created by Josh Abernathy on 3/6/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACValueTransformer.h" @interface RACValueTransformer () @property (nonatomic, copy) id (^transformBlock)(id value); @end @implementation RACValueTransformer #pragma mark NSValueTransformer + (BOOL)allowsReverseTransformation { return NO; } - (id)transformedValue:(id)value { return self.transformBlock(value); } #pragma mark API @synthesize transformBlock; + (instancetype)transformerWithBlock:(id (^)(id value))block { NSCParameterAssert(block != NULL); RACValueTransformer *transformer = [[self alloc] init]; transformer.transformBlock = block; return transformer; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/ReactiveCocoa-Bridging-Header.h ================================================ // // Use this file to import your target's public headers that you would like to expose to Swift. // #import "RACCommand.h" #import "RACDisposable.h" #import "RACEvent.h" #import "RACScheduler.h" #import "RACTargetQueueScheduler.h" #import "RACSignal.h" #import "RACSignal+Operations.h" #import "RACStream.h" #import "RACSubscriber.h" ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIActionSheet+RACSignalSupport.h ================================================ // // UIActionSheet+RACSignalSupport.h // ReactiveCocoa // // Created by Dave Lee on 2013-06-22. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACDelegateProxy; @class RACSignal; @interface UIActionSheet (RACSignalSupport) /// A delegate proxy which will be set as the receiver's delegate when any of the /// methods in this category are used. @property (nonatomic, strong, readonly) RACDelegateProxy *rac_delegateProxy; /// Creates a signal for button clicks on the receiver. /// /// When this method is invoked, the `rac_delegateProxy` will become the /// receiver's delegate. Any previous delegate will become the -[RACDelegateProxy /// rac_proxiedDelegate], so that it receives any messages that the proxy doesn't /// know how to handle. Setting the receiver's `delegate` afterward is /// considered undefined behavior. /// /// Returns a signal which will send the index of the specific button clicked. /// The signal will complete when the receiver is deallocated. - (RACSignal *)rac_buttonClickedSignal; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIActionSheet+RACSignalSupport.m ================================================ // // UIActionSheet+RACSignalSupport.m // ReactiveCocoa // // Created by Dave Lee on 2013-06-22. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "UIActionSheet+RACSignalSupport.h" #import "RACDelegateProxy.h" #import "RACSignal+Operations.h" #import "NSObject+RACDeallocating.h" #import "NSObject+RACDescription.h" #import @implementation UIActionSheet (RACSignalSupport) static void RACUseDelegateProxy(UIActionSheet *self) { if (self.delegate == self.rac_delegateProxy) return; self.rac_delegateProxy.rac_proxiedDelegate = self.delegate; self.delegate = (id)self.rac_delegateProxy; } - (RACDelegateProxy *)rac_delegateProxy { RACDelegateProxy *proxy = objc_getAssociatedObject(self, _cmd); if (proxy == nil) { proxy = [[RACDelegateProxy alloc] initWithProtocol:@protocol(UIActionSheetDelegate)]; objc_setAssociatedObject(self, _cmd, proxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return proxy; } - (RACSignal *)rac_buttonClickedSignal { RACSignal *signal = [[[[self.rac_delegateProxy signalForSelector:@selector(actionSheet:clickedButtonAtIndex:)] reduceEach:^(UIActionSheet *actionSheet, NSNumber *buttonIndex) { return buttonIndex; }] takeUntil:self.rac_willDeallocSignal] setNameWithFormat:@"%@ -rac_buttonClickedSignal", RACDescription(self)]; RACUseDelegateProxy(self); return signal; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIAlertView+RACSignalSupport.h ================================================ // // UIAlertView+RACSignalSupport.h // ReactiveCocoa // // Created by Henrik Hodne on 6/16/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACDelegateProxy; @class RACSignal; @interface UIAlertView (RACSignalSupport) /// A delegate proxy which will be set as the receiver's delegate when any of the /// methods in this category are used. @property (nonatomic, strong, readonly) RACDelegateProxy *rac_delegateProxy; /// Creates a signal for button clicks on the receiver. /// /// When this method is invoked, the `rac_delegateProxy` will become the /// receiver's delegate. Any previous delegate will become the -[RACDelegateProxy /// rac_proxiedDelegate], so that it receives any messages that the proxy doesn't /// know how to handle. Setting the receiver's `delegate` afterward is considered /// undefined behavior. /// /// Note that this signal will not send a value when the alert is dismissed /// programatically. /// /// Returns a signal which will send the index of the specific button clicked. /// The signal will complete itself when the receiver is deallocated. - (RACSignal *)rac_buttonClickedSignal; /// Creates a signal for dismissal of the receiver. /// /// When this method is invoked, the `rac_delegateProxy` will become the /// receiver's delegate. Any previous delegate will become the -[RACDelegateProxy /// rac_proxiedDelegate], so that it receives any messages that the proxy doesn't /// know how to handle. Setting the receiver's `delegate` afterward is considered /// undefined behavior. /// /// Returns a signal which will send the index of the button associated with the /// dismissal. The signal will complete itself when the receiver is deallocated. - (RACSignal *)rac_willDismissSignal; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIAlertView+RACSignalSupport.m ================================================ // // UIAlertView+RACSignalSupport.m // ReactiveCocoa // // Created by Henrik Hodne on 6/16/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "UIAlertView+RACSignalSupport.h" #import "RACDelegateProxy.h" #import "RACSignal+Operations.h" #import "NSObject+RACDeallocating.h" #import "NSObject+RACDescription.h" #import @implementation UIAlertView (RACSignalSupport) static void RACUseDelegateProxy(UIAlertView *self) { if (self.delegate == self.rac_delegateProxy) return; self.rac_delegateProxy.rac_proxiedDelegate = self.delegate; self.delegate = (id)self.rac_delegateProxy; } - (RACDelegateProxy *)rac_delegateProxy { RACDelegateProxy *proxy = objc_getAssociatedObject(self, _cmd); if (proxy == nil) { proxy = [[RACDelegateProxy alloc] initWithProtocol:@protocol(UIAlertViewDelegate)]; objc_setAssociatedObject(self, _cmd, proxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return proxy; } - (RACSignal *)rac_buttonClickedSignal { RACSignal *signal = [[[[self.rac_delegateProxy signalForSelector:@selector(alertView:clickedButtonAtIndex:)] reduceEach:^(UIAlertView *alertView, NSNumber *buttonIndex) { return buttonIndex; }] takeUntil:self.rac_willDeallocSignal] setNameWithFormat:@"%@ -rac_buttonClickedSignal", RACDescription(self)]; RACUseDelegateProxy(self); return signal; } - (RACSignal *)rac_willDismissSignal { RACSignal *signal = [[[[self.rac_delegateProxy signalForSelector:@selector(alertView:willDismissWithButtonIndex:)] reduceEach:^(UIAlertView *alertView, NSNumber *buttonIndex) { return buttonIndex; }] takeUntil:self.rac_willDeallocSignal] setNameWithFormat:@"%@ -rac_willDismissSignal", RACDescription(self)]; RACUseDelegateProxy(self); return signal; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIBarButtonItem+RACCommandSupport.h ================================================ // // UIBarButtonItem+RACCommandSupport.h // ReactiveCocoa // // Created by Kyle LeNeau on 3/27/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACCommand; @interface UIBarButtonItem (RACCommandSupport) /// Sets the control's command. When the control is clicked, the command is /// executed with the sender of the event. The control's enabledness is bound /// to the command's `canExecute`. /// /// Note: this will reset the control's target and action. @property (nonatomic, strong) RACCommand *rac_command; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIBarButtonItem+RACCommandSupport.m ================================================ // // UIBarButtonItem+RACCommandSupport.m // ReactiveCocoa // // Created by Kyle LeNeau on 3/27/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "UIBarButtonItem+RACCommandSupport.h" #import #import "RACCommand.h" #import "RACDisposable.h" #import "RACSignal+Operations.h" #import static void *UIControlRACCommandKey = &UIControlRACCommandKey; static void *UIControlEnabledDisposableKey = &UIControlEnabledDisposableKey; @implementation UIBarButtonItem (RACCommandSupport) - (RACCommand *)rac_command { return objc_getAssociatedObject(self, UIControlRACCommandKey); } - (void)setRac_command:(RACCommand *)command { objc_setAssociatedObject(self, UIControlRACCommandKey, command, OBJC_ASSOCIATION_RETAIN_NONATOMIC); // Check for stored signal in order to remove it and add a new one RACDisposable *disposable = objc_getAssociatedObject(self, UIControlEnabledDisposableKey); [disposable dispose]; if (command == nil) return; disposable = [command.enabled setKeyPath:@keypath(self.enabled) onObject:self]; objc_setAssociatedObject(self, UIControlEnabledDisposableKey, disposable, OBJC_ASSOCIATION_RETAIN_NONATOMIC); [self rac_hijackActionAndTargetIfNeeded]; } - (void)rac_hijackActionAndTargetIfNeeded { SEL hijackSelector = @selector(rac_commandPerformAction:); if (self.target == self && self.action == hijackSelector) return; if (self.target != nil) NSLog(@"WARNING: UIBarButtonItem.rac_command hijacks the control's existing target and action."); self.target = self; self.action = hijackSelector; } - (void)rac_commandPerformAction:(id)sender { [self.rac_command execute:sender]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIButton+RACCommandSupport.h ================================================ // // UIButton+RACCommandSupport.h // ReactiveCocoa // // Created by Ash Furrow on 2013-06-06. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACCommand; @interface UIButton (RACCommandSupport) /// Sets the button's command. When the button is clicked, the command is /// executed with the sender of the event. The button's enabledness is bound /// to the command's `canExecute`. @property (nonatomic, strong) RACCommand *rac_command; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIButton+RACCommandSupport.m ================================================ // // UIButton+RACCommandSupport.m // ReactiveCocoa // // Created by Ash Furrow on 2013-06-06. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "UIButton+RACCommandSupport.h" #import #import "RACCommand.h" #import "RACDisposable.h" #import "RACSignal+Operations.h" #import static void *UIButtonRACCommandKey = &UIButtonRACCommandKey; static void *UIButtonEnabledDisposableKey = &UIButtonEnabledDisposableKey; @implementation UIButton (RACCommandSupport) - (RACCommand *)rac_command { return objc_getAssociatedObject(self, UIButtonRACCommandKey); } - (void)setRac_command:(RACCommand *)command { objc_setAssociatedObject(self, UIButtonRACCommandKey, command, OBJC_ASSOCIATION_RETAIN_NONATOMIC); // Check for stored signal in order to remove it and add a new one RACDisposable *disposable = objc_getAssociatedObject(self, UIButtonEnabledDisposableKey); [disposable dispose]; if (command == nil) return; disposable = [command.enabled setKeyPath:@keypath(self.enabled) onObject:self]; objc_setAssociatedObject(self, UIButtonEnabledDisposableKey, disposable, OBJC_ASSOCIATION_RETAIN_NONATOMIC); [self rac_hijackActionAndTargetIfNeeded]; } - (void)rac_hijackActionAndTargetIfNeeded { SEL hijackSelector = @selector(rac_commandPerformAction:); for (NSString *selector in [self actionsForTarget:self forControlEvent:UIControlEventTouchUpInside]) { if (hijackSelector == NSSelectorFromString(selector)) { return; } } [self addTarget:self action:hijackSelector forControlEvents:UIControlEventTouchUpInside]; } - (void)rac_commandPerformAction:(id)sender { [self.rac_command execute:sender]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UICollectionReusableView+RACSignalSupport.h ================================================ // // UICollectionReusableView+RACSignalSupport.h // ReactiveCocoa // // Created by Kent Wong on 2013-10-04. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACSignal; // This category is only applicable to iOS >= 6.0. @interface UICollectionReusableView (RACSignalSupport) /// A signal which will send a RACUnit whenever -prepareForReuse is invoked upon /// the receiver. /// /// Examples /// /// [[[self.cancelButton /// rac_signalForControlEvents:UIControlEventTouchUpInside] /// takeUntil:self.rac_prepareForReuseSignal] /// subscribeNext:^(UIButton *x) { /// // do other things /// }]; @property (nonatomic, strong, readonly) RACSignal *rac_prepareForReuseSignal; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UICollectionReusableView+RACSignalSupport.m ================================================ // // UICollectionReusableView+RACSignalSupport.m // ReactiveCocoa // // Created by Kent Wong on 2013-10-04. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "UICollectionReusableView+RACSignalSupport.h" #import "NSObject+RACDescription.h" #import "NSObject+RACSelectorSignal.h" #import "RACSignal+Operations.h" #import "RACUnit.h" #import @implementation UICollectionReusableView (RACSignalSupport) - (RACSignal *)rac_prepareForReuseSignal { RACSignal *signal = objc_getAssociatedObject(self, _cmd); if (signal != nil) return signal; signal = [[[self rac_signalForSelector:@selector(prepareForReuse)] mapReplace:RACUnit.defaultUnit] setNameWithFormat:@"%@ -rac_prepareForReuseSignal", RACDescription(self)]; objc_setAssociatedObject(self, _cmd, signal, OBJC_ASSOCIATION_RETAIN_NONATOMIC); return signal; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIControl+RACSignalSupport.h ================================================ // // UIControl+RACSignalSupport.h // ReactiveCocoa // // Created by Josh Abernathy on 4/17/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import @class RACSignal; @interface UIControl (RACSignalSupport) /// Creates and returns a signal that sends the sender of the control event /// whenever one of the control events is triggered. - (RACSignal *)rac_signalForControlEvents:(UIControlEvents)controlEvents; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIControl+RACSignalSupport.m ================================================ // // UIControl+RACSignalSupport.m // ReactiveCocoa // // Created by Josh Abernathy on 4/17/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "UIControl+RACSignalSupport.h" #import #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACSignal.h" #import "RACSubscriber.h" #import "NSObject+RACDeallocating.h" #import "NSObject+RACDescription.h" @implementation UIControl (RACSignalSupport) - (RACSignal *)rac_signalForControlEvents:(UIControlEvents)controlEvents { @weakify(self); return [[RACSignal createSignal:^(id subscriber) { @strongify(self); [self addTarget:subscriber action:@selector(sendNext:) forControlEvents:controlEvents]; [self.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ [subscriber sendCompleted]; }]]; return [RACDisposable disposableWithBlock:^{ @strongify(self); [self removeTarget:subscriber action:@selector(sendNext:) forControlEvents:controlEvents]; }]; }] setNameWithFormat:@"%@ -rac_signalForControlEvents: %lx", RACDescription(self), (unsigned long)controlEvents]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIControl+RACSignalSupportPrivate.h ================================================ // // UIControl+RACSignalSupportPrivate.h // ReactiveCocoa // // Created by Uri Baghin on 06/08/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACChannelTerminal; @interface UIControl (RACSignalSupportPrivate) // Adds a RACChannel-based interface to the receiver for the given // UIControlEvents and exposes it. // // controlEvents - A mask of UIControlEvents on which to send new values. // key - The key whose value should be read and set when a control // event fires and when a value is sent to the // RACChannelTerminal respectively. // nilValue - The value to be assigned to the key when `nil` is sent to the // RACChannelTerminal. // // Returns a RACChannelTerminal which will send future values from the receiver, // and update the receiver when values are sent to the terminal. - (RACChannelTerminal *)rac_channelForControlEvents:(UIControlEvents)controlEvents key:(NSString *)key nilValue:(id)nilValue; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIControl+RACSignalSupportPrivate.m ================================================ // // UIControl+RACSignalSupportPrivate.m // ReactiveCocoa // // Created by Uri Baghin on 06/08/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "UIControl+RACSignalSupportPrivate.h" #import "NSObject+RACDeallocating.h" #import "NSObject+RACLifting.h" #import "RACChannel.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACSignal+Operations.h" #import "UIControl+RACSignalSupport.h" @implementation UIControl (RACSignalSupportPrivate) - (RACChannelTerminal *)rac_channelForControlEvents:(UIControlEvents)controlEvents key:(NSString *)key nilValue:(id)nilValue { NSCParameterAssert(key.length > 0); key = [key copy]; RACChannel *channel = [[RACChannel alloc] init]; [self.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ [channel.followingTerminal sendCompleted]; }]]; RACSignal *eventSignal = [[[self rac_signalForControlEvents:controlEvents] mapReplace:key] takeUntil:[[channel.followingTerminal ignoreValues] catchTo:RACSignal.empty]]; [[self rac_liftSelector:@selector(valueForKey:) withSignals:eventSignal, nil] subscribe:channel.followingTerminal]; RACSignal *valuesSignal = [channel.followingTerminal map:^(id value) { return value ?: nilValue; }]; [self rac_liftSelector:@selector(setValue:forKey:) withSignals:valuesSignal, [RACSignal return:key], nil]; return channel.leadingTerminal; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIDatePicker+RACSignalSupport.h ================================================ // // UIDatePicker+RACSignalSupport.h // ReactiveCocoa // // Created by Uri Baghin on 20/07/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACChannelTerminal; @interface UIDatePicker (RACSignalSupport) /// Creates a new RACChannel-based binding to the receiver. /// /// nilValue - The date to set when the terminal receives `nil`. /// /// Returns a RACChannelTerminal that sends the receiver's date whenever the /// UIControlEventValueChanged control event is fired, and sets the date to the /// values it receives. - (RACChannelTerminal *)rac_newDateChannelWithNilValue:(NSDate *)nilValue; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIDatePicker+RACSignalSupport.m ================================================ // // UIDatePicker+RACSignalSupport.m // ReactiveCocoa // // Created by Uri Baghin on 20/07/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "UIDatePicker+RACSignalSupport.h" #import #import "UIControl+RACSignalSupportPrivate.h" @implementation UIDatePicker (RACSignalSupport) - (RACChannelTerminal *)rac_newDateChannelWithNilValue:(NSDate *)nilValue { return [self rac_channelForControlEvents:UIControlEventValueChanged key:@keypath(self.date) nilValue:nilValue]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIGestureRecognizer+RACSignalSupport.h ================================================ // // UIGestureRecognizer+RACSignalSupport.h // ReactiveCocoa // // Created by Josh Vera on 5/5/13. // Copyright (c) 2013 GitHub. All rights reserved. // #import @class RACSignal; @interface UIGestureRecognizer (RACSignalSupport) /// Returns a signal that sends the receiver when its gesture occurs. - (RACSignal *)rac_gestureSignal; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIGestureRecognizer+RACSignalSupport.m ================================================ // // UIGestureRecognizer+RACSignalSupport.m // ReactiveCocoa // // Created by Josh Vera on 5/5/13. // Copyright (c) 2013 GitHub. All rights reserved. // #import "UIGestureRecognizer+RACSignalSupport.h" #import #import "NSObject+RACDeallocating.h" #import "NSObject+RACDescription.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACSignal.h" #import "RACSubscriber.h" @implementation UIGestureRecognizer (RACSignalSupport) - (RACSignal *)rac_gestureSignal { @weakify(self); return [[RACSignal createSignal:^(id subscriber) { @strongify(self); [self addTarget:subscriber action:@selector(sendNext:)]; [self.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ [subscriber sendCompleted]; }]]; return [RACDisposable disposableWithBlock:^{ @strongify(self); [self removeTarget:subscriber action:@selector(sendNext:)]; }]; }] setNameWithFormat:@"%@ -rac_gestureSignal", RACDescription(self)]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIImagePickerController+RACSignalSupport.h ================================================ // // UIImagePickerController+RACSignalSupport.h // ReactiveCocoa // // Created by Timur Kuchkarov on 28.03.14. // Copyright (c) 2014 GitHub. All rights reserved. // #import @class RACDelegateProxy; @class RACSignal; @interface UIImagePickerController (RACSignalSupport) /// A delegate proxy which will be set as the receiver's delegate when any of the /// methods in this category are used. @property (nonatomic, strong, readonly) RACDelegateProxy *rac_delegateProxy; /// Creates a signal for every new selected image. /// /// When this method is invoked, the `rac_delegateProxy` will become the /// receiver's delegate. Any previous delegate will become the -[RACDelegateProxy /// rac_proxiedDelegate], so that it receives any messages that the proxy doesn't /// know how to handle. Setting the receiver's `delegate` afterward is considered /// undefined behavior. /// /// Returns a signal which will send the dictionary with info for the selected image. /// Caller is responsible for picker controller dismissal. The signal will complete /// itself when the receiver is deallocated or when user cancels selection. - (RACSignal *)rac_imageSelectedSignal; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIImagePickerController+RACSignalSupport.m ================================================ // // UIImagePickerController+RACSignalSupport.m // ReactiveCocoa // // Created by Timur Kuchkarov on 28.03.14. // Copyright (c) 2014 GitHub. All rights reserved. // #import "UIImagePickerController+RACSignalSupport.h" #import "RACDelegateProxy.h" #import "RACSignal+Operations.h" #import "NSObject+RACDeallocating.h" #import "NSObject+RACDescription.h" #import @implementation UIImagePickerController (RACSignalSupport) static void RACUseDelegateProxy(UIImagePickerController *self) { if (self.delegate == self.rac_delegateProxy) return; self.rac_delegateProxy.rac_proxiedDelegate = self.delegate; self.delegate = (id)self.rac_delegateProxy; } - (RACDelegateProxy *)rac_delegateProxy { RACDelegateProxy *proxy = objc_getAssociatedObject(self, _cmd); if (proxy == nil) { proxy = [[RACDelegateProxy alloc] initWithProtocol:@protocol(UIImagePickerControllerDelegate)]; objc_setAssociatedObject(self, _cmd, proxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return proxy; } - (RACSignal *)rac_imageSelectedSignal { RACSignal *pickerCancelledSignal = [[self.rac_delegateProxy signalForSelector:@selector(imagePickerControllerDidCancel:)] merge:self.rac_willDeallocSignal]; RACSignal *imagePickerSignal = [[[[self.rac_delegateProxy signalForSelector:@selector(imagePickerController:didFinishPickingMediaWithInfo:)] reduceEach:^(UIImagePickerController *pickerController, NSDictionary *userInfo) { return userInfo; }] takeUntil:pickerCancelledSignal] setNameWithFormat:@"%@ -rac_imageSelectedSignal", RACDescription(self)]; RACUseDelegateProxy(self); return imagePickerSignal; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIRefreshControl+RACCommandSupport.h ================================================ // // UIRefreshControl+RACCommandSupport.h // ReactiveCocoa // // Created by Dave Lee on 2013-10-17. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACCommand; @interface UIRefreshControl (RACCommandSupport) /// Manipulate the RACCommand property associated with this refresh control. /// /// When this refresh control is activated by the user, the command will be /// executed. Upon completion or error of the execution signal, -endRefreshing /// will be invoked. @property (nonatomic, strong) RACCommand *rac_command; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIRefreshControl+RACCommandSupport.m ================================================ // // UIRefreshControl+RACCommandSupport.m // ReactiveCocoa // // Created by Dave Lee on 2013-10-17. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "UIRefreshControl+RACCommandSupport.h" #import #import "RACCommand.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACSignal.h" #import "RACSignal+Operations.h" #import "UIControl+RACSignalSupport.h" #import static void *UIRefreshControlRACCommandKey = &UIRefreshControlRACCommandKey; static void *UIRefreshControlDisposableKey = &UIRefreshControlDisposableKey; @implementation UIRefreshControl (RACCommandSupport) - (RACCommand *)rac_command { return objc_getAssociatedObject(self, UIRefreshControlRACCommandKey); } - (void)setRac_command:(RACCommand *)command { objc_setAssociatedObject(self, UIRefreshControlRACCommandKey, command, OBJC_ASSOCIATION_RETAIN_NONATOMIC); // Dispose of any active command associations. [objc_getAssociatedObject(self, UIRefreshControlDisposableKey) dispose]; if (command == nil) return; // Like RAC(self, enabled) = command.enabled; but with access to disposable. RACDisposable *enabledDisposable = [command.enabled setKeyPath:@keypath(self.enabled) onObject:self]; RACDisposable *executionDisposable = [[[[[self rac_signalForControlEvents:UIControlEventValueChanged] map:^(UIRefreshControl *x) { return [[[command execute:x] catchTo:[RACSignal empty]] then:^{ return [RACSignal return:x]; }]; }] concat] deliverOnMainThread] subscribeNext:^(UIRefreshControl *x) { [x endRefreshing]; }]; RACDisposable *commandDisposable = [RACCompoundDisposable compoundDisposableWithDisposables:@[ enabledDisposable, executionDisposable ]]; objc_setAssociatedObject(self, UIRefreshControlDisposableKey, commandDisposable, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UISegmentedControl+RACSignalSupport.h ================================================ // // UISegmentedControl+RACSignalSupport.h // ReactiveCocoa // // Created by Uri Baghin on 20/07/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACChannelTerminal; @interface UISegmentedControl (RACSignalSupport) /// Creates a new RACChannel-based binding to the receiver. /// /// nilValue - The segment to select when the terminal receives `nil`. /// /// Returns a RACChannelTerminal that sends the receiver's currently selected /// segment's index whenever the UIControlEventValueChanged control event is /// fired, and sets the selected segment index to the values it receives. - (RACChannelTerminal *)rac_newSelectedSegmentIndexChannelWithNilValue:(NSNumber *)nilValue; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UISegmentedControl+RACSignalSupport.m ================================================ // // UISegmentedControl+RACSignalSupport.m // ReactiveCocoa // // Created by Uri Baghin on 20/07/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "UISegmentedControl+RACSignalSupport.h" #import #import "UIControl+RACSignalSupportPrivate.h" @implementation UISegmentedControl (RACSignalSupport) - (RACChannelTerminal *)rac_newSelectedSegmentIndexChannelWithNilValue:(NSNumber *)nilValue { return [self rac_channelForControlEvents:UIControlEventValueChanged key:@keypath(self.selectedSegmentIndex) nilValue:nilValue]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UISlider+RACSignalSupport.h ================================================ // // UISlider+RACSignalSupport.h // ReactiveCocoa // // Created by Uri Baghin on 20/07/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACChannelTerminal; @interface UISlider (RACSignalSupport) /// Creates a new RACChannel-based binding to the receiver. /// /// nilValue - The value to set when the terminal receives `nil`. /// /// Returns a RACChannelTerminal that sends the receiver's value whenever the /// UIControlEventValueChanged control event is fired, and sets the value to the /// values it receives. - (RACChannelTerminal *)rac_newValueChannelWithNilValue:(NSNumber *)nilValue; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UISlider+RACSignalSupport.m ================================================ // // UISlider+RACSignalSupport.m // ReactiveCocoa // // Created by Uri Baghin on 20/07/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "UISlider+RACSignalSupport.h" #import #import "UIControl+RACSignalSupportPrivate.h" @implementation UISlider (RACSignalSupport) - (RACChannelTerminal *)rac_newValueChannelWithNilValue:(NSNumber *)nilValue { return [self rac_channelForControlEvents:UIControlEventValueChanged key:@keypath(self.value) nilValue:nilValue]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIStepper+RACSignalSupport.h ================================================ // // UIStepper+RACSignalSupport.h // ReactiveCocoa // // Created by Uri Baghin on 20/07/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACChannelTerminal; @interface UIStepper (RACSignalSupport) /// Creates a new RACChannel-based binding to the receiver. /// /// nilValue - The value to set when the terminal receives `nil`. /// /// Returns a RACChannelTerminal that sends the receiver's value whenever the /// UIControlEventValueChanged control event is fired, and sets the value to the /// values it receives. - (RACChannelTerminal *)rac_newValueChannelWithNilValue:(NSNumber *)nilValue; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UIStepper+RACSignalSupport.m ================================================ // // UIStepper+RACSignalSupport.m // ReactiveCocoa // // Created by Uri Baghin on 20/07/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "UIStepper+RACSignalSupport.h" #import #import "UIControl+RACSignalSupportPrivate.h" @implementation UIStepper (RACSignalSupport) - (RACChannelTerminal *)rac_newValueChannelWithNilValue:(NSNumber *)nilValue { return [self rac_channelForControlEvents:UIControlEventValueChanged key:@keypath(self.value) nilValue:nilValue]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UISwitch+RACSignalSupport.h ================================================ // // UISwitch+RACSignalSupport.h // ReactiveCocoa // // Created by Uri Baghin on 20/07/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACChannelTerminal; @interface UISwitch (RACSignalSupport) /// Creates a new RACChannel-based binding to the receiver. /// /// Returns a RACChannelTerminal that sends whether the receiver is on whenever /// the UIControlEventValueChanged control event is fired, and sets it on or off /// when it receives @YES or @NO respectively. - (RACChannelTerminal *)rac_newOnChannel; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UISwitch+RACSignalSupport.m ================================================ // // UISwitch+RACSignalSupport.m // ReactiveCocoa // // Created by Uri Baghin on 20/07/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "UISwitch+RACSignalSupport.h" #import #import "UIControl+RACSignalSupportPrivate.h" @implementation UISwitch (RACSignalSupport) - (RACChannelTerminal *)rac_newOnChannel { return [self rac_channelForControlEvents:UIControlEventValueChanged key:@keypath(self.on) nilValue:@NO]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UITableViewCell+RACSignalSupport.h ================================================ // // UITableViewCell+RACSignalSupport.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-07-22. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACSignal; @interface UITableViewCell (RACSignalSupport) /// A signal which will send a RACUnit whenever -prepareForReuse is invoked upon /// the receiver. /// /// Examples /// /// [[[self.cancelButton /// rac_signalForControlEvents:UIControlEventTouchUpInside] /// takeUntil:self.rac_prepareForReuseSignal] /// subscribeNext:^(UIButton *x) { /// // do other things /// }]; @property (nonatomic, strong, readonly) RACSignal *rac_prepareForReuseSignal; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UITableViewCell+RACSignalSupport.m ================================================ // // UITableViewCell+RACSignalSupport.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-07-22. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "UITableViewCell+RACSignalSupport.h" #import "NSObject+RACDescription.h" #import "NSObject+RACSelectorSignal.h" #import "RACSignal+Operations.h" #import "RACUnit.h" #import @implementation UITableViewCell (RACSignalSupport) - (RACSignal *)rac_prepareForReuseSignal { RACSignal *signal = objc_getAssociatedObject(self, _cmd); if (signal != nil) return signal; signal = [[[self rac_signalForSelector:@selector(prepareForReuse)] mapReplace:RACUnit.defaultUnit] setNameWithFormat:@"%@ -rac_prepareForReuseSignal", RACDescription(self)]; objc_setAssociatedObject(self, _cmd, signal, OBJC_ASSOCIATION_RETAIN_NONATOMIC); return signal; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UITableViewHeaderFooterView+RACSignalSupport.h ================================================ // // UITableViewHeaderFooterView+RACSignalSupport.h // ReactiveCocoa // // Created by Syo Ikeda on 12/30/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @class RACSignal; // This category is only applicable to iOS >= 6.0. @interface UITableViewHeaderFooterView (RACSignalSupport) /// A signal which will send a RACUnit whenever -prepareForReuse is invoked upon /// the receiver. /// /// Examples /// /// [[[self.cancelButton /// rac_signalForControlEvents:UIControlEventTouchUpInside] /// takeUntil:self.rac_prepareForReuseSignal] /// subscribeNext:^(UIButton *x) { /// // do other things /// }]; @property (nonatomic, strong, readonly) RACSignal *rac_prepareForReuseSignal; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UITableViewHeaderFooterView+RACSignalSupport.m ================================================ // // UITableViewHeaderFooterView+RACSignalSupport.m // ReactiveCocoa // // Created by Syo Ikeda on 12/30/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "UITableViewHeaderFooterView+RACSignalSupport.h" #import "NSObject+RACDescription.h" #import "NSObject+RACSelectorSignal.h" #import "RACSignal+Operations.h" #import "RACUnit.h" #import @implementation UITableViewHeaderFooterView (RACSignalSupport) - (RACSignal *)rac_prepareForReuseSignal { RACSignal *signal = objc_getAssociatedObject(self, _cmd); if (signal != nil) return signal; signal = [[[self rac_signalForSelector:@selector(prepareForReuse)] mapReplace:RACUnit.defaultUnit] setNameWithFormat:@"%@ -rac_prepareForReuseSignal", RACDescription(self)]; objc_setAssociatedObject(self, _cmd, signal, OBJC_ASSOCIATION_RETAIN_NONATOMIC); return signal; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UITextField+RACSignalSupport.h ================================================ // // UITextField+RACSignalSupport.h // ReactiveCocoa // // Created by Josh Abernathy on 4/17/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import @class RACChannelTerminal; @class RACSignal; @interface UITextField (RACSignalSupport) /// Creates and returns a signal for the text of the field. It always starts with /// the current text. The signal sends next when the UIControlEventAllEditingEvents /// control event is fired on the control. - (RACSignal *)rac_textSignal; /// Creates a new RACChannel-based binding to the receiver. /// /// Returns a RACChannelTerminal that sends the receiver's text whenever the /// UIControlEventAllEditingEvents control event is fired, and sets the text /// to the values it receives. - (RACChannelTerminal *)rac_newTextChannel; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UITextField+RACSignalSupport.m ================================================ // // UITextField+RACSignalSupport.m // ReactiveCocoa // // Created by Josh Abernathy on 4/17/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "UITextField+RACSignalSupport.h" #import #import #import "NSObject+RACDeallocating.h" #import "NSObject+RACDescription.h" #import "RACSignal+Operations.h" #import "UIControl+RACSignalSupport.h" #import "UIControl+RACSignalSupportPrivate.h" @implementation UITextField (RACSignalSupport) - (RACSignal *)rac_textSignal { @weakify(self); return [[[[[RACSignal defer:^{ @strongify(self); return [RACSignal return:self]; }] concat:[self rac_signalForControlEvents:UIControlEventAllEditingEvents]] map:^(UITextField *x) { return x.text; }] takeUntil:self.rac_willDeallocSignal] setNameWithFormat:@"%@ -rac_textSignal", RACDescription(self)]; } - (RACChannelTerminal *)rac_newTextChannel { return [self rac_channelForControlEvents:UIControlEventAllEditingEvents key:@keypath(self.text) nilValue:@""]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UITextView+RACSignalSupport.h ================================================ // // UITextView+RACSignalSupport.h // ReactiveCocoa // // Created by Cody Krieger on 5/18/12. // Copyright (c) 2012 Cody Krieger. All rights reserved. // #import @class RACDelegateProxy; @class RACSignal; @interface UITextView (RACSignalSupport) /// A delegate proxy which will be set as the receiver's delegate when any of the /// methods in this category are used. @property (nonatomic, strong, readonly) RACDelegateProxy *rac_delegateProxy; /// Creates a signal for the text of the receiver. /// /// When this method is invoked, the `rac_delegateProxy` will become the /// receiver's delegate. Any previous delegate will become the -[RACDelegateProxy /// rac_proxiedDelegate], so that it receives any messages that the proxy doesn't /// know how to handle. Setting the receiver's `delegate` afterward is /// considered undefined behavior. /// /// Returns a signal which will send the current text upon subscription, then /// again whenever the receiver's text is changed. The signal will complete when /// the receiver is deallocated. - (RACSignal *)rac_textSignal; @end @interface UITextView (RACSignalSupportUnavailable) - (RACSignal *)rac_signalForDelegateMethod:(SEL)method __attribute__((unavailable("Use -rac_signalForSelector:fromProtocol: instead"))); @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/UITextView+RACSignalSupport.m ================================================ // // UITextView+RACSignalSupport.m // ReactiveCocoa // // Created by Cody Krieger on 5/18/12. // Copyright (c) 2012 Cody Krieger. All rights reserved. // #import "UITextView+RACSignalSupport.h" #import #import "NSObject+RACDeallocating.h" #import "NSObject+RACDescription.h" #import "RACDelegateProxy.h" #import "RACSignal+Operations.h" #import "RACTuple.h" #import @implementation UITextView (RACSignalSupport) static void RACUseDelegateProxy(UITextView *self) { if (self.delegate == self.rac_delegateProxy) return; self.rac_delegateProxy.rac_proxiedDelegate = self.delegate; self.delegate = (id)self.rac_delegateProxy; } - (RACDelegateProxy *)rac_delegateProxy { RACDelegateProxy *proxy = objc_getAssociatedObject(self, _cmd); if (proxy == nil) { proxy = [[RACDelegateProxy alloc] initWithProtocol:@protocol(UITextViewDelegate)]; objc_setAssociatedObject(self, _cmd, proxy, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return proxy; } - (RACSignal *)rac_textSignal { @weakify(self); RACSignal *signal = [[[[[RACSignal defer:^{ @strongify(self); return [RACSignal return:RACTuplePack(self)]; }] concat:[self.rac_delegateProxy signalForSelector:@selector(textViewDidChange:)]] reduceEach:^(UITextView *x) { return x.text; }] takeUntil:self.rac_willDeallocSignal] setNameWithFormat:@"%@ -rac_textSignal", RACDescription(self)]; RACUseDelegateProxy(self); return signal; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/extobjc/EXTKeyPathCoding.h ================================================ // // EXTKeyPathCoding.h // extobjc // // Created by Justin Spahr-Summers on 19.06.12. // Copyright (C) 2012 Justin Spahr-Summers. // Released under the MIT license. // #import #import "metamacros.h" /** * \@keypath allows compile-time verification of key paths. Given a real object * receiver and key path: * * @code NSString *UTF8StringPath = @keypath(str.lowercaseString.UTF8String); // => @"lowercaseString.UTF8String" NSString *versionPath = @keypath(NSObject, version); // => @"version" NSString *lowercaseStringPath = @keypath(NSString.new, lowercaseString); // => @"lowercaseString" * @endcode * * ... the macro returns an \c NSString containing all but the first path * component or argument (e.g., @"lowercaseString.UTF8String", @"version"). * * In addition to simply creating a key path, this macro ensures that the key * path is valid at compile-time (causing a syntax error if not), and supports * refactoring, such that changing the name of the property will also update any * uses of \@keypath. */ #define keypath(...) \ metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__))(keypath1(__VA_ARGS__))(keypath2(__VA_ARGS__)) #define keypath1(PATH) \ (((void)(NO && ((void)PATH, NO)), strchr(# PATH, '.') + 1)) #define keypath2(OBJ, PATH) \ (((void)(NO && ((void)OBJ.PATH, NO)), # PATH)) /** * \@collectionKeypath allows compile-time verification of key paths across collections NSArray/NSSet etc. Given a real object * receiver, collection object receiver and related keypaths: * * @code NSString *employessFirstNamePath = @collectionKeypath(department.employees, Employee.new, firstName) // => @"employees.firstName" NSString *employessFirstNamePath = @collectionKeypath(Department.new, employees, Employee.new, firstName) // => @"employees.firstName" * @endcode * */ #define collectionKeypath(...) \ metamacro_if_eq(3, metamacro_argcount(__VA_ARGS__))(collectionKeypath3(__VA_ARGS__))(collectionKeypath4(__VA_ARGS__)) #define collectionKeypath3(PATH, COLLECTION_OBJECT, COLLECTION_PATH) ([[NSString stringWithFormat:@"%s.%s",keypath(PATH), keypath(COLLECTION_OBJECT, COLLECTION_PATH)] UTF8String]) #define collectionKeypath4(OBJ, PATH, COLLECTION_OBJECT, COLLECTION_PATH) ([[NSString stringWithFormat:@"%s.%s",keypath(OBJ, PATH), keypath(COLLECTION_OBJECT, COLLECTION_PATH)] UTF8String]) ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/extobjc/EXTRuntimeExtensions.h ================================================ // // EXTRuntimeExtensions.h // extobjc // // Created by Justin Spahr-Summers on 2011-03-05. // Copyright (C) 2012 Justin Spahr-Summers. // Released under the MIT license. // #import /** * Describes the memory management policy of a property. */ typedef enum { /** * The value is assigned. */ rac_propertyMemoryManagementPolicyAssign = 0, /** * The value is retained. */ rac_propertyMemoryManagementPolicyRetain, /** * The value is copied. */ rac_propertyMemoryManagementPolicyCopy } rac_propertyMemoryManagementPolicy; /** * Describes the attributes and type information of a property. */ typedef struct { /** * Whether this property was declared with the \c readonly attribute. */ BOOL readonly; /** * Whether this property was declared with the \c nonatomic attribute. */ BOOL nonatomic; /** * Whether the property is a weak reference. */ BOOL weak; /** * Whether the property is eligible for garbage collection. */ BOOL canBeCollected; /** * Whether this property is defined with \c \@dynamic. */ BOOL dynamic; /** * The memory management policy for this property. This will always be * #rac_propertyMemoryManagementPolicyAssign if #readonly is \c YES. */ rac_propertyMemoryManagementPolicy memoryManagementPolicy; /** * The selector for the getter of this property. This will reflect any * custom \c getter= attribute provided in the property declaration, or the * inferred getter name otherwise. */ SEL getter; /** * The selector for the setter of this property. This will reflect any * custom \c setter= attribute provided in the property declaration, or the * inferred setter name otherwise. * * @note If #readonly is \c YES, this value will represent what the setter * \e would be, if the property were writable. */ SEL setter; /** * The backing instance variable for this property, or \c NULL if \c * \c @synthesize was not used, and therefore no instance variable exists. This * would also be the case if the property is implemented dynamically. */ const char *ivar; /** * If this property is defined as being an instance of a specific class, * this will be the class object representing it. * * This will be \c nil if the property was defined as type \c id, if the * property is not of an object type, or if the class could not be found at * runtime. */ Class objectClass; /** * The type encoding for the value of this property. This is the type as it * would be returned by the \c \@encode() directive. */ char type[]; } rac_propertyAttributes; /** * Finds the instance method named \a aSelector on \a aClass and returns it, or * returns \c NULL if no such instance method exists. Unlike \c * class_getInstanceMethod(), this does not search superclasses. * * @note To get class methods in this manner, use a metaclass for \a aClass. */ Method rac_getImmediateInstanceMethod (Class aClass, SEL aSelector); /** * Returns a pointer to a structure containing information about \a property. * You must \c free() the returned pointer. Returns \c NULL if there is an error * obtaining information from \a property. */ rac_propertyAttributes *rac_copyPropertyAttributes (objc_property_t property); ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/extobjc/EXTRuntimeExtensions.m ================================================ // // EXTRuntimeExtensions.m // extobjc // // Created by Justin Spahr-Summers on 2011-03-05. // Copyright (C) 2012 Justin Spahr-Summers. // Released under the MIT license. // #import #import #import #import #import #import #import #import #import rac_propertyAttributes *rac_copyPropertyAttributes (objc_property_t property) { const char * const attrString = property_getAttributes(property); if (!attrString) { fprintf(stderr, "ERROR: Could not get attribute string from property %s\n", property_getName(property)); return NULL; } if (attrString[0] != 'T') { fprintf(stderr, "ERROR: Expected attribute string \"%s\" for property %s to start with 'T'\n", attrString, property_getName(property)); return NULL; } const char *typeString = attrString + 1; const char *next = NSGetSizeAndAlignment(typeString, NULL, NULL); if (!next) { fprintf(stderr, "ERROR: Could not read past type in attribute string \"%s\" for property %s\n", attrString, property_getName(property)); return NULL; } size_t typeLength = (size_t)(next - typeString); if (!typeLength) { fprintf(stderr, "ERROR: Invalid type in attribute string \"%s\" for property %s\n", attrString, property_getName(property)); return NULL; } // allocate enough space for the structure and the type string (plus a NUL) rac_propertyAttributes *attributes = calloc(1, sizeof(rac_propertyAttributes) + typeLength + 1); if (!attributes) { fprintf(stderr, "ERROR: Could not allocate rac_propertyAttributes structure for attribute string \"%s\" for property %s\n", attrString, property_getName(property)); return NULL; } // copy the type string strncpy(attributes->type, typeString, typeLength); attributes->type[typeLength] = '\0'; // if this is an object type, and immediately followed by a quoted string... if (typeString[0] == *(@encode(id)) && typeString[1] == '"') { // we should be able to extract a class name const char *className = typeString + 2; next = strchr(className, '"'); if (!next) { fprintf(stderr, "ERROR: Could not read class name in attribute string \"%s\" for property %s\n", attrString, property_getName(property)); return NULL; } if (className != next) { size_t classNameLength = (size_t)(next - className); char trimmedName[classNameLength + 1]; strncpy(trimmedName, className, classNameLength); trimmedName[classNameLength] = '\0'; // attempt to look up the class in the runtime attributes->objectClass = objc_getClass(trimmedName); } } if (*next != '\0') { // skip past any junk before the first flag next = strchr(next, ','); } while (next && *next == ',') { char flag = next[1]; next += 2; switch (flag) { case '\0': break; case 'R': attributes->readonly = YES; break; case 'C': attributes->memoryManagementPolicy = rac_propertyMemoryManagementPolicyCopy; break; case '&': attributes->memoryManagementPolicy = rac_propertyMemoryManagementPolicyRetain; break; case 'N': attributes->nonatomic = YES; break; case 'G': case 'S': { const char *nextFlag = strchr(next, ','); SEL name = NULL; if (!nextFlag) { // assume that the rest of the string is the selector const char *selectorString = next; next = ""; name = sel_registerName(selectorString); } else { size_t selectorLength = (size_t)(nextFlag - next); if (!selectorLength) { fprintf(stderr, "ERROR: Found zero length selector name in attribute string \"%s\" for property %s\n", attrString, property_getName(property)); goto errorOut; } char selectorString[selectorLength + 1]; strncpy(selectorString, next, selectorLength); selectorString[selectorLength] = '\0'; name = sel_registerName(selectorString); next = nextFlag; } if (flag == 'G') attributes->getter = name; else attributes->setter = name; } break; case 'D': attributes->dynamic = YES; attributes->ivar = NULL; break; case 'V': // assume that the rest of the string (if present) is the ivar name if (*next == '\0') { // if there's nothing there, let's assume this is dynamic attributes->ivar = NULL; } else { attributes->ivar = next; next = ""; } break; case 'W': attributes->weak = YES; break; case 'P': attributes->canBeCollected = YES; break; case 't': fprintf(stderr, "ERROR: Old-style type encoding is unsupported in attribute string \"%s\" for property %s\n", attrString, property_getName(property)); // skip over this type encoding while (*next != ',' && *next != '\0') ++next; break; default: fprintf(stderr, "ERROR: Unrecognized attribute string flag '%c' in attribute string \"%s\" for property %s\n", flag, attrString, property_getName(property)); } } if (next && *next != '\0') { fprintf(stderr, "Warning: Unparsed data \"%s\" in attribute string \"%s\" for property %s\n", next, attrString, property_getName(property)); } if (!attributes->getter) { // use the property name as the getter by default attributes->getter = sel_registerName(property_getName(property)); } if (!attributes->setter) { const char *propertyName = property_getName(property); size_t propertyNameLength = strlen(propertyName); // we want to transform the name to setProperty: style size_t setterLength = propertyNameLength + 4; char setterName[setterLength + 1]; strncpy(setterName, "set", 3); strncpy(setterName + 3, propertyName, propertyNameLength); // capitalize property name for the setter setterName[3] = (char)toupper(setterName[3]); setterName[setterLength - 1] = ':'; setterName[setterLength] = '\0'; attributes->setter = sel_registerName(setterName); } return attributes; errorOut: free(attributes); return NULL; } Method rac_getImmediateInstanceMethod (Class aClass, SEL aSelector) { unsigned methodCount = 0; Method *methods = class_copyMethodList(aClass, &methodCount); Method foundMethod = NULL; for (unsigned methodIndex = 0;methodIndex < methodCount;++methodIndex) { if (method_getName(methods[methodIndex]) == aSelector) { foundMethod = methods[methodIndex]; break; } } free(methods); return foundMethod; } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/extobjc/EXTScope.h ================================================ // // EXTScope.h // extobjc // // Created by Justin Spahr-Summers on 2011-05-04. // Copyright (C) 2012 Justin Spahr-Summers. // Released under the MIT license. // #import "metamacros.h" /** * \@onExit defines some code to be executed when the current scope exits. The * code must be enclosed in braces and terminated with a semicolon, and will be * executed regardless of how the scope is exited, including from exceptions, * \c goto, \c return, \c break, and \c continue. * * Provided code will go into a block to be executed later. Keep this in mind as * it pertains to memory management, restrictions on assignment, etc. Because * the code is used within a block, \c return is a legal (though perhaps * confusing) way to exit the cleanup block early. * * Multiple \@onExit statements in the same scope are executed in reverse * lexical order. This helps when pairing resource acquisition with \@onExit * statements, as it guarantees teardown in the opposite order of acquisition. * * @note This statement cannot be used within scopes defined without braces * (like a one line \c if). In practice, this is not an issue, since \@onExit is * a useless construct in such a case anyways. */ #define onExit \ rac_keywordify \ __strong rac_cleanupBlock_t metamacro_concat(rac_exitBlock_, __LINE__) __attribute__((cleanup(rac_executeCleanupBlock), unused)) = ^ /** * Creates \c __weak shadow variables for each of the variables provided as * arguments, which can later be made strong again with #strongify. * * This is typically used to weakly reference variables in a block, but then * ensure that the variables stay alive during the actual execution of the block * (if they were live upon entry). * * See #strongify for an example of usage. */ #define weakify(...) \ rac_keywordify \ metamacro_foreach_cxt(rac_weakify_,, __weak, __VA_ARGS__) /** * Like #weakify, but uses \c __unsafe_unretained instead, for targets or * classes that do not support weak references. */ #define unsafeify(...) \ rac_keywordify \ metamacro_foreach_cxt(rac_weakify_,, __unsafe_unretained, __VA_ARGS__) /** * Strongly references each of the variables provided as arguments, which must * have previously been passed to #weakify. * * The strong references created will shadow the original variable names, such * that the original names can be used without issue (and a significantly * reduced risk of retain cycles) in the current scope. * * @code id foo = [[NSObject alloc] init]; id bar = [[NSObject alloc] init]; @weakify(foo, bar); // this block will not keep 'foo' or 'bar' alive BOOL (^matchesFooOrBar)(id) = ^ BOOL (id obj){ // but now, upon entry, 'foo' and 'bar' will stay alive until the block has // finished executing @strongify(foo, bar); return [foo isEqual:obj] || [bar isEqual:obj]; }; * @endcode */ #define strongify(...) \ rac_keywordify \ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wshadow\"") \ metamacro_foreach(rac_strongify_,, __VA_ARGS__) \ _Pragma("clang diagnostic pop") /*** implementation details follow ***/ typedef void (^rac_cleanupBlock_t)(); static inline void rac_executeCleanupBlock (__strong rac_cleanupBlock_t *block) { (*block)(); } #define rac_weakify_(INDEX, CONTEXT, VAR) \ CONTEXT __typeof__(VAR) metamacro_concat(VAR, _weak_) = (VAR); #define rac_strongify_(INDEX, VAR) \ __strong __typeof__(VAR) VAR = metamacro_concat(VAR, _weak_); // Details about the choice of backing keyword: // // The use of @try/@catch/@finally can cause the compiler to suppress // return-type warnings. // The use of @autoreleasepool {} is not optimized away by the compiler, // resulting in superfluous creation of autorelease pools. // // Since neither option is perfect, and with no other alternatives, the // compromise is to use @autorelease in DEBUG builds to maintain compiler // analysis, and to use @try/@catch otherwise to avoid insertion of unnecessary // autorelease pools. #if DEBUG #define rac_keywordify autoreleasepool {} #else #define rac_keywordify try {} @catch (...) {} #endif ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Objective-C/extobjc/metamacros.h ================================================ /** * Macros for metaprogramming * ExtendedC * * Copyright (C) 2012 Justin Spahr-Summers * Released under the MIT license */ #ifndef EXTC_METAMACROS_H #define EXTC_METAMACROS_H /** * Executes one or more expressions (which may have a void type, such as a call * to a function that returns no value) and always returns true. */ #define metamacro_exprify(...) \ ((__VA_ARGS__), true) /** * Returns a string representation of VALUE after full macro expansion. */ #define metamacro_stringify(VALUE) \ metamacro_stringify_(VALUE) /** * Returns A and B concatenated after full macro expansion. */ #define metamacro_concat(A, B) \ metamacro_concat_(A, B) /** * Returns the Nth variadic argument (starting from zero). At least * N + 1 variadic arguments must be given. N must be between zero and twenty, * inclusive. */ #define metamacro_at(N, ...) \ metamacro_concat(metamacro_at, N)(__VA_ARGS__) /** * Returns the number of arguments (up to twenty) provided to the macro. At * least one argument must be provided. * * Inspired by P99: http://p99.gforge.inria.fr */ #define metamacro_argcount(...) \ metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) /** * Identical to #metamacro_foreach_cxt, except that no CONTEXT argument is * given. Only the index and current argument will thus be passed to MACRO. */ #define metamacro_foreach(MACRO, SEP, ...) \ metamacro_foreach_cxt(metamacro_foreach_iter, SEP, MACRO, __VA_ARGS__) /** * For each consecutive variadic argument (up to twenty), MACRO is passed the * zero-based index of the current argument, CONTEXT, and then the argument * itself. The results of adjoining invocations of MACRO are then separated by * SEP. * * Inspired by P99: http://p99.gforge.inria.fr */ #define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \ metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__) /** * Identical to #metamacro_foreach_cxt. This can be used when the former would * fail due to recursive macro expansion. */ #define metamacro_foreach_cxt_recursive(MACRO, SEP, CONTEXT, ...) \ metamacro_concat(metamacro_foreach_cxt_recursive, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__) /** * In consecutive order, appends each variadic argument (up to twenty) onto * BASE. The resulting concatenations are then separated by SEP. * * This is primarily useful to manipulate a list of macro invocations into instead * invoking a different, possibly related macro. */ #define metamacro_foreach_concat(BASE, SEP, ...) \ metamacro_foreach_cxt(metamacro_foreach_concat_iter, SEP, BASE, __VA_ARGS__) /** * Iterates COUNT times, each time invoking MACRO with the current index * (starting at zero) and CONTEXT. The results of adjoining invocations of MACRO * are then separated by SEP. * * COUNT must be an integer between zero and twenty, inclusive. */ #define metamacro_for_cxt(COUNT, MACRO, SEP, CONTEXT) \ metamacro_concat(metamacro_for_cxt, COUNT)(MACRO, SEP, CONTEXT) /** * Returns the first argument given. At least one argument must be provided. * * This is useful when implementing a variadic macro, where you may have only * one variadic argument, but no way to retrieve it (for example, because \c ... * always needs to match at least one argument). * * @code #define varmacro(...) \ metamacro_head(__VA_ARGS__) * @endcode */ #define metamacro_head(...) \ metamacro_head_(__VA_ARGS__, 0) /** * Returns every argument except the first. At least two arguments must be * provided. */ #define metamacro_tail(...) \ metamacro_tail_(__VA_ARGS__) /** * Returns the first N (up to twenty) variadic arguments as a new argument list. * At least N variadic arguments must be provided. */ #define metamacro_take(N, ...) \ metamacro_concat(metamacro_take, N)(__VA_ARGS__) /** * Removes the first N (up to twenty) variadic arguments from the given argument * list. At least N variadic arguments must be provided. */ #define metamacro_drop(N, ...) \ metamacro_concat(metamacro_drop, N)(__VA_ARGS__) /** * Decrements VAL, which must be a number between zero and twenty, inclusive. * * This is primarily useful when dealing with indexes and counts in * metaprogramming. */ #define metamacro_dec(VAL) \ metamacro_at(VAL, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19) /** * Increments VAL, which must be a number between zero and twenty, inclusive. * * This is primarily useful when dealing with indexes and counts in * metaprogramming. */ #define metamacro_inc(VAL) \ metamacro_at(VAL, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21) /** * If A is equal to B, the next argument list is expanded; otherwise, the * argument list after that is expanded. A and B must be numbers between zero * and twenty, inclusive. Additionally, B must be greater than or equal to A. * * @code // expands to true metamacro_if_eq(0, 0)(true)(false) // expands to false metamacro_if_eq(0, 1)(true)(false) * @endcode * * This is primarily useful when dealing with indexes and counts in * metaprogramming. */ #define metamacro_if_eq(A, B) \ metamacro_concat(metamacro_if_eq, A)(B) /** * Identical to #metamacro_if_eq. This can be used when the former would fail * due to recursive macro expansion. */ #define metamacro_if_eq_recursive(A, B) \ metamacro_concat(metamacro_if_eq_recursive, A)(B) /** * Returns 1 if N is an even number, or 0 otherwise. N must be between zero and * twenty, inclusive. * * For the purposes of this test, zero is considered even. */ #define metamacro_is_even(N) \ metamacro_at(N, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1) /** * Returns the logical NOT of B, which must be the number zero or one. */ #define metamacro_not(B) \ metamacro_at(B, 1, 0) // IMPLEMENTATION DETAILS FOLLOW! // Do not write code that depends on anything below this line. #define metamacro_stringify_(VALUE) # VALUE #define metamacro_concat_(A, B) A ## B #define metamacro_foreach_iter(INDEX, MACRO, ARG) MACRO(INDEX, ARG) #define metamacro_head_(FIRST, ...) FIRST #define metamacro_tail_(FIRST, ...) __VA_ARGS__ #define metamacro_consume_(...) #define metamacro_expand_(...) __VA_ARGS__ // implemented from scratch so that metamacro_concat() doesn't end up nesting #define metamacro_foreach_concat_iter(INDEX, BASE, ARG) metamacro_foreach_concat_iter_(BASE, ARG) #define metamacro_foreach_concat_iter_(BASE, ARG) BASE ## ARG // metamacro_at expansions #define metamacro_at0(...) metamacro_head(__VA_ARGS__) #define metamacro_at1(_0, ...) metamacro_head(__VA_ARGS__) #define metamacro_at2(_0, _1, ...) metamacro_head(__VA_ARGS__) #define metamacro_at3(_0, _1, _2, ...) metamacro_head(__VA_ARGS__) #define metamacro_at4(_0, _1, _2, _3, ...) metamacro_head(__VA_ARGS__) #define metamacro_at5(_0, _1, _2, _3, _4, ...) metamacro_head(__VA_ARGS__) #define metamacro_at6(_0, _1, _2, _3, _4, _5, ...) metamacro_head(__VA_ARGS__) #define metamacro_at7(_0, _1, _2, _3, _4, _5, _6, ...) metamacro_head(__VA_ARGS__) #define metamacro_at8(_0, _1, _2, _3, _4, _5, _6, _7, ...) metamacro_head(__VA_ARGS__) #define metamacro_at9(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) metamacro_head(__VA_ARGS__) #define metamacro_at10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) metamacro_head(__VA_ARGS__) #define metamacro_at11(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) metamacro_head(__VA_ARGS__) #define metamacro_at12(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, ...) metamacro_head(__VA_ARGS__) #define metamacro_at13(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) metamacro_head(__VA_ARGS__) #define metamacro_at14(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) metamacro_head(__VA_ARGS__) #define metamacro_at15(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) metamacro_head(__VA_ARGS__) #define metamacro_at16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) metamacro_head(__VA_ARGS__) #define metamacro_at17(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) metamacro_head(__VA_ARGS__) #define metamacro_at18(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, ...) metamacro_head(__VA_ARGS__) #define metamacro_at19(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, ...) metamacro_head(__VA_ARGS__) #define metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) metamacro_head(__VA_ARGS__) // metamacro_foreach_cxt expansions #define metamacro_foreach_cxt0(MACRO, SEP, CONTEXT) #define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0) #define metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \ metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) \ SEP \ MACRO(1, CONTEXT, _1) #define metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \ metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \ SEP \ MACRO(2, CONTEXT, _2) #define metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \ SEP \ MACRO(3, CONTEXT, _3) #define metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ SEP \ MACRO(4, CONTEXT, _4) #define metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ SEP \ MACRO(5, CONTEXT, _5) #define metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ SEP \ MACRO(6, CONTEXT, _6) #define metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ SEP \ MACRO(7, CONTEXT, _7) #define metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ SEP \ MACRO(8, CONTEXT, _8) #define metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ SEP \ MACRO(9, CONTEXT, _9) #define metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ SEP \ MACRO(10, CONTEXT, _10) #define metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ SEP \ MACRO(11, CONTEXT, _11) #define metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ SEP \ MACRO(12, CONTEXT, _12) #define metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ SEP \ MACRO(13, CONTEXT, _13) #define metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ SEP \ MACRO(14, CONTEXT, _14) #define metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ SEP \ MACRO(15, CONTEXT, _15) #define metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ SEP \ MACRO(16, CONTEXT, _16) #define metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ SEP \ MACRO(17, CONTEXT, _17) #define metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ SEP \ MACRO(18, CONTEXT, _18) #define metamacro_foreach_cxt20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \ metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ SEP \ MACRO(19, CONTEXT, _19) // metamacro_foreach_cxt_recursive expansions #define metamacro_foreach_cxt_recursive0(MACRO, SEP, CONTEXT) #define metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0) #define metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \ metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) \ SEP \ MACRO(1, CONTEXT, _1) #define metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) \ metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \ SEP \ MACRO(2, CONTEXT, _2) #define metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) \ SEP \ MACRO(3, CONTEXT, _3) #define metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \ SEP \ MACRO(4, CONTEXT, _4) #define metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \ SEP \ MACRO(5, CONTEXT, _5) #define metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \ SEP \ MACRO(6, CONTEXT, _6) #define metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \ SEP \ MACRO(7, CONTEXT, _7) #define metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \ SEP \ MACRO(8, CONTEXT, _8) #define metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \ SEP \ MACRO(9, CONTEXT, _9) #define metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \ SEP \ MACRO(10, CONTEXT, _10) #define metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \ SEP \ MACRO(11, CONTEXT, _11) #define metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \ SEP \ MACRO(12, CONTEXT, _12) #define metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \ SEP \ MACRO(13, CONTEXT, _13) #define metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \ SEP \ MACRO(14, CONTEXT, _14) #define metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \ SEP \ MACRO(15, CONTEXT, _15) #define metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \ SEP \ MACRO(16, CONTEXT, _16) #define metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) \ SEP \ MACRO(17, CONTEXT, _17) #define metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) \ SEP \ MACRO(18, CONTEXT, _18) #define metamacro_foreach_cxt_recursive20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) \ metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) \ SEP \ MACRO(19, CONTEXT, _19) // metamacro_for_cxt expansions #define metamacro_for_cxt0(MACRO, SEP, CONTEXT) #define metamacro_for_cxt1(MACRO, SEP, CONTEXT) MACRO(0, CONTEXT) #define metamacro_for_cxt2(MACRO, SEP, CONTEXT) \ metamacro_for_cxt1(MACRO, SEP, CONTEXT) \ SEP \ MACRO(1, CONTEXT) #define metamacro_for_cxt3(MACRO, SEP, CONTEXT) \ metamacro_for_cxt2(MACRO, SEP, CONTEXT) \ SEP \ MACRO(2, CONTEXT) #define metamacro_for_cxt4(MACRO, SEP, CONTEXT) \ metamacro_for_cxt3(MACRO, SEP, CONTEXT) \ SEP \ MACRO(3, CONTEXT) #define metamacro_for_cxt5(MACRO, SEP, CONTEXT) \ metamacro_for_cxt4(MACRO, SEP, CONTEXT) \ SEP \ MACRO(4, CONTEXT) #define metamacro_for_cxt6(MACRO, SEP, CONTEXT) \ metamacro_for_cxt5(MACRO, SEP, CONTEXT) \ SEP \ MACRO(5, CONTEXT) #define metamacro_for_cxt7(MACRO, SEP, CONTEXT) \ metamacro_for_cxt6(MACRO, SEP, CONTEXT) \ SEP \ MACRO(6, CONTEXT) #define metamacro_for_cxt8(MACRO, SEP, CONTEXT) \ metamacro_for_cxt7(MACRO, SEP, CONTEXT) \ SEP \ MACRO(7, CONTEXT) #define metamacro_for_cxt9(MACRO, SEP, CONTEXT) \ metamacro_for_cxt8(MACRO, SEP, CONTEXT) \ SEP \ MACRO(8, CONTEXT) #define metamacro_for_cxt10(MACRO, SEP, CONTEXT) \ metamacro_for_cxt9(MACRO, SEP, CONTEXT) \ SEP \ MACRO(9, CONTEXT) #define metamacro_for_cxt11(MACRO, SEP, CONTEXT) \ metamacro_for_cxt10(MACRO, SEP, CONTEXT) \ SEP \ MACRO(10, CONTEXT) #define metamacro_for_cxt12(MACRO, SEP, CONTEXT) \ metamacro_for_cxt11(MACRO, SEP, CONTEXT) \ SEP \ MACRO(11, CONTEXT) #define metamacro_for_cxt13(MACRO, SEP, CONTEXT) \ metamacro_for_cxt12(MACRO, SEP, CONTEXT) \ SEP \ MACRO(12, CONTEXT) #define metamacro_for_cxt14(MACRO, SEP, CONTEXT) \ metamacro_for_cxt13(MACRO, SEP, CONTEXT) \ SEP \ MACRO(13, CONTEXT) #define metamacro_for_cxt15(MACRO, SEP, CONTEXT) \ metamacro_for_cxt14(MACRO, SEP, CONTEXT) \ SEP \ MACRO(14, CONTEXT) #define metamacro_for_cxt16(MACRO, SEP, CONTEXT) \ metamacro_for_cxt15(MACRO, SEP, CONTEXT) \ SEP \ MACRO(15, CONTEXT) #define metamacro_for_cxt17(MACRO, SEP, CONTEXT) \ metamacro_for_cxt16(MACRO, SEP, CONTEXT) \ SEP \ MACRO(16, CONTEXT) #define metamacro_for_cxt18(MACRO, SEP, CONTEXT) \ metamacro_for_cxt17(MACRO, SEP, CONTEXT) \ SEP \ MACRO(17, CONTEXT) #define metamacro_for_cxt19(MACRO, SEP, CONTEXT) \ metamacro_for_cxt18(MACRO, SEP, CONTEXT) \ SEP \ MACRO(18, CONTEXT) #define metamacro_for_cxt20(MACRO, SEP, CONTEXT) \ metamacro_for_cxt19(MACRO, SEP, CONTEXT) \ SEP \ MACRO(19, CONTEXT) // metamacro_if_eq expansions #define metamacro_if_eq0(VALUE) \ metamacro_concat(metamacro_if_eq0_, VALUE) #define metamacro_if_eq0_0(...) __VA_ARGS__ metamacro_consume_ #define metamacro_if_eq0_1(...) metamacro_expand_ #define metamacro_if_eq0_2(...) metamacro_expand_ #define metamacro_if_eq0_3(...) metamacro_expand_ #define metamacro_if_eq0_4(...) metamacro_expand_ #define metamacro_if_eq0_5(...) metamacro_expand_ #define metamacro_if_eq0_6(...) metamacro_expand_ #define metamacro_if_eq0_7(...) metamacro_expand_ #define metamacro_if_eq0_8(...) metamacro_expand_ #define metamacro_if_eq0_9(...) metamacro_expand_ #define metamacro_if_eq0_10(...) metamacro_expand_ #define metamacro_if_eq0_11(...) metamacro_expand_ #define metamacro_if_eq0_12(...) metamacro_expand_ #define metamacro_if_eq0_13(...) metamacro_expand_ #define metamacro_if_eq0_14(...) metamacro_expand_ #define metamacro_if_eq0_15(...) metamacro_expand_ #define metamacro_if_eq0_16(...) metamacro_expand_ #define metamacro_if_eq0_17(...) metamacro_expand_ #define metamacro_if_eq0_18(...) metamacro_expand_ #define metamacro_if_eq0_19(...) metamacro_expand_ #define metamacro_if_eq0_20(...) metamacro_expand_ #define metamacro_if_eq1(VALUE) metamacro_if_eq0(metamacro_dec(VALUE)) #define metamacro_if_eq2(VALUE) metamacro_if_eq1(metamacro_dec(VALUE)) #define metamacro_if_eq3(VALUE) metamacro_if_eq2(metamacro_dec(VALUE)) #define metamacro_if_eq4(VALUE) metamacro_if_eq3(metamacro_dec(VALUE)) #define metamacro_if_eq5(VALUE) metamacro_if_eq4(metamacro_dec(VALUE)) #define metamacro_if_eq6(VALUE) metamacro_if_eq5(metamacro_dec(VALUE)) #define metamacro_if_eq7(VALUE) metamacro_if_eq6(metamacro_dec(VALUE)) #define metamacro_if_eq8(VALUE) metamacro_if_eq7(metamacro_dec(VALUE)) #define metamacro_if_eq9(VALUE) metamacro_if_eq8(metamacro_dec(VALUE)) #define metamacro_if_eq10(VALUE) metamacro_if_eq9(metamacro_dec(VALUE)) #define metamacro_if_eq11(VALUE) metamacro_if_eq10(metamacro_dec(VALUE)) #define metamacro_if_eq12(VALUE) metamacro_if_eq11(metamacro_dec(VALUE)) #define metamacro_if_eq13(VALUE) metamacro_if_eq12(metamacro_dec(VALUE)) #define metamacro_if_eq14(VALUE) metamacro_if_eq13(metamacro_dec(VALUE)) #define metamacro_if_eq15(VALUE) metamacro_if_eq14(metamacro_dec(VALUE)) #define metamacro_if_eq16(VALUE) metamacro_if_eq15(metamacro_dec(VALUE)) #define metamacro_if_eq17(VALUE) metamacro_if_eq16(metamacro_dec(VALUE)) #define metamacro_if_eq18(VALUE) metamacro_if_eq17(metamacro_dec(VALUE)) #define metamacro_if_eq19(VALUE) metamacro_if_eq18(metamacro_dec(VALUE)) #define metamacro_if_eq20(VALUE) metamacro_if_eq19(metamacro_dec(VALUE)) // metamacro_if_eq_recursive expansions #define metamacro_if_eq_recursive0(VALUE) \ metamacro_concat(metamacro_if_eq_recursive0_, VALUE) #define metamacro_if_eq_recursive0_0(...) __VA_ARGS__ metamacro_consume_ #define metamacro_if_eq_recursive0_1(...) metamacro_expand_ #define metamacro_if_eq_recursive0_2(...) metamacro_expand_ #define metamacro_if_eq_recursive0_3(...) metamacro_expand_ #define metamacro_if_eq_recursive0_4(...) metamacro_expand_ #define metamacro_if_eq_recursive0_5(...) metamacro_expand_ #define metamacro_if_eq_recursive0_6(...) metamacro_expand_ #define metamacro_if_eq_recursive0_7(...) metamacro_expand_ #define metamacro_if_eq_recursive0_8(...) metamacro_expand_ #define metamacro_if_eq_recursive0_9(...) metamacro_expand_ #define metamacro_if_eq_recursive0_10(...) metamacro_expand_ #define metamacro_if_eq_recursive0_11(...) metamacro_expand_ #define metamacro_if_eq_recursive0_12(...) metamacro_expand_ #define metamacro_if_eq_recursive0_13(...) metamacro_expand_ #define metamacro_if_eq_recursive0_14(...) metamacro_expand_ #define metamacro_if_eq_recursive0_15(...) metamacro_expand_ #define metamacro_if_eq_recursive0_16(...) metamacro_expand_ #define metamacro_if_eq_recursive0_17(...) metamacro_expand_ #define metamacro_if_eq_recursive0_18(...) metamacro_expand_ #define metamacro_if_eq_recursive0_19(...) metamacro_expand_ #define metamacro_if_eq_recursive0_20(...) metamacro_expand_ #define metamacro_if_eq_recursive1(VALUE) metamacro_if_eq_recursive0(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive2(VALUE) metamacro_if_eq_recursive1(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive3(VALUE) metamacro_if_eq_recursive2(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive4(VALUE) metamacro_if_eq_recursive3(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive5(VALUE) metamacro_if_eq_recursive4(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive6(VALUE) metamacro_if_eq_recursive5(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive7(VALUE) metamacro_if_eq_recursive6(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive8(VALUE) metamacro_if_eq_recursive7(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive9(VALUE) metamacro_if_eq_recursive8(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive10(VALUE) metamacro_if_eq_recursive9(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive11(VALUE) metamacro_if_eq_recursive10(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive12(VALUE) metamacro_if_eq_recursive11(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive13(VALUE) metamacro_if_eq_recursive12(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive14(VALUE) metamacro_if_eq_recursive13(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive15(VALUE) metamacro_if_eq_recursive14(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive16(VALUE) metamacro_if_eq_recursive15(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive17(VALUE) metamacro_if_eq_recursive16(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive18(VALUE) metamacro_if_eq_recursive17(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive19(VALUE) metamacro_if_eq_recursive18(metamacro_dec(VALUE)) #define metamacro_if_eq_recursive20(VALUE) metamacro_if_eq_recursive19(metamacro_dec(VALUE)) // metamacro_take expansions #define metamacro_take0(...) #define metamacro_take1(...) metamacro_head(__VA_ARGS__) #define metamacro_take2(...) metamacro_head(__VA_ARGS__), metamacro_take1(metamacro_tail(__VA_ARGS__)) #define metamacro_take3(...) metamacro_head(__VA_ARGS__), metamacro_take2(metamacro_tail(__VA_ARGS__)) #define metamacro_take4(...) metamacro_head(__VA_ARGS__), metamacro_take3(metamacro_tail(__VA_ARGS__)) #define metamacro_take5(...) metamacro_head(__VA_ARGS__), metamacro_take4(metamacro_tail(__VA_ARGS__)) #define metamacro_take6(...) metamacro_head(__VA_ARGS__), metamacro_take5(metamacro_tail(__VA_ARGS__)) #define metamacro_take7(...) metamacro_head(__VA_ARGS__), metamacro_take6(metamacro_tail(__VA_ARGS__)) #define metamacro_take8(...) metamacro_head(__VA_ARGS__), metamacro_take7(metamacro_tail(__VA_ARGS__)) #define metamacro_take9(...) metamacro_head(__VA_ARGS__), metamacro_take8(metamacro_tail(__VA_ARGS__)) #define metamacro_take10(...) metamacro_head(__VA_ARGS__), metamacro_take9(metamacro_tail(__VA_ARGS__)) #define metamacro_take11(...) metamacro_head(__VA_ARGS__), metamacro_take10(metamacro_tail(__VA_ARGS__)) #define metamacro_take12(...) metamacro_head(__VA_ARGS__), metamacro_take11(metamacro_tail(__VA_ARGS__)) #define metamacro_take13(...) metamacro_head(__VA_ARGS__), metamacro_take12(metamacro_tail(__VA_ARGS__)) #define metamacro_take14(...) metamacro_head(__VA_ARGS__), metamacro_take13(metamacro_tail(__VA_ARGS__)) #define metamacro_take15(...) metamacro_head(__VA_ARGS__), metamacro_take14(metamacro_tail(__VA_ARGS__)) #define metamacro_take16(...) metamacro_head(__VA_ARGS__), metamacro_take15(metamacro_tail(__VA_ARGS__)) #define metamacro_take17(...) metamacro_head(__VA_ARGS__), metamacro_take16(metamacro_tail(__VA_ARGS__)) #define metamacro_take18(...) metamacro_head(__VA_ARGS__), metamacro_take17(metamacro_tail(__VA_ARGS__)) #define metamacro_take19(...) metamacro_head(__VA_ARGS__), metamacro_take18(metamacro_tail(__VA_ARGS__)) #define metamacro_take20(...) metamacro_head(__VA_ARGS__), metamacro_take19(metamacro_tail(__VA_ARGS__)) // metamacro_drop expansions #define metamacro_drop0(...) __VA_ARGS__ #define metamacro_drop1(...) metamacro_tail(__VA_ARGS__) #define metamacro_drop2(...) metamacro_drop1(metamacro_tail(__VA_ARGS__)) #define metamacro_drop3(...) metamacro_drop2(metamacro_tail(__VA_ARGS__)) #define metamacro_drop4(...) metamacro_drop3(metamacro_tail(__VA_ARGS__)) #define metamacro_drop5(...) metamacro_drop4(metamacro_tail(__VA_ARGS__)) #define metamacro_drop6(...) metamacro_drop5(metamacro_tail(__VA_ARGS__)) #define metamacro_drop7(...) metamacro_drop6(metamacro_tail(__VA_ARGS__)) #define metamacro_drop8(...) metamacro_drop7(metamacro_tail(__VA_ARGS__)) #define metamacro_drop9(...) metamacro_drop8(metamacro_tail(__VA_ARGS__)) #define metamacro_drop10(...) metamacro_drop9(metamacro_tail(__VA_ARGS__)) #define metamacro_drop11(...) metamacro_drop10(metamacro_tail(__VA_ARGS__)) #define metamacro_drop12(...) metamacro_drop11(metamacro_tail(__VA_ARGS__)) #define metamacro_drop13(...) metamacro_drop12(metamacro_tail(__VA_ARGS__)) #define metamacro_drop14(...) metamacro_drop13(metamacro_tail(__VA_ARGS__)) #define metamacro_drop15(...) metamacro_drop14(metamacro_tail(__VA_ARGS__)) #define metamacro_drop16(...) metamacro_drop15(metamacro_tail(__VA_ARGS__)) #define metamacro_drop17(...) metamacro_drop16(metamacro_tail(__VA_ARGS__)) #define metamacro_drop18(...) metamacro_drop17(metamacro_tail(__VA_ARGS__)) #define metamacro_drop19(...) metamacro_drop18(metamacro_tail(__VA_ARGS__)) #define metamacro_drop20(...) metamacro_drop19(metamacro_tail(__VA_ARGS__)) #endif ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/ReactiveCocoa.h ================================================ // // ReactiveCocoa.h // ReactiveCocoa // // Created by Josh Abernathy on 3/5/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import //! Project version number for ReactiveCocoa. FOUNDATION_EXPORT double ReactiveCocoaVersionNumber; //! Project version string for ReactiveCocoa. FOUNDATION_EXPORT const unsigned char ReactiveCocoaVersionString[]; #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #import #if TARGET_OS_WATCH #elif TARGET_OS_IOS || TARGET_OS_TV #import #import #import #import #import #import #import #import #import #if TARGET_OS_IOS #import #import #import #import #import #import #import #import #import #import #import #endif #elif TARGET_OS_MAC #import #import #import #import #import #endif ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Swift/Action.swift ================================================ import Foundation import enum Result.NoError /// Represents an action that will do some work when executed with a value of /// type `Input`, then return zero or more values of type `Output` and/or fail /// with an error of type `Error`. If no failure should be possible, NoError can /// be specified for the `Error` parameter. /// /// Actions enforce serial execution. Any attempt to execute an action multiple /// times concurrently will return an error. public final class Action { private let executeClosure: Input -> SignalProducer private let eventsObserver: Signal, NoError>.Observer /// A signal of all events generated from applications of the Action. /// /// In other words, this will send every `Event` from every signal generated /// by each SignalProducer returned from apply(). public let events: Signal, NoError> /// A signal of all values generated from applications of the Action. /// /// In other words, this will send every value from every signal generated /// by each SignalProducer returned from apply(). public let values: Signal /// A signal of all errors generated from applications of the Action. /// /// In other words, this will send errors from every signal generated by /// each SignalProducer returned from apply(). public let errors: Signal /// Whether the action is currently executing. public var executing: AnyProperty { return AnyProperty(_executing) } private let _executing: MutableProperty = MutableProperty(false) /// Whether the action is currently enabled. public var enabled: AnyProperty { return AnyProperty(_enabled) } private let _enabled: MutableProperty = MutableProperty(false) /// Whether the instantiator of this action wants it to be enabled. private let userEnabled: AnyProperty /// Lazy creation and storage of a UI bindable `CocoaAction`. The default behavior /// force casts the AnyObject? input to match the action's `Input` type. This makes /// it unsafe for use when the action is parameterized for something like `Void` /// input. In those cases, explicitly assign a value to this property that transforms /// the input to suit your needs. public lazy var unsafeCocoaAction: CocoaAction = CocoaAction(self) { $0 as! Input } /// This queue is used for read-modify-write operations on the `_executing` /// property. private let executingQueue = dispatch_queue_create("org.reactivecocoa.ReactiveCocoa.Action.executingQueue", DISPATCH_QUEUE_SERIAL) /// Whether the action should be enabled for the given combination of user /// enabledness and executing status. private static func shouldBeEnabled(userEnabled userEnabled: Bool, executing: Bool) -> Bool { return userEnabled && !executing } /// Initializes an action that will be conditionally enabled, and create a /// SignalProducer for each input. public init(enabledIf: P, _ execute: Input -> SignalProducer) { executeClosure = execute userEnabled = AnyProperty(enabledIf) (events, eventsObserver) = Signal, NoError>.pipe() values = events.map { $0.value }.ignoreNil() errors = events.map { $0.error }.ignoreNil() _enabled <~ enabledIf.producer .combineLatestWith(executing.producer) .map(Action.shouldBeEnabled) } /// Initializes an action that will be enabled by default, and create a /// SignalProducer for each input. public convenience init(_ execute: Input -> SignalProducer) { self.init(enabledIf: ConstantProperty(true), execute) } deinit { eventsObserver.sendCompleted() } /// Creates a SignalProducer that, when started, will execute the action /// with the given input, then forward the results upon the produced Signal. /// /// If the action is disabled when the returned SignalProducer is started, /// the produced signal will send `ActionError.NotEnabled`, and nothing will /// be sent upon `values` or `errors` for that particular signal. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func apply(input: Input) -> SignalProducer> { return SignalProducer { observer, disposable in var startedExecuting = false dispatch_sync(self.executingQueue) { if self._enabled.value { self._executing.value = true startedExecuting = true } } if !startedExecuting { observer.sendFailed(.NotEnabled) return } self.executeClosure(input).startWithSignal { signal, signalDisposable in disposable.addDisposable(signalDisposable) signal.observe { event in observer.action(event.mapError { .ProducerError($0) }) self.eventsObserver.sendNext(event) } } disposable.addDisposable { self._executing.value = false } } } } /// Wraps an Action for use by a GUI control (such as `NSControl` or /// `UIControl`), with KVO, or with Cocoa Bindings. public final class CocoaAction: NSObject { /// The selector that a caller should invoke upon a CocoaAction in order to /// execute it. public static let selector: Selector = "execute:" /// Whether the action is enabled. /// /// This property will only change on the main thread, and will generate a /// KVO notification for every change. public var enabled: Bool { return _enabled } /// Whether the action is executing. /// /// This property will only change on the main thread, and will generate a /// KVO notification for every change. public var executing: Bool { return _executing } private var _enabled = false private var _executing = false private let _execute: AnyObject? -> () private let disposable = CompositeDisposable() /// Initializes a Cocoa action that will invoke the given Action by /// transforming the object given to execute(). public init(_ action: Action, _ inputTransform: AnyObject? -> Input) { _execute = { input in let producer = action.apply(inputTransform(input)) producer.start() } super.init() disposable += action.enabled.producer .observeOn(UIScheduler()) .startWithNext { [weak self] value in self?.willChangeValueForKey("enabled") self?._enabled = value self?.didChangeValueForKey("enabled") } disposable += action.executing.producer .observeOn(UIScheduler()) .startWithNext { [weak self] value in self?.willChangeValueForKey("executing") self?._executing = value self?.didChangeValueForKey("executing") } } /// Initializes a Cocoa action that will invoke the given Action by /// always providing the given input. public convenience init(_ action: Action, input: Input) { self.init(action, { _ in input }) } deinit { disposable.dispose() } /// Attempts to execute the underlying action with the given input, subject /// to the behavior described by the initializer that was used. @IBAction public func execute(input: AnyObject?) { _execute(input) } public override class func automaticallyNotifiesObserversForKey(key: String) -> Bool { return false } } /// The type of error that can occur from Action.apply, where `Error` is the type of /// error that can be generated by the specific Action instance. public enum ActionError: ErrorType { /// The producer returned from apply() was started while the Action was /// disabled. case NotEnabled /// The producer returned from apply() sent the given error. case ProducerError(Error) } public func == (lhs: ActionError, rhs: ActionError) -> Bool { switch (lhs, rhs) { case (.NotEnabled, .NotEnabled): return true case let (.ProducerError(left), .ProducerError(right)): return left == right default: return false } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Swift/Atomic.swift ================================================ // // Atomic.swift // ReactiveCocoa // // Created by Justin Spahr-Summers on 2014-06-10. // Copyright (c) 2014 GitHub. All rights reserved. // import Foundation /// An atomic variable. public final class Atomic { private var spinLock = OS_SPINLOCK_INIT private var _value: Value /// Atomically gets or sets the value of the variable. public var value: Value { get { return withValue { $0 } } set(newValue) { modify { _ in newValue } } } /// Initializes the variable with the given initial value. public init(_ value: Value) { _value = value } private func lock() { OSSpinLockLock(&spinLock) } private func unlock() { OSSpinLockUnlock(&spinLock) } /// Atomically replaces the contents of the variable. /// /// Returns the old value. public func swap(newValue: Value) -> Value { return modify { _ in newValue } } /// Atomically modifies the variable. /// /// Returns the old value. public func modify(@noescape action: (Value) throws -> Value) rethrows -> Value { lock() defer { unlock() } let oldValue = _value _value = try action(_value) return oldValue } /// Atomically performs an arbitrary action using the current value of the /// variable. /// /// Returns the result of the action. public func withValue(@noescape action: (Value) throws -> Result) rethrows -> Result { lock() defer { unlock() } return try action(_value) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Swift/Bag.swift ================================================ // // Bag.swift // ReactiveCocoa // // Created by Justin Spahr-Summers on 2014-07-10. // Copyright (c) 2014 GitHub. All rights reserved. // /// A uniquely identifying token for removing a value that was inserted into a /// Bag. public final class RemovalToken { private var identifier: UInt? private init(identifier: UInt) { self.identifier = identifier } } /// An unordered, non-unique collection of values of type `Element`. public struct Bag { private var elements: [BagElement] = [] private var currentIdentifier: UInt = 0 public init() { } /// Inserts the given value in the collection, and returns a token that can /// later be passed to removeValueForToken(). public mutating func insert(value: Element) -> RemovalToken { let (nextIdentifier, overflow) = UInt.addWithOverflow(currentIdentifier, 1) if overflow { reindex() } let token = RemovalToken(identifier: currentIdentifier) let element = BagElement(value: value, identifier: currentIdentifier, token: token) elements.append(element) currentIdentifier = nextIdentifier return token } /// Removes a value, given the token returned from insert(). /// /// If the value has already been removed, nothing happens. public mutating func removeValueForToken(token: RemovalToken) { if let identifier = token.identifier { // Removal is more likely for recent objects than old ones. for i in elements.indices.reverse() { if elements[i].identifier == identifier { elements.removeAtIndex(i) token.identifier = nil break } } } } /// In the event of an identifier overflow (highly, highly unlikely), this /// will reset all current identifiers to reclaim a contiguous set of /// available identifiers for the future. private mutating func reindex() { for i in elements.indices { currentIdentifier = UInt(i) elements[i].identifier = currentIdentifier elements[i].token.identifier = currentIdentifier } } } extension Bag: CollectionType { public typealias Index = Array.Index public var startIndex: Index { return elements.startIndex } public var endIndex: Index { return elements.endIndex } public subscript(index: Index) -> Element { return elements[index].value } } private struct BagElement { let value: Value var identifier: UInt let token: RemovalToken } extension BagElement: CustomStringConvertible { var description: String { return "BagElement(\(value))" } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Swift/Disposable.swift ================================================ // // Disposable.swift // ReactiveCocoa // // Created by Justin Spahr-Summers on 2014-06-02. // Copyright (c) 2014 GitHub. All rights reserved. // /// Represents something that can be “disposed,” usually associated with freeing /// resources or canceling work. public protocol Disposable: class { /// Whether this disposable has been disposed already. var disposed: Bool { get } func dispose() } /// A disposable that only flips `disposed` upon disposal, and performs no other /// work. public final class SimpleDisposable: Disposable { private let _disposed = Atomic(false) public var disposed: Bool { return _disposed.value } public init() {} public func dispose() { _disposed.value = true } } /// A disposable that will run an action upon disposal. public final class ActionDisposable: Disposable { private let action: Atomic<(() -> ())?> public var disposed: Bool { return action.value == nil } /// Initializes the disposable to run the given action upon disposal. public init(action: () -> ()) { self.action = Atomic(action) } public func dispose() { let oldAction = action.swap(nil) oldAction?() } } /// A disposable that will dispose of any number of other disposables. public final class CompositeDisposable: Disposable { private let disposables: Atomic?> /// Represents a handle to a disposable previously added to a /// CompositeDisposable. public final class DisposableHandle { private let bagToken: Atomic private weak var disposable: CompositeDisposable? private static let empty = DisposableHandle() private init() { self.bagToken = Atomic(nil) } private init(bagToken: RemovalToken, disposable: CompositeDisposable) { self.bagToken = Atomic(bagToken) self.disposable = disposable } /// Removes the pointed-to disposable from its CompositeDisposable. /// /// This is useful to minimize memory growth, by removing disposables /// that are no longer needed. public func remove() { if let token = bagToken.swap(nil) { disposable?.disposables.modify { bag in guard let immutableBag = bag else { return nil } var mutableBag = immutableBag mutableBag.removeValueForToken(token) return mutableBag } } } } public var disposed: Bool { return disposables.value == nil } /// Initializes a CompositeDisposable containing the given sequence of /// disposables. public init(_ disposables: S) { var bag: Bag = Bag() for disposable in disposables { bag.insert(disposable) } self.disposables = Atomic(bag) } /// Initializes an empty CompositeDisposable. public convenience init() { self.init([]) } public func dispose() { if let ds = disposables.swap(nil) { for d in ds.reverse() { d.dispose() } } } /// Adds the given disposable to the list, then returns a handle which can /// be used to opaquely remove the disposable later (if desired). public func addDisposable(d: Disposable?) -> DisposableHandle { guard let d = d else { return DisposableHandle.empty } var handle: DisposableHandle? = nil disposables.modify { ds in guard let immutableDs = ds else { return nil } var mutableDs = immutableDs let token = mutableDs.insert(d) handle = DisposableHandle(bagToken: token, disposable: self) return mutableDs } if let handle = handle { return handle } else { d.dispose() return DisposableHandle.empty } } /// Adds an ActionDisposable to the list. public func addDisposable(action: () -> ()) -> DisposableHandle { return addDisposable(ActionDisposable(action: action)) } } /// A disposable that, upon deinitialization, will automatically dispose of /// another disposable. public final class ScopedDisposable: Disposable { /// The disposable which will be disposed when the ScopedDisposable /// deinitializes. public let innerDisposable: Disposable public var disposed: Bool { return innerDisposable.disposed } /// Initializes the receiver to dispose of the argument upon /// deinitialization. public init(_ disposable: Disposable) { innerDisposable = disposable } deinit { dispose() } public func dispose() { innerDisposable.dispose() } } /// A disposable that will optionally dispose of another disposable. public final class SerialDisposable: Disposable { private struct State { var innerDisposable: Disposable? = nil var disposed = false } private let state = Atomic(State()) public var disposed: Bool { return state.value.disposed } /// The inner disposable to dispose of. /// /// Whenever this property is set (even to the same value!), the previous /// disposable is automatically disposed. public var innerDisposable: Disposable? { get { return state.value.innerDisposable } set(d) { let oldState = state.modify { state in var mutableState = state mutableState.innerDisposable = d return mutableState } oldState.innerDisposable?.dispose() if oldState.disposed { d?.dispose() } } } /// Initializes the receiver to dispose of the argument when the /// SerialDisposable is disposed. public init(_ disposable: Disposable? = nil) { innerDisposable = disposable } public func dispose() { let orig = state.swap(State(innerDisposable: nil, disposed: true)) orig.innerDisposable?.dispose() } } /// Adds the right-hand-side disposable to the left-hand-side /// `CompositeDisposable`. /// /// disposable += producer /// .filter { ... } /// .map { ... } /// .start(observer) /// public func +=(lhs: CompositeDisposable, rhs: Disposable?) -> CompositeDisposable.DisposableHandle { return lhs.addDisposable(rhs) } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Swift/Event.swift ================================================ // // Event.swift // ReactiveCocoa // // Created by Justin Spahr-Summers on 2015-01-16. // Copyright (c) 2015 GitHub. All rights reserved. // /// Represents a signal event. /// /// Signals must conform to the grammar: /// `Next* (Failed | Completed | Interrupted)?` public enum Event { /// A value provided by the signal. case Next(Value) /// The signal terminated because of an error. No further events will be /// received. case Failed(Error) /// The signal successfully terminated. No further events will be received. case Completed /// Event production on the signal has been interrupted. No further events /// will be received. case Interrupted /// Whether this event indicates signal termination (i.e., that no further /// events will be received). public var isTerminating: Bool { switch self { case .Next: return false case .Failed, .Completed, .Interrupted: return true } } /// Lifts the given function over the event's value. public func map(f: Value -> U) -> Event { switch self { case let .Next(value): return .Next(f(value)) case let .Failed(error): return .Failed(error) case .Completed: return .Completed case .Interrupted: return .Interrupted } } /// Lifts the given function over the event's error. public func mapError(f: Error -> F) -> Event { switch self { case let .Next(value): return .Next(value) case let .Failed(error): return .Failed(f(error)) case .Completed: return .Completed case .Interrupted: return .Interrupted } } /// Unwraps the contained `Next` value. public var value: Value? { if case let .Next(value) = self { return value } else { return nil } } /// Unwraps the contained `Error` value. public var error: Error? { if case let .Failed(error) = self { return error } else { return nil } } } public func == (lhs: Event, rhs: Event) -> Bool { switch (lhs, rhs) { case let (.Next(left), .Next(right)): return left == right case let (.Failed(left), .Failed(right)): return left == right case (.Completed, .Completed): return true case (.Interrupted, .Interrupted): return true default: return false } } extension Event: CustomStringConvertible { public var description: String { switch self { case let .Next(value): return "NEXT \(value)" case let .Failed(error): return "FAILED \(error)" case .Completed: return "COMPLETED" case .Interrupted: return "INTERRUPTED" } } } /// Event protocol for constraining signal extensions public protocol EventType { // The value type of an event. typealias Value /// The error type of an event. If errors aren't possible then `NoError` can be used. typealias Error: ErrorType /// Extracts the event from the receiver. var event: Event { get } } extension Event: EventType { public var event: Event { return self } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Swift/Flatten.swift ================================================ // // Flatten.swift // ReactiveCocoa // // Created by Neil Pankey on 11/30/15. // Copyright © 2015 GitHub. All rights reserved. // /// Describes how multiple producers should be joined together. public enum FlattenStrategy: Equatable { /// The producers should be merged, so that any value received on any of the /// input producers will be forwarded immediately to the output producer. /// /// The resulting producer will complete only when all inputs have completed. case Merge /// The producers should be concatenated, so that their values are sent in the /// order of the producers themselves. /// /// The resulting producer will complete only when all inputs have completed. case Concat /// Only the events from the latest input producer should be considered for /// the output. Any producers received before that point will be disposed of. /// /// The resulting producer will complete only when the producer-of-producers and /// the latest producer has completed. case Latest } extension SignalType where Value: SignalProducerType, Error == Value.Error { /// Flattens the inner producers sent upon `signal` (into a single signal of /// values), according to the semantics of the given strategy. /// /// If `signal` or an active inner producer fails, the returned signal will /// forward that failure immediately. /// /// `Interrupted` events on inner producers will be treated like `Completed` /// events on inner producers. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func flatten(strategy: FlattenStrategy) -> Signal { switch strategy { case .Merge: return self.merge() case .Concat: return self.concat() case .Latest: return self.switchToLatest() } } } extension SignalProducerType where Value: SignalProducerType, Error == Value.Error { /// Flattens the inner producers sent upon `producer` (into a single producer of /// values), according to the semantics of the given strategy. /// /// If `producer` or an active inner producer fails, the returned producer will /// forward that failure immediately. /// /// `Interrupted` events on inner producers will be treated like `Completed` /// events on inner producers. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func flatten(strategy: FlattenStrategy) -> SignalProducer { switch strategy { case .Merge: return self.merge() case .Concat: return self.concat() case .Latest: return self.switchToLatest() } } } extension SignalType where Value: SignalType, Error == Value.Error { /// Flattens the inner signals sent upon `signal` (into a single signal of /// values), according to the semantics of the given strategy. /// /// If `signal` or an active inner signal emits an error, the returned /// signal will forward that error immediately. /// /// `Interrupted` events on inner signals will be treated like `Completed` /// events on inner signals. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func flatten(strategy: FlattenStrategy) -> Signal { return self.map(SignalProducer.init).flatten(strategy) } } extension SignalProducerType where Value: SignalType, Error == Value.Error { /// Flattens the inner signals sent upon `producer` (into a single producer of /// values), according to the semantics of the given strategy. /// /// If `producer` or an active inner signal emits an error, the returned /// producer will forward that error immediately. /// /// `Interrupted` events on inner signals will be treated like `Completed` /// events on inner signals. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func flatten(strategy: FlattenStrategy) -> SignalProducer { return self.map(SignalProducer.init).flatten(strategy) } } extension SignalType where Value: SignalProducerType, Error == Value.Error { /// Returns a signal which sends all the values from producer signal emitted from /// `signal`, waiting until each inner producer completes before beginning to /// send the values from the next inner producer. /// /// If any of the inner producers fail, the returned signal will forward /// that failure immediately /// /// The returned signal completes only when `signal` and all producers /// emitted from `signal` complete. private func concat() -> Signal { return Signal { relayObserver in let disposable = CompositeDisposable() let relayDisposable = CompositeDisposable() disposable += relayDisposable disposable += self.observeConcat(relayObserver, relayDisposable) return disposable } } private func observeConcat(observer: Observer, _ disposable: CompositeDisposable? = nil) -> Disposable? { let state = ConcatState(observer: observer, disposable: disposable) return self.observe { event in switch event { case let .Next(value): state.enqueueSignalProducer(value.producer) case let .Failed(error): observer.sendFailed(error) case .Completed: // Add one last producer to the queue, whose sole job is to // "turn out the lights" by completing `observer`. state.enqueueSignalProducer(SignalProducer.empty.on(completed: { observer.sendCompleted() })) case .Interrupted: observer.sendInterrupted() } } } } extension SignalProducerType where Value: SignalProducerType, Error == Value.Error { /// Returns a producer which sends all the values from each producer emitted from /// `producer`, waiting until each inner producer completes before beginning to /// send the values from the next inner producer. /// /// If any of the inner producers emit an error, the returned producer will emit /// that error. /// /// The returned producer completes only when `producer` and all producers /// emitted from `producer` complete. private func concat() -> SignalProducer { return SignalProducer { observer, disposable in self.startWithSignal { signal, signalDisposable in disposable += signalDisposable signal.observeConcat(observer, disposable) } } } } extension SignalProducerType { /// `concat`s `next` onto `self`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func concat(next: SignalProducer) -> SignalProducer { return SignalProducer, Error>(values: [self.producer, next]).flatten(.Concat) } } private final class ConcatState { /// The observer of a started `concat` producer. let observer: Observer /// The top level disposable of a started `concat` producer. let disposable: CompositeDisposable? /// The active producer, if any, and the producers waiting to be started. let queuedSignalProducers: Atomic<[SignalProducer]> = Atomic([]) init(observer: Signal.Observer, disposable: CompositeDisposable?) { self.observer = observer self.disposable = disposable } func enqueueSignalProducer(producer: SignalProducer) { if let d = disposable where d.disposed { return } var shouldStart = true queuedSignalProducers.modify { // An empty queue means the concat is idle, ready & waiting to start // the next producer. var queue = $0 shouldStart = queue.isEmpty queue.append(producer) return queue } if shouldStart { startNextSignalProducer(producer) } } func dequeueSignalProducer() -> SignalProducer? { if let d = disposable where d.disposed { return nil } var nextSignalProducer: SignalProducer? queuedSignalProducers.modify { // Active producers remain in the queue until completed. Since // dequeueing happens at completion of the active producer, the // first producer in the queue can be removed. var queue = $0 if !queue.isEmpty { queue.removeAtIndex(0) } nextSignalProducer = queue.first return queue } return nextSignalProducer } /// Subscribes to the given signal producer. func startNextSignalProducer(signalProducer: SignalProducer) { signalProducer.startWithSignal { signal, disposable in let handle = self.disposable?.addDisposable(disposable) ?? nil signal.observe { event in switch event { case .Completed, .Interrupted: handle?.remove() if let nextSignalProducer = self.dequeueSignalProducer() { self.startNextSignalProducer(nextSignalProducer) } default: self.observer.action(event) } } } } } extension SignalType where Value: SignalProducerType, Error == Value.Error { /// Merges a `signal` of SignalProducers down into a single signal, biased toward the producer /// added earlier. Returns a Signal that will forward events from the inner producers as they arrive. private func merge() -> Signal { return Signal { relayObserver in let disposable = CompositeDisposable() let relayDisposable = CompositeDisposable() disposable += relayDisposable disposable += self.observeMerge(relayObserver, relayDisposable) return disposable } } private func observeMerge(observer: Observer, _ disposable: CompositeDisposable) -> Disposable? { let inFlight = Atomic(1) let decrementInFlight: () -> () = { let orig = inFlight.modify { $0 - 1 } if orig == 1 { observer.sendCompleted() } } return self.observe { event in switch event { case let .Next(producer): producer.startWithSignal { innerSignal, innerDisposable in inFlight.modify { $0 + 1 } let handle = disposable.addDisposable(innerDisposable) innerSignal.observe { event in switch event { case .Completed, .Interrupted: handle.remove() decrementInFlight() default: observer.action(event) } } } case let .Failed(error): observer.sendFailed(error) case .Completed: decrementInFlight() case .Interrupted: observer.sendInterrupted() } } } } extension SignalProducerType where Value: SignalProducerType, Error == Value.Error { /// Merges a `signal` of SignalProducers down into a single signal, biased toward the producer /// added earlier. Returns a Signal that will forward events from the inner producers as they arrive. private func merge() -> SignalProducer { return SignalProducer { relayObserver, disposable in self.startWithSignal { signal, signalDisposable in disposable.addDisposable(signalDisposable) signal.observeMerge(relayObserver, disposable) } } } } extension SignalType { /// Merges the given signals into a single `Signal` that will emit all values /// from each of them, and complete when all of them have completed. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public static func merge>(signals: S) -> Signal { let producer = SignalProducer, Error>(values: signals) var result: Signal! producer.startWithSignal { (signal, _) in result = signal.flatten(.Merge) } return result } } extension SignalType where Value: SignalProducerType, Error == Value.Error { /// Returns a signal that forwards values from the latest signal sent on /// `signal`, ignoring values sent on previous inner signal. /// /// An error sent on `signal` or the latest inner signal will be sent on the /// returned signal. /// /// The returned signal completes when `signal` and the latest inner /// signal have both completed. private func switchToLatest() -> Signal { return Signal { observer in let composite = CompositeDisposable() let serial = SerialDisposable() composite += serial composite += self.observeSwitchToLatest(observer, serial) return composite } } private func observeSwitchToLatest(observer: Observer, _ latestInnerDisposable: SerialDisposable) -> Disposable? { let state = Atomic(LatestState()) return self.observe { event in switch event { case let .Next(innerProducer): innerProducer.startWithSignal { innerSignal, innerDisposable in state.modify { // When we replace the disposable below, this prevents the // generated Interrupted event from doing any work. var state = $0 state.replacingInnerSignal = true return state } latestInnerDisposable.innerDisposable = innerDisposable state.modify { var state = $0 state.replacingInnerSignal = false state.innerSignalComplete = false return state } innerSignal.observe { event in switch event { case .Interrupted: // If interruption occurred as a result of a new producer // arriving, we don't want to notify our observer. let original = state.modify { var state = $0 if !state.replacingInnerSignal { state.innerSignalComplete = true } return state } if !original.replacingInnerSignal && original.outerSignalComplete { observer.sendCompleted() } case .Completed: let original = state.modify { var state = $0 state.innerSignalComplete = true return state } if original.outerSignalComplete { observer.sendCompleted() } default: observer.action(event) } } } case let .Failed(error): observer.sendFailed(error) case .Completed: let original = state.modify { var state = $0 state.outerSignalComplete = true return state } if original.innerSignalComplete { observer.sendCompleted() } case .Interrupted: observer.sendInterrupted() } } } } extension SignalProducerType where Value: SignalProducerType, Error == Value.Error { /// Returns a signal that forwards values from the latest signal sent on /// `signal`, ignoring values sent on previous inner signal. /// /// An error sent on `signal` or the latest inner signal will be sent on the /// returned signal. /// /// The returned signal completes when `signal` and the latest inner /// signal have both completed. private func switchToLatest() -> SignalProducer { return SignalProducer { observer, disposable in let latestInnerDisposable = SerialDisposable() disposable.addDisposable(latestInnerDisposable) self.startWithSignal { signal, signalDisposable in disposable += signalDisposable disposable += signal.observeSwitchToLatest(observer, latestInnerDisposable) } } } } private struct LatestState { var outerSignalComplete: Bool = false var innerSignalComplete: Bool = true var replacingInnerSignal: Bool = false } extension SignalType { /// Maps each event from `signal` to a new signal, then flattens the /// resulting producers (into a signal of values), according to the /// semantics of the given strategy. /// /// If `signal` or any of the created producers fail, the returned signal /// will forward that failure immediately. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func flatMap(strategy: FlattenStrategy, transform: Value -> SignalProducer) -> Signal { return map(transform).flatten(strategy) } /// Maps each event from `signal` to a new signal, then flattens the /// resulting signals (into a signal of values), according to the /// semantics of the given strategy. /// /// If `signal` or any of the created signals emit an error, the returned /// signal will forward that error immediately. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func flatMap(strategy: FlattenStrategy, transform: Value -> Signal) -> Signal { return map(transform).flatten(strategy) } } extension SignalProducerType { /// Maps each event from `self` to a new producer, then flattens the /// resulting producers (into a producer of values), according to the /// semantics of the given strategy. /// /// If `self` or any of the created producers fail, the returned producer /// will forward that failure immediately. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func flatMap(strategy: FlattenStrategy, transform: Value -> SignalProducer) -> SignalProducer { return map(transform).flatten(strategy) } /// Maps each event from `self` to a new producer, then flattens the /// resulting signals (into a producer of values), according to the /// semantics of the given strategy. /// /// If `self` or any of the created signals emit an error, the returned /// producer will forward that error immediately. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func flatMap(strategy: FlattenStrategy, transform: Value -> Signal) -> SignalProducer { return map(transform).flatten(strategy) } } extension SignalType { /// Catches any failure that may occur on the input signal, mapping to a new producer /// that starts in its place. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func flatMapError(handler: Error -> SignalProducer) -> Signal { return Signal { observer in self.observeFlatMapError(handler, observer, SerialDisposable()) } } private func observeFlatMapError(handler: Error -> SignalProducer, _ observer: Observer, _ serialDisposable: SerialDisposable) -> Disposable? { return self.observe { event in switch event { case let .Next(value): observer.sendNext(value) case let .Failed(error): handler(error).startWithSignal { signal, disposable in serialDisposable.innerDisposable = disposable signal.observe(observer) } case .Completed: observer.sendCompleted() case .Interrupted: observer.sendInterrupted() } } } } extension SignalProducerType { /// Catches any failure that may occur on the input producer, mapping to a new producer /// that starts in its place. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func flatMapError(handler: Error -> SignalProducer) -> SignalProducer { return SignalProducer { observer, disposable in let serialDisposable = SerialDisposable() disposable.addDisposable(serialDisposable) self.startWithSignal { signal, signalDisposable in serialDisposable.innerDisposable = signalDisposable signal.observeFlatMapError(handler, observer, serialDisposable) } } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Swift/FoundationExtensions.swift ================================================ // // FoundationExtensions.swift // ReactiveCocoa // // Created by Justin Spahr-Summers on 2014-10-19. // Copyright (c) 2014 GitHub. All rights reserved. // import Foundation import enum Result.NoError extension NSNotificationCenter { /// Returns a producer of notifications posted that match the given criteria. /// This producer will not terminate naturally, so it must be explicitly /// disposed to avoid leaks. public func rac_notifications(name: String? = nil, object: AnyObject? = nil) -> SignalProducer { return SignalProducer { observer, disposable in let notificationObserver = self.addObserverForName(name, object: object, queue: nil) { notification in observer.sendNext(notification) } disposable.addDisposable { self.removeObserver(notificationObserver) } } } } private let defaultSessionError = NSError(domain: "org.reactivecocoa.ReactiveCocoa.rac_dataWithRequest", code: 1, userInfo: nil) extension NSURLSession { /// Returns a producer that will execute the given request once for each /// invocation of start(). public func rac_dataWithRequest(request: NSURLRequest) -> SignalProducer<(NSData, NSURLResponse), NSError> { return SignalProducer { observer, disposable in let task = self.dataTaskWithRequest(request) { data, response, error in if let data = data, response = response { observer.sendNext((data, response)) observer.sendCompleted() } else { observer.sendFailed(error ?? defaultSessionError) } } disposable.addDisposable { task.cancel() } task.resume() } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Swift/ObjectiveCBridging.swift ================================================ // // ObjectiveCBridging.swift // ReactiveCocoa // // Created by Justin Spahr-Summers on 2014-07-02. // Copyright (c) 2014 GitHub, Inc. All rights reserved. // import Result extension RACDisposable: Disposable {} extension RACScheduler: DateSchedulerType { public var currentDate: NSDate { return NSDate() } public func schedule(action: () -> ()) -> Disposable? { let disposable: RACDisposable = self.schedule(action) // Call the Objective-C implementation return disposable as Disposable? } public func scheduleAfter(date: NSDate, action: () -> ()) -> Disposable? { return self.after(date, schedule: action) } public func scheduleAfter(date: NSDate, repeatingEvery: NSTimeInterval, withLeeway: NSTimeInterval, action: () -> ()) -> Disposable? { return self.after(date, repeatingEvery: repeatingEvery, withLeeway: withLeeway, schedule: action) } } extension ImmediateScheduler { public func toRACScheduler() -> RACScheduler { return RACScheduler.immediateScheduler() } } extension UIScheduler { public func toRACScheduler() -> RACScheduler { return RACScheduler.mainThreadScheduler() } } extension QueueScheduler { public func toRACScheduler() -> RACScheduler { return RACTargetQueueScheduler(name: "org.reactivecocoa.ReactiveCocoa.QueueScheduler.toRACScheduler()", targetQueue: queue) } } private func defaultNSError(message: String, file: String, line: Int) -> NSError { return Result<(), NSError>.error(message, file: file, line: line) } extension RACSignal { /// Creates a SignalProducer which will subscribe to the receiver once for /// each invocation of start(). public func toSignalProducer(file: String = __FILE__, line: Int = __LINE__) -> SignalProducer { return SignalProducer { observer, disposable in let next = { obj in observer.sendNext(obj) } let failed = { nsError in observer.sendFailed(nsError ?? defaultNSError("Nil RACSignal error", file: file, line: line)) } let completed = { observer.sendCompleted() } disposable += self.subscribeNext(next, error: failed, completed: completed) } } } extension SignalType { /// Turns each value into an Optional. private func optionalize() -> Signal { return signal.map(Optional.init) } } // MARK: - toRACSignal extension SignalProducerType where Value: AnyObject { /// Creates a RACSignal that will start() the producer once for each /// subscription. /// /// Any `Interrupted` events will be silently discarded. public func toRACSignal() -> RACSignal { return self .lift { $0.optionalize() } .toRACSignal() } } extension SignalProducerType where Value: OptionalType, Value.Wrapped: AnyObject { /// Creates a RACSignal that will start() the producer once for each /// subscription. /// /// Any `Interrupted` events will be silently discarded. public func toRACSignal() -> RACSignal { return self .mapError { $0 as NSError } .toRACSignal() } } extension SignalProducerType where Value: AnyObject, Error: NSError { /// Creates a RACSignal that will start() the producer once for each /// subscription. /// /// Any `Interrupted` events will be silently discarded. public func toRACSignal() -> RACSignal { return self .lift { $0.optionalize() } .toRACSignal() } } extension SignalProducerType where Value: OptionalType, Value.Wrapped: AnyObject, Error: NSError { /// Creates a RACSignal that will start() the producer once for each /// subscription. /// /// Any `Interrupted` events will be silently discarded. public func toRACSignal() -> RACSignal { // This special casing of `Error: NSError` is a workaround for rdar://22708537 // which causes an NSError's UserInfo dictionary to get discarded // during a cast from ErrorType to NSError in a generic function return RACSignal.createSignal { subscriber in let selfDisposable = self.start { event in switch event { case let .Next(value): subscriber.sendNext(value.optional) case let .Failed(error): subscriber.sendError(error) case .Completed: subscriber.sendCompleted() case .Interrupted: break } } return RACDisposable { selfDisposable.dispose() } } } } extension SignalType where Value: AnyObject { /// Creates a RACSignal that will observe the given signal. /// /// Any `Interrupted` event will be silently discarded. public func toRACSignal() -> RACSignal { return self .optionalize() .toRACSignal() } } extension SignalType where Value: AnyObject, Error: NSError { /// Creates a RACSignal that will observe the given signal. /// /// Any `Interrupted` event will be silently discarded. public func toRACSignal() -> RACSignal { return self .optionalize() .toRACSignal() } } extension SignalType where Value: OptionalType, Value.Wrapped: AnyObject { /// Creates a RACSignal that will observe the given signal. /// /// Any `Interrupted` event will be silently discarded. public func toRACSignal() -> RACSignal { return self .mapError { $0 as NSError } .toRACSignal() } } extension SignalType where Value: OptionalType, Value.Wrapped: AnyObject, Error: NSError { /// Creates a RACSignal that will observe the given signal. /// /// Any `Interrupted` event will be silently discarded. public func toRACSignal() -> RACSignal { // This special casing of `Error: NSError` is a workaround for rdar://22708537 // which causes an NSError's UserInfo dictionary to get discarded // during a cast from ErrorType to NSError in a generic function return RACSignal.createSignal { subscriber in let selfDisposable = self.observe { event in switch event { case let .Next(value): subscriber.sendNext(value.optional) case let .Failed(error): subscriber.sendError(error) case .Completed: subscriber.sendCompleted() case .Interrupted: break } } return RACDisposable { selfDisposable?.dispose() } } } } // MARK: - extension RACCommand { /// Creates an Action that will execute the receiver. /// /// Note that the returned Action will not necessarily be marked as /// executing when the command is. However, the reverse is always true: /// the RACCommand will always be marked as executing when the action is. public func toAction(file: String = __FILE__, line: Int = __LINE__) -> Action { let enabledProperty = MutableProperty(true) enabledProperty <~ self.enabled.toSignalProducer() .map { $0 as! Bool } .flatMapError { _ in SignalProducer(value: false) } return Action(enabledIf: enabledProperty) { input -> SignalProducer in let executionSignal = RACSignal.`defer` { return self.execute(input) } return executionSignal.toSignalProducer(file, line: line) } } } extension Action { private var commandEnabled: RACSignal { return self.enabled.producer .map { $0 as NSNumber } .toRACSignal() } } /// Creates a RACCommand that will execute the action. /// /// Note that the returned command will not necessarily be marked as /// executing when the action is. However, the reverse is always true: /// the Action will always be marked as executing when the RACCommand is. public func toRACCommand(action: Action) -> RACCommand { return RACCommand(enabled: action.commandEnabled) { input -> RACSignal in return action .apply(input) .toRACSignal() } } /// Creates a RACCommand that will execute the action. /// /// Note that the returned command will not necessarily be marked as /// executing when the action is. However, the reverse is always true: /// the Action will always be marked as executing when the RACCommand is. public func toRACCommand(action: Action) -> RACCommand { return RACCommand(enabled: action.commandEnabled) { input -> RACSignal in return action .apply(input) .toRACSignal() } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Swift/Observer.swift ================================================ // // Observer.swift // ReactiveCocoa // // Created by Andy Matuschak on 10/2/15. // Copyright © 2015 GitHub. All rights reserved. // /// An Observer is a simple wrapper around a function which can receive Events /// (typically from a Signal). public struct Observer { public typealias Action = Event -> () public let action: Action public init(_ action: Action) { self.action = action } public init(failed: (Error -> ())? = nil, completed: (() -> ())? = nil, interrupted: (() -> ())? = nil, next: (Value -> ())? = nil) { self.init { event in switch event { case let .Next(value): next?(value) case let .Failed(error): failed?(error) case .Completed: completed?() case .Interrupted: interrupted?() } } } /// Puts a `Next` event into the given observer. public func sendNext(value: Value) { action(.Next(value)) } /// Puts an `Failed` event into the given observer. public func sendFailed(error: Error) { action(.Failed(error)) } /// Puts a `Completed` event into the given observer. public func sendCompleted() { action(.Completed) } /// Puts a `Interrupted` event into the given observer. public func sendInterrupted() { action(.Interrupted) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Swift/Optional.swift ================================================ // // Optional.swift // ReactiveCocoa // // Created by Neil Pankey on 6/24/15. // Copyright (c) 2015 GitHub. All rights reserved. // /// An optional protocol for use in type constraints. public protocol OptionalType { /// The type contained in the otpional. typealias Wrapped /// Extracts an optional from the receiver. var optional: Wrapped? { get } } extension Optional: OptionalType { public var optional: Wrapped? { return self } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Swift/Property.swift ================================================ import Foundation import enum Result.NoError /// Represents a property that allows observation of its changes. public protocol PropertyType { typealias Value /// The current value of the property. var value: Value { get } /// A producer for Signals that will send the property's current value, /// followed by all changes over time. var producer: SignalProducer { get } /// A signal that will send the property's changes over time. var signal: Signal { get } } /// A read-only property that allows observation of its changes. public struct AnyProperty: PropertyType { private let _value: () -> Value private let _producer: () -> SignalProducer private let _signal: () -> Signal public var value: Value { return _value() } public var producer: SignalProducer { return _producer() } public var signal: Signal { return _signal() } /// Initializes a property as a read-only view of the given property. public init(_ property: P) { _value = { property.value } _producer = { property.producer } _signal = { property.signal } } /// Initializes a property that first takes on `initialValue`, then each value /// sent on a signal created by `producer`. public init(initialValue: Value, producer: SignalProducer) { let mutableProperty = MutableProperty(initialValue) mutableProperty <~ producer self.init(mutableProperty) } /// Initializes a property that first takes on `initialValue`, then each value /// sent on `signal`. public init(initialValue: Value, signal: Signal) { let mutableProperty = MutableProperty(initialValue) mutableProperty <~ signal self.init(mutableProperty) } } /// A property that never changes. public struct ConstantProperty: PropertyType { public let value: Value public let producer: SignalProducer public let signal: Signal /// Initializes the property to have the given value. public init(_ value: Value) { self.value = value self.producer = SignalProducer(value: value) self.signal = .empty } } /// Represents an observable property that can be mutated directly. /// /// Only classes can conform to this protocol, because instances must support /// weak references (and value types currently do not). public protocol MutablePropertyType: class, PropertyType { var value: Value { get set } } /// A mutable property of type `Value` that allows observation of its changes. /// /// Instances of this class are thread-safe. public final class MutableProperty: MutablePropertyType { private let observer: Signal.Observer /// Need a recursive lock around `value` to allow recursive access to /// `value`. Note that recursive sets will still deadlock because the /// underlying producer prevents sending recursive events. private let lock: NSRecursiveLock private var _value: Value /// The current value of the property. /// /// Setting this to a new value will notify all observers of any Signals /// created from the `values` producer. public var value: Value { get { return withValue { $0 } } set { modify { _ in newValue } } } /// A signal that will send the property's changes over time, /// then complete when the property has deinitialized. public lazy var signal: Signal = { [unowned self] in var extractedSignal: Signal! self.producer.startWithSignal { signal, _ in extractedSignal = signal } return extractedSignal }() /// A producer for Signals that will send the property's current value, /// followed by all changes over time, then complete when the property has /// deinitialized. public let producer: SignalProducer /// Initializes the property with the given value to start. public init(_ initialValue: Value) { _value = initialValue lock = NSRecursiveLock() lock.name = "org.reactivecocoa.ReactiveCocoa.MutableProperty" (producer, observer) = SignalProducer.buffer(1) observer.sendNext(initialValue) } /// Atomically replaces the contents of the variable. /// /// Returns the old value. public func swap(newValue: Value) -> Value { return modify { _ in newValue } } /// Atomically modifies the variable. /// /// Returns the old value. public func modify(@noescape action: (Value) throws -> Value) rethrows -> Value { lock.lock() defer { lock.unlock() } let oldValue = _value _value = try action(_value) observer.sendNext(_value) return oldValue } /// Atomically performs an arbitrary action using the current value of the /// variable. /// /// Returns the result of the action. public func withValue(@noescape action: (Value) throws -> Result) rethrows -> Result { lock.lock() defer { lock.unlock() } return try action(_value) } deinit { observer.sendCompleted() } } /// Wraps a `dynamic` property, or one defined in Objective-C, using Key-Value /// Coding and Key-Value Observing. /// /// Use this class only as a last resort! `MutableProperty` is generally better /// unless KVC/KVO is required by the API you're using (for example, /// `NSOperation`). @objc public final class DynamicProperty: RACDynamicPropertySuperclass, MutablePropertyType { public typealias Value = AnyObject? private weak var object: NSObject? private let keyPath: String private var property: MutableProperty? /// The current value of the property, as read and written using Key-Value /// Coding. public var value: AnyObject? { @objc(rac_value) get { return object?.valueForKeyPath(keyPath) } @objc(setRac_value:) set(newValue) { object?.setValue(newValue, forKeyPath: keyPath) } } /// A producer that will create a Key-Value Observer for the given object, /// send its initial value then all changes over time, and then complete /// when the observed object has deallocated. /// /// By definition, this only works if the object given to init() is /// KVO-compliant. Most UI controls are not! public var producer: SignalProducer { return property?.producer ?? .empty } public var signal: Signal { return property?.signal ?? .empty } /// Initializes a property that will observe and set the given key path of /// the given object. `object` must support weak references! public init(object: NSObject?, keyPath: String) { self.object = object self.keyPath = keyPath self.property = MutableProperty(nil) /// DynamicProperty stay alive as long as object is alive. /// This is made possible by strong reference cycles. super.init() object?.rac_valuesForKeyPath(keyPath, observer: nil)? .toSignalProducer() .start { event in switch event { case let .Next(newValue): self.property?.value = newValue case let .Failed(error): fatalError("Received unexpected error from KVO signal: \(error)") case .Interrupted, .Completed: self.property = nil } } } } infix operator <~ { associativity right // Binds tighter than assignment but looser than everything else precedence 93 } /// Binds a signal to a property, updating the property's value to the latest /// value sent by the signal. /// /// The binding will automatically terminate when the property is deinitialized, /// or when the signal sends a `Completed` event. public func <~ (property: P, signal: Signal) -> Disposable { let disposable = CompositeDisposable() disposable += property.producer.startWithCompleted { disposable.dispose() } disposable += signal.observe { [weak property] event in switch event { case let .Next(value): property?.value = value case .Completed: disposable.dispose() default: break } } return disposable } /// Creates a signal from the given producer, which will be immediately bound to /// the given property, updating the property's value to the latest value sent /// by the signal. /// /// The binding will automatically terminate when the property is deinitialized, /// or when the created signal sends a `Completed` event. public func <~ (property: P, producer: SignalProducer) -> Disposable { var disposable: Disposable! producer.startWithSignal { signal, signalDisposable in property <~ signal disposable = signalDisposable property.producer.startWithCompleted { signalDisposable.dispose() } } return disposable } /// Binds `destinationProperty` to the latest values of `sourceProperty`. /// /// The binding will automatically terminate when either property is /// deinitialized. public func <~ (destinationProperty: Destination, sourceProperty: Source) -> Disposable { return destinationProperty <~ sourceProperty.producer } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Swift/Scheduler.swift ================================================ // // Scheduler.swift // ReactiveCocoa // // Created by Justin Spahr-Summers on 2014-06-02. // Copyright (c) 2014 GitHub. All rights reserved. // import Foundation /// Represents a serial queue of work items. public protocol SchedulerType { /// Enqueues an action on the scheduler. /// /// When the work is executed depends on the scheduler in use. /// /// Optionally returns a disposable that can be used to cancel the work /// before it begins. func schedule(action: () -> ()) -> Disposable? } /// A particular kind of scheduler that supports enqueuing actions at future /// dates. public protocol DateSchedulerType: SchedulerType { /// The current date, as determined by this scheduler. /// /// This can be implemented to deterministic return a known date (e.g., for /// testing purposes). var currentDate: NSDate { get } /// Schedules an action for execution at or after the given date. /// /// Optionally returns a disposable that can be used to cancel the work /// before it begins. func scheduleAfter(date: NSDate, action: () -> ()) -> Disposable? /// Schedules a recurring action at the given interval, beginning at the /// given start time. /// /// Optionally returns a disposable that can be used to cancel the work /// before it begins. func scheduleAfter(date: NSDate, repeatingEvery: NSTimeInterval, withLeeway: NSTimeInterval, action: () -> ()) -> Disposable? } /// A scheduler that performs all work synchronously. public final class ImmediateScheduler: SchedulerType { public init() {} public func schedule(action: () -> ()) -> Disposable? { action() return nil } } /// A scheduler that performs all work on the main thread, as soon as possible. /// /// If the caller is already running on the main thread when an action is /// scheduled, it may be run synchronously. However, ordering between actions /// will always be preserved. public final class UIScheduler: SchedulerType { private var queueLength: Int32 = 0 public init() {} public func schedule(action: () -> ()) -> Disposable? { let disposable = SimpleDisposable() let actionAndDecrement: () -> () = { if !disposable.disposed { action() } OSAtomicDecrement32(&self.queueLength) } let queued = OSAtomicIncrement32(&queueLength) // If we're already running on the main thread, and there isn't work // already enqueued, we can skip scheduling and just execute directly. if NSThread.isMainThread() && queued == 1 { actionAndDecrement() } else { dispatch_async(dispatch_get_main_queue(), actionAndDecrement) } return disposable } } /// A scheduler backed by a serial GCD queue. public final class QueueScheduler: DateSchedulerType { internal let queue: dispatch_queue_t internal init(internalQueue: dispatch_queue_t) { queue = internalQueue } /// Initializes a scheduler that will target the given queue with its work. /// /// Even if the queue is concurrent, all work items enqueued with the /// QueueScheduler will be serial with respect to each other. /// /// - warning: Obsoleted in OS X 10.11 @available(OSX, deprecated=10.10, obsoleted=10.11, message="Use init(qos:, name:) instead") public convenience init(queue: dispatch_queue_t, name: String = "org.reactivecocoa.ReactiveCocoa.QueueScheduler") { self.init(internalQueue: dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL)) dispatch_set_target_queue(self.queue, queue) } /// A singleton QueueScheduler that always targets the main thread's GCD /// queue. /// /// Unlike UIScheduler, this scheduler supports scheduling for a future /// date, and will always schedule asynchronously (even if already running /// on the main thread). public static let mainQueueScheduler = QueueScheduler(internalQueue: dispatch_get_main_queue()) public var currentDate: NSDate { return NSDate() } /// Initializes a scheduler that will target a new serial /// queue with the given quality of service class. @available(iOS 8, watchOS 2, OSX 10.10, *) public convenience init(qos: dispatch_qos_class_t = QOS_CLASS_DEFAULT, name: String = "org.reactivecocoa.ReactiveCocoa.QueueScheduler") { self.init(internalQueue: dispatch_queue_create(name, dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, qos, 0))) } public func schedule(action: () -> ()) -> Disposable? { let d = SimpleDisposable() dispatch_async(queue) { if !d.disposed { action() } } return d } private func wallTimeWithDate(date: NSDate) -> dispatch_time_t { let (seconds, frac) = modf(date.timeIntervalSince1970) let nsec: Double = frac * Double(NSEC_PER_SEC) var walltime = timespec(tv_sec: Int(seconds), tv_nsec: Int(nsec)) return dispatch_walltime(&walltime, 0) } public func scheduleAfter(date: NSDate, action: () -> ()) -> Disposable? { let d = SimpleDisposable() dispatch_after(wallTimeWithDate(date), queue) { if !d.disposed { action() } } return d } /// Schedules a recurring action at the given interval, beginning at the /// given start time, and with a reasonable default leeway. /// /// Optionally returns a disposable that can be used to cancel the work /// before it begins. public func scheduleAfter(date: NSDate, repeatingEvery: NSTimeInterval, action: () -> ()) -> Disposable? { // Apple's "Power Efficiency Guide for Mac Apps" recommends a leeway of // at least 10% of the timer interval. return scheduleAfter(date, repeatingEvery: repeatingEvery, withLeeway: repeatingEvery * 0.1, action: action) } public func scheduleAfter(date: NSDate, repeatingEvery: NSTimeInterval, withLeeway leeway: NSTimeInterval, action: () -> ()) -> Disposable? { precondition(repeatingEvery >= 0) precondition(leeway >= 0) let nsecInterval = repeatingEvery * Double(NSEC_PER_SEC) let nsecLeeway = leeway * Double(NSEC_PER_SEC) let timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue) dispatch_source_set_timer(timer, wallTimeWithDate(date), UInt64(nsecInterval), UInt64(nsecLeeway)) dispatch_source_set_event_handler(timer, action) dispatch_resume(timer) return ActionDisposable { dispatch_source_cancel(timer) } } } /// A scheduler that implements virtualized time, for use in testing. public final class TestScheduler: DateSchedulerType { private final class ScheduledAction { let date: NSDate let action: () -> () init(date: NSDate, action: () -> ()) { self.date = date self.action = action } func less(rhs: ScheduledAction) -> Bool { return date.compare(rhs.date) == .OrderedAscending } } private let lock = NSRecursiveLock() private var _currentDate: NSDate /// The virtual date that the scheduler is currently at. public var currentDate: NSDate { let d: NSDate lock.lock() d = _currentDate lock.unlock() return d } private var scheduledActions: [ScheduledAction] = [] /// Initializes a TestScheduler with the given start date. public init(startDate: NSDate = NSDate(timeIntervalSinceReferenceDate: 0)) { lock.name = "org.reactivecocoa.ReactiveCocoa.TestScheduler" _currentDate = startDate } private func schedule(action: ScheduledAction) -> Disposable { lock.lock() scheduledActions.append(action) scheduledActions.sortInPlace { $0.less($1) } lock.unlock() return ActionDisposable { self.lock.lock() self.scheduledActions = self.scheduledActions.filter { $0 !== action } self.lock.unlock() } } public func schedule(action: () -> ()) -> Disposable? { return schedule(ScheduledAction(date: currentDate, action: action)) } /// Schedules an action for execution at or after the given interval /// (counted from `currentDate`). /// /// Optionally returns a disposable that can be used to cancel the work /// before it begins. public func scheduleAfter(interval: NSTimeInterval, action: () -> ()) -> Disposable? { return scheduleAfter(currentDate.dateByAddingTimeInterval(interval), action: action) } public func scheduleAfter(date: NSDate, action: () -> ()) -> Disposable? { return schedule(ScheduledAction(date: date, action: action)) } private func scheduleAfter(date: NSDate, repeatingEvery: NSTimeInterval, disposable: SerialDisposable, action: () -> ()) { precondition(repeatingEvery >= 0) disposable.innerDisposable = scheduleAfter(date) { [unowned self] in action() self.scheduleAfter(date.dateByAddingTimeInterval(repeatingEvery), repeatingEvery: repeatingEvery, disposable: disposable, action: action) } } /// Schedules a recurring action at the given interval, beginning at the /// given interval (counted from `currentDate`). /// /// Optionally returns a disposable that can be used to cancel the work /// before it begins. public func scheduleAfter(interval: NSTimeInterval, repeatingEvery: NSTimeInterval, withLeeway leeway: NSTimeInterval = 0, action: () -> ()) -> Disposable? { return scheduleAfter(currentDate.dateByAddingTimeInterval(interval), repeatingEvery: repeatingEvery, withLeeway: leeway, action: action) } public func scheduleAfter(date: NSDate, repeatingEvery: NSTimeInterval, withLeeway: NSTimeInterval = 0, action: () -> ()) -> Disposable? { let disposable = SerialDisposable() scheduleAfter(date, repeatingEvery: repeatingEvery, disposable: disposable, action: action) return disposable } /// Advances the virtualized clock by an extremely tiny interval, dequeuing /// and executing any actions along the way. /// /// This is intended to be used as a way to execute actions that have been /// scheduled to run as soon as possible. public func advance() { advanceByInterval(DBL_EPSILON) } /// Advances the virtualized clock by the given interval, dequeuing and /// executing any actions along the way. public func advanceByInterval(interval: NSTimeInterval) { lock.lock() advanceToDate(currentDate.dateByAddingTimeInterval(interval)) lock.unlock() } /// Advances the virtualized clock to the given future date, dequeuing and /// executing any actions up until that point. public func advanceToDate(newDate: NSDate) { lock.lock() assert(currentDate.compare(newDate) != .OrderedDescending) _currentDate = newDate while scheduledActions.count > 0 { if newDate.compare(scheduledActions[0].date) == .OrderedAscending { break } let scheduledAction = scheduledActions.removeAtIndex(0) scheduledAction.action() } lock.unlock() } /// Dequeues and executes all scheduled actions, leaving the scheduler's /// date at `NSDate.distantFuture()`. public func run() { advanceToDate(NSDate.distantFuture()) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Swift/Signal.swift ================================================ import Foundation import Result /// A push-driven stream that sends Events over time, parameterized by the type /// of values being sent (`Value`) and the type of failure that can occur (`Error`). /// If no failures should be possible, NoError can be specified for `Error`. /// /// An observer of a Signal will see the exact same sequence of events as all /// other observers. In other words, events will be sent to all observers at the /// same time. /// /// Signals are generally used to represent event streams that are already “in /// progress,” like notifications, user input, etc. To represent streams that /// must first be _started_, see the SignalProducer type. /// /// Signals do not need to be retained. A Signal will be automatically kept /// alive until the event stream has terminated. public final class Signal { public typealias Observer = ReactiveCocoa.Observer private let atomicObservers: Atomic?> = Atomic(Bag()) /// Initializes a Signal that will immediately invoke the given generator, /// then forward events sent to the given observer. /// /// The disposable returned from the closure will be automatically disposed /// if a terminating event is sent to the observer. The Signal itself will /// remain alive until the observer is released. public init(@noescape _ generator: Observer -> Disposable?) { /// Used to ensure that events are serialized during delivery to observers. let sendLock = NSLock() sendLock.name = "org.reactivecocoa.ReactiveCocoa.Signal" let generatorDisposable = SerialDisposable() /// When set to `true`, the Signal should interrupt as soon as possible. let interrupted = Atomic(false) let observer = Observer { event in if case .Interrupted = event { // Normally we disallow recursive events, but // Interrupted is kind of a special snowflake, since it // can inadvertently be sent by downstream consumers. // // So we'll flag Interrupted events specially, and if it // happened to occur while we're sending something else, // we'll wait to deliver it. interrupted.value = true if sendLock.tryLock() { self.interrupt() sendLock.unlock() generatorDisposable.dispose() } } else { if let observers = (event.isTerminating ? self.atomicObservers.swap(nil) : self.atomicObservers.value) { sendLock.lock() for observer in observers { observer.action(event) } let shouldInterrupt = !event.isTerminating && interrupted.value if shouldInterrupt { self.interrupt() } sendLock.unlock() if event.isTerminating || shouldInterrupt { // Dispose only after notifying observers, so disposal logic // is consistently the last thing to run. generatorDisposable.dispose() } } } } generatorDisposable.innerDisposable = generator(observer) } /// A Signal that never sends any events to its observers. public static var never: Signal { return self.init { _ in nil } } /// A Signal that completes immediately without emitting any value. public static var empty: Signal { return self.init { observer in observer.sendCompleted() return nil } } /// Creates a Signal that will be controlled by sending events to the given /// observer. /// /// The Signal will remain alive until a terminating event is sent to the /// observer. public static func pipe() -> (Signal, Observer) { var observer: Observer! let signal = self.init { innerObserver in observer = innerObserver return nil } return (signal, observer) } /// Interrupts all observers and terminates the stream. private func interrupt() { if let observers = self.atomicObservers.swap(nil) { for observer in observers { observer.sendInterrupted() } } } /// Observes the Signal by sending any future events to the given observer. If /// the Signal has already terminated, the observer will immediately receive an /// `Interrupted` event. /// /// Returns a Disposable which can be used to disconnect the observer. Disposing /// of the Disposable will have no effect on the Signal itself. public func observe(observer: Observer) -> Disposable? { var token: RemovalToken? atomicObservers.modify { observers in guard let immutableObservers = observers else { return nil } var mutableObservers = immutableObservers token = mutableObservers.insert(observer) return mutableObservers } if let token = token { return ActionDisposable { [weak self] in self?.atomicObservers.modify { observers in guard let immutableObservers = observers else { return nil } var mutableObservers = immutableObservers mutableObservers.removeValueForToken(token) return mutableObservers } } } else { observer.sendInterrupted() return nil } } } public protocol SignalType { /// The type of values being sent on the signal. typealias Value /// The type of error that can occur on the signal. If errors aren't possible /// then `NoError` can be used. typealias Error: ErrorType /// Extracts a signal from the receiver. var signal: Signal { get } /// Observes the Signal by sending any future events to the given observer. func observe(observer: Signal.Observer) -> Disposable? } extension Signal: SignalType { public var signal: Signal { return self } } extension SignalType { /// Convenience override for observe(_:) to allow trailing-closure style /// invocations. public func observe(action: Signal.Observer.Action) -> Disposable? { return observe(Observer(action)) } /// Observes the Signal by invoking the given callback when `next` events are /// received. /// /// Returns a Disposable which can be used to stop the invocation of the /// callbacks. Disposing of the Disposable will have no effect on the Signal /// itself. public func observeNext(next: Value -> ()) -> Disposable? { return observe(Observer(next: next)) } /// Observes the Signal by invoking the given callback when a `completed` event is /// received. /// /// Returns a Disposable which can be used to stop the invocation of the /// callback. Disposing of the Disposable will have no effect on the Signal /// itself. public func observeCompleted(completed: () -> ()) -> Disposable? { return observe(Observer(completed: completed)) } /// Observes the Signal by invoking the given callback when a `failed` event is /// received. /// /// Returns a Disposable which can be used to stop the invocation of the /// callback. Disposing of the Disposable will have no effect on the Signal /// itself. public func observeFailed(error: Error -> ()) -> Disposable? { return observe(Observer(failed: error)) } /// Observes the Signal by invoking the given callback when an `interrupted` event is /// received. If the Signal has already terminated, the callback will be invoked /// immediately. /// /// Returns a Disposable which can be used to stop the invocation of the /// callback. Disposing of the Disposable will have no effect on the Signal /// itself. public func observeInterrupted(interrupted: () -> ()) -> Disposable? { return observe(Observer(interrupted: interrupted)) } /// Maps each value in the signal to a new value. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func map(transform: Value -> U) -> Signal { return Signal { observer in return self.observe { event in observer.action(event.map(transform)) } } } /// Maps errors in the signal to a new error. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func mapError(transform: Error -> F) -> Signal { return Signal { observer in return self.observe { event in observer.action(event.mapError(transform)) } } } /// Preserves only the values of the signal that pass the given predicate. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func filter(predicate: Value -> Bool) -> Signal { return Signal { observer in return self.observe { (event: Event) -> () in if case let .Next(value) = event { if predicate(value) { observer.sendNext(value) } } else { observer.action(event) } } } } } extension SignalType where Value: OptionalType { /// Unwraps non-`nil` values and forwards them on the returned signal, `nil` /// values are dropped. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func ignoreNil() -> Signal { return filter { $0.optional != nil }.map { $0.optional! } } } extension SignalType { /// Returns a signal that will yield the first `count` values from `self` @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func take(count: Int) -> Signal { precondition(count >= 0) return Signal { observer in if count == 0 { observer.sendCompleted() return nil } var taken = 0 return self.observe { event in if case let .Next(value) = event { if taken < count { taken++ observer.sendNext(value) } if taken == count { observer.sendCompleted() } } else { observer.action(event) } } } } } /// A reference type which wraps an array to avoid copying it for performance and /// memory usage optimization. private final class CollectState { var values: [Value] = [] func append(value: Value) -> Self { values.append(value) return self } } extension SignalType { /// Returns a signal that will yield an array of values when `self` completes. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func collect() -> Signal<[Value], Error> { return self .reduce(CollectState()) { $0.append($1) } .map { $0.values } } /// Forwards all events onto the given scheduler, instead of whichever /// scheduler they originally arrived upon. public func observeOn(scheduler: SchedulerType) -> Signal { return Signal { observer in return self.observe { event in scheduler.schedule { observer.action(event) } } } } } private final class CombineLatestState { var latestValue: Value? var completed = false } extension SignalType { private func observeWithStates(signalState: CombineLatestState, _ otherState: CombineLatestState, _ lock: NSLock, _ onBothNext: () -> (), _ onFailed: Error -> (), _ onBothCompleted: () -> (), _ onInterrupted: () -> ()) -> Disposable? { return self.observe { event in switch event { case let .Next(value): lock.lock() signalState.latestValue = value if otherState.latestValue != nil { onBothNext() } lock.unlock() case let .Failed(error): onFailed(error) case .Completed: lock.lock() signalState.completed = true if otherState.completed { onBothCompleted() } lock.unlock() case .Interrupted: onInterrupted() } } } /// Combines the latest value of the receiver with the latest value from /// the given signal. /// /// The returned signal will not send a value until both inputs have sent /// at least one value each. If either signal is interrupted, the returned signal /// will also be interrupted. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func combineLatestWith(otherSignal: Signal) -> Signal<(Value, U), Error> { return Signal { observer in let lock = NSLock() lock.name = "org.reactivecocoa.ReactiveCocoa.combineLatestWith" let signalState = CombineLatestState() let otherState = CombineLatestState() let onBothNext = { () -> () in observer.sendNext((signalState.latestValue!, otherState.latestValue!)) } let onFailed = observer.sendFailed let onBothCompleted = observer.sendCompleted let onInterrupted = observer.sendInterrupted let disposable = CompositeDisposable() disposable += self.observeWithStates(signalState, otherState, lock, onBothNext, onFailed, onBothCompleted, onInterrupted) disposable += otherSignal.observeWithStates(otherState, signalState, lock, onBothNext, onFailed, onBothCompleted, onInterrupted) return disposable } } /// Delays `Next` and `Completed` events by the given interval, forwarding /// them on the given scheduler. /// /// `Failed` and `Interrupted` events are always scheduled immediately. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func delay(interval: NSTimeInterval, onScheduler scheduler: DateSchedulerType) -> Signal { precondition(interval >= 0) return Signal { observer in return self.observe { event in switch event { case .Failed, .Interrupted: scheduler.schedule { observer.action(event) } default: let date = scheduler.currentDate.dateByAddingTimeInterval(interval) scheduler.scheduleAfter(date) { observer.action(event) } } } } } /// Returns a signal that will skip the first `count` values, then forward /// everything afterward. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func skip(count: Int) -> Signal { precondition(count >= 0) if count == 0 { return signal } return Signal { observer in var skipped = 0 return self.observe { event in if case .Next = event where skipped < count { skipped++ } else { observer.action(event) } } } } /// Treats all Events from `self` as plain values, allowing them to be manipulated /// just like any other value. /// /// In other words, this brings Events “into the monad.” /// /// When a Completed or Failed event is received, the resulting signal will send /// the Event itself and then complete. When an Interrupted event is received, /// the resulting signal will send the Event itself and then interrupt. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func materialize() -> Signal, NoError> { return Signal { observer in return self.observe { event in observer.sendNext(event) switch event { case .Interrupted: observer.sendInterrupted() case .Completed, .Failed: observer.sendCompleted() case .Next: break } } } } } extension SignalType where Value: EventType, Error == NoError { /// The inverse of materialize(), this will translate a signal of `Event` /// _values_ into a signal of those events themselves. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func dematerialize() -> Signal { return Signal { observer in return self.observe { event in switch event { case let .Next(innerEvent): observer.action(innerEvent.event) case .Failed: fatalError("NoError is impossible to construct") case .Completed: observer.sendCompleted() case .Interrupted: observer.sendInterrupted() } } } } } extension SignalType { /// Injects side effects to be performed upon the specified signal events. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func on(event event: (Event -> ())? = nil, failed: (Error -> ())? = nil, completed: (() -> ())? = nil, interrupted: (() -> ())? = nil, terminated: (() -> ())? = nil, disposed: (() -> ())? = nil, next: (Value -> ())? = nil) -> Signal { return Signal { observer in let disposable = CompositeDisposable() _ = disposed.map(disposable.addDisposable) disposable += signal.observe { receivedEvent in event?(receivedEvent) switch receivedEvent { case let .Next(value): next?(value) case let .Failed(error): failed?(error) case .Completed: completed?() case .Interrupted: interrupted?() } if receivedEvent.isTerminating { terminated?() } observer.action(receivedEvent) } return disposable } } } private struct SampleState { var latestValue: Value? = nil var signalCompleted: Bool = false var samplerCompleted: Bool = false } extension SignalType { /// Forwards the latest value from `signal` whenever `sampler` sends a Next /// event. /// /// If `sampler` fires before a value has been observed on `signal`, nothing /// happens. /// /// Returns a signal that will send values from `signal`, sampled (possibly /// multiple times) by `sampler`, then complete once both input signals have /// completed, or interrupt if either input signal is interrupted. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func sampleOn(sampler: Signal<(), NoError>) -> Signal { return Signal { observer in let state = Atomic(SampleState()) let disposable = CompositeDisposable() disposable += self.observe { event in switch event { case let .Next(value): state.modify { st in var mutableSt = st mutableSt.latestValue = value return mutableSt } case let .Failed(error): observer.sendFailed(error) case .Completed: let oldState = state.modify { st in var mutableSt = st mutableSt.signalCompleted = true return mutableSt } if oldState.samplerCompleted { observer.sendCompleted() } case .Interrupted: observer.sendInterrupted() } } disposable += sampler.observe { event in switch event { case .Next: if let value = state.value.latestValue { observer.sendNext(value) } case .Completed: let oldState = state.modify { st in var mutableSt = st mutableSt.samplerCompleted = true return mutableSt } if oldState.signalCompleted { observer.sendCompleted() } case .Interrupted: observer.sendInterrupted() default: break } } return disposable } } /// Forwards events from `self` until `trigger` sends a Next or Completed /// event, at which point the returned signal will complete. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func takeUntil(trigger: Signal<(), NoError>) -> Signal { return Signal { observer in let disposable = CompositeDisposable() disposable += self.observe(observer) disposable += trigger.observe { event in switch event { case .Next, .Completed: observer.sendCompleted() case .Failed, .Interrupted: break } } return disposable } } /// Does not forward any values from `self` until `trigger` sends a Next or /// Completed event, at which point the returned signal behaves exactly like /// `signal`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func skipUntil(trigger: Signal<(), NoError>) -> Signal { return Signal { observer in let disposable = SerialDisposable() disposable.innerDisposable = trigger.observe { event in switch event { case .Next, .Completed: disposable.innerDisposable = self.observe(observer) case .Failed, .Interrupted: break } } return disposable } } /// Forwards events from `self` with history: values of the returned signal /// are a tuple whose first member is the previous value and whose second member /// is the current value. `initial` is supplied as the first member when `self` /// sends its first value. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func combinePrevious(initial: Value) -> Signal<(Value, Value), Error> { return scan((initial, initial)) { previousCombinedValues, newValue in return (previousCombinedValues.1, newValue) } } /// Like `scan`, but sends only the final value and then immediately completes. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func reduce(initial: U, _ combine: (U, Value) -> U) -> Signal { // We need to handle the special case in which `signal` sends no values. // We'll do that by sending `initial` on the output signal (before taking // the last value). let (scannedSignalWithInitialValue, outputSignalObserver) = Signal.pipe() let outputSignal = scannedSignalWithInitialValue.takeLast(1) // Now that we've got takeLast() listening to the piped signal, send that initial value. outputSignalObserver.sendNext(initial) // Pipe the scanned input signal into the output signal. scan(initial, combine).observe(outputSignalObserver) return outputSignal } /// Aggregates `selfs`'s values into a single combined value. When `self` emits /// its first value, `combine` is invoked with `initial` as the first argument and /// that emitted value as the second argument. The result is emitted from the /// signal returned from `scan`. That result is then passed to `combine` as the /// first argument when the next value is emitted, and so on. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func scan(initial: U, _ combine: (U, Value) -> U) -> Signal { return Signal { observer in var accumulator = initial return self.observe { event in observer.action(event.map { value in accumulator = combine(accumulator, value) return accumulator }) } } } } extension SignalType where Value: Equatable { /// Forwards only those values from `self` which are not duplicates of the /// immedately preceding value. The first value is always forwarded. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func skipRepeats() -> Signal { return skipRepeats(==) } } extension SignalType { /// Forwards only those values from `self` which do not pass `isRepeat` with /// respect to the previous value. The first value is always forwarded. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func skipRepeats(isRepeat: (Value, Value) -> Bool) -> Signal { return self .map(Optional.init) .combinePrevious(nil) .filter { a, b in if let a = a, b = b where isRepeat(a, b) { return false } else { return true } } .map { $0.1! } } /// Does not forward any values from `self` until `predicate` returns false, /// at which point the returned signal behaves exactly like `signal`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func skipWhile(predicate: Value -> Bool) -> Signal { return Signal { observer in var shouldSkip = true return self.observe { event in switch event { case let .Next(value): shouldSkip = shouldSkip && predicate(value) if !shouldSkip { fallthrough } default: observer.action(event) } } } } /// Forwards events from `self` until `replacement` begins sending events. /// /// Returns a signal which passes through `Next`, `Failed`, and `Interrupted` /// events from `signal` until `replacement` sends an event, at which point the /// returned signal will send that event and switch to passing through events /// from `replacement` instead, regardless of whether `self` has sent events /// already. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func takeUntilReplacement(replacement: Signal) -> Signal { return Signal { observer in let disposable = CompositeDisposable() let signalDisposable = self.observe { event in switch event { case .Completed: break case .Next, .Failed, .Interrupted: observer.action(event) } } disposable += signalDisposable disposable += replacement.observe { event in signalDisposable?.dispose() observer.action(event) } return disposable } } /// Waits until `self` completes and then forwards the final `count` values /// on the returned signal. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func takeLast(count: Int) -> Signal { return Signal { observer in var buffer: [Value] = [] buffer.reserveCapacity(count) return self.observe { event in switch event { case let .Next(value): // To avoid exceeding the reserved capacity of the buffer, we remove then add. // Remove elements until we have room to add one more. while (buffer.count + 1) > count { buffer.removeAtIndex(0) } buffer.append(value) case let .Failed(error): observer.sendFailed(error) case .Completed: buffer.forEach(observer.sendNext) observer.sendCompleted() case .Interrupted: observer.sendInterrupted() } } } } /// Forwards any values from `self` until `predicate` returns false, /// at which point the returned signal will complete. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func takeWhile(predicate: Value -> Bool) -> Signal { return Signal { observer in return self.observe { event in if case let .Next(value) = event where !predicate(value) { observer.sendCompleted() } else { observer.action(event) } } } } } private struct ZipState { var values: [Value] = [] var completed = false var isFinished: Bool { return values.isEmpty && completed } } extension SignalType { /// Zips elements of two signals into pairs. The elements of any Nth pair /// are the Nth elements of the two input signals. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func zipWith(otherSignal: Signal) -> Signal<(Value, U), Error> { return Signal { observer in let states = Atomic(ZipState(), ZipState()) let disposable = CompositeDisposable() let flush = { () -> () in var originalStates: (ZipState, ZipState)! states.modify { states in originalStates = states var updatedStates = states let extractCount = min(states.0.values.count, states.1.values.count) updatedStates.0.values.removeRange(0 ..< extractCount) updatedStates.1.values.removeRange(0 ..< extractCount) return updatedStates } while !originalStates.0.values.isEmpty && !originalStates.1.values.isEmpty { let left = originalStates.0.values.removeAtIndex(0) let right = originalStates.1.values.removeAtIndex(0) observer.sendNext((left, right)) } if originalStates.0.isFinished || originalStates.1.isFinished { observer.sendCompleted() } } let onFailed = observer.sendFailed let onInterrupted = observer.sendInterrupted disposable += self.observe { event in switch event { case let .Next(value): states.modify { states in var mutableStates = states mutableStates.0.values.append(value) return mutableStates } flush() case let .Failed(error): onFailed(error) case .Completed: states.modify { states in var mutableStates = states mutableStates.0.completed = true return mutableStates } flush() case .Interrupted: onInterrupted() } } disposable += otherSignal.observe { event in switch event { case let .Next(value): states.modify { states in var mutableStates = states mutableStates.1.values.append(value) return mutableStates } flush() case let .Failed(error): onFailed(error) case .Completed: states.modify { states in var mutableStates = states mutableStates.1.completed = true return mutableStates } flush() case .Interrupted: onInterrupted() } } return disposable } } /// Applies `operation` to values from `self` with `Success`ful results /// forwarded on the returned signal and `Failure`s sent as `Failed` events. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func attempt(operation: Value -> Result<(), Error>) -> Signal { return attemptMap { value in return operation(value).map { return value } } } /// Applies `operation` to values from `self` with `Success`ful results mapped /// on the returned signal and `Failure`s sent as `Failed` events. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func attemptMap(operation: Value -> Result) -> Signal { return Signal { observer in self.observe { event in switch event { case let .Next(value): operation(value).analysis( ifSuccess: observer.sendNext, ifFailure: observer.sendFailed ) case let .Failed(error): observer.sendFailed(error) case .Completed: observer.sendCompleted() case .Interrupted: observer.sendInterrupted() } } } } /// Throttle values sent by the receiver, so that at least `interval` /// seconds pass between each, then forwards them on the given scheduler. /// /// If multiple values are received before the interval has elapsed, the /// latest value is the one that will be passed on. /// /// If the input signal terminates while a value is being throttled, that value /// will be discarded and the returned signal will terminate immediately. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func throttle(interval: NSTimeInterval, onScheduler scheduler: DateSchedulerType) -> Signal { precondition(interval >= 0) return Signal { observer in let state: Atomic> = Atomic(ThrottleState()) let schedulerDisposable = SerialDisposable() let disposable = CompositeDisposable() disposable.addDisposable(schedulerDisposable) disposable += self.observe { event in if case let .Next(value) = event { var scheduleDate: NSDate! state.modify { state in var mutableState = state mutableState.pendingValue = value let proposedScheduleDate = mutableState.previousDate?.dateByAddingTimeInterval(interval) ?? scheduler.currentDate scheduleDate = proposedScheduleDate.laterDate(scheduler.currentDate) return mutableState } schedulerDisposable.innerDisposable = scheduler.scheduleAfter(scheduleDate) { let previousState = state.modify { state in var mutableState = state if mutableState.pendingValue != nil { mutableState.pendingValue = nil mutableState.previousDate = scheduleDate } return mutableState } if let pendingValue = previousState.pendingValue { observer.sendNext(pendingValue) } } } else { schedulerDisposable.innerDisposable = scheduler.schedule { observer.action(event) } } } return disposable } } } private struct ThrottleState { var previousDate: NSDate? = nil var pendingValue: Value? = nil } /// Combines the values of all the given signals, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func combineLatest(a: Signal, _ b: Signal) -> Signal<(A, B), Error> { return a.combineLatestWith(b) } /// Combines the values of all the given signals, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func combineLatest(a: Signal, _ b: Signal, _ c: Signal) -> Signal<(A, B, C), Error> { return combineLatest(a, b) .combineLatestWith(c) .map(repack) } /// Combines the values of all the given signals, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func combineLatest(a: Signal, _ b: Signal, _ c: Signal, _ d: Signal) -> Signal<(A, B, C, D), Error> { return combineLatest(a, b, c) .combineLatestWith(d) .map(repack) } /// Combines the values of all the given signals, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func combineLatest(a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal) -> Signal<(A, B, C, D, E), Error> { return combineLatest(a, b, c, d) .combineLatestWith(e) .map(repack) } /// Combines the values of all the given signals, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func combineLatest(a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal) -> Signal<(A, B, C, D, E, F), Error> { return combineLatest(a, b, c, d, e) .combineLatestWith(f) .map(repack) } /// Combines the values of all the given signals, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func combineLatest(a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal) -> Signal<(A, B, C, D, E, F, G), Error> { return combineLatest(a, b, c, d, e, f) .combineLatestWith(g) .map(repack) } /// Combines the values of all the given signals, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func combineLatest(a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal, _ h: Signal) -> Signal<(A, B, C, D, E, F, G, H), Error> { return combineLatest(a, b, c, d, e, f, g) .combineLatestWith(h) .map(repack) } /// Combines the values of all the given signals, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func combineLatest(a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal, _ h: Signal, _ i: Signal) -> Signal<(A, B, C, D, E, F, G, H, I), Error> { return combineLatest(a, b, c, d, e, f, g, h) .combineLatestWith(i) .map(repack) } /// Combines the values of all the given signals, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func combineLatest(a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal, _ h: Signal, _ i: Signal, _ j: Signal) -> Signal<(A, B, C, D, E, F, G, H, I, J), Error> { return combineLatest(a, b, c, d, e, f, g, h, i) .combineLatestWith(j) .map(repack) } /// Combines the values of all the given signals, in the manner described by /// `combineLatestWith`. No events will be sent if the sequence is empty. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func combineLatest>(signals: S) -> Signal<[Value], Error> { var generator = signals.generate() if let first = generator.next() { let initial = first.map { [$0] } return GeneratorSequence(generator).reduce(initial) { signal, next in signal.combineLatestWith(next).map { $0.0 + [$0.1] } } } return .never } /// Zips the values of all the given signals, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func zip(a: Signal, _ b: Signal) -> Signal<(A, B), Error> { return a.zipWith(b) } /// Zips the values of all the given signals, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func zip(a: Signal, _ b: Signal, _ c: Signal) -> Signal<(A, B, C), Error> { return zip(a, b) .zipWith(c) .map(repack) } /// Zips the values of all the given signals, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func zip(a: Signal, _ b: Signal, _ c: Signal, _ d: Signal) -> Signal<(A, B, C, D), Error> { return zip(a, b, c) .zipWith(d) .map(repack) } /// Zips the values of all the given signals, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func zip(a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal) -> Signal<(A, B, C, D, E), Error> { return zip(a, b, c, d) .zipWith(e) .map(repack) } /// Zips the values of all the given signals, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func zip(a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal) -> Signal<(A, B, C, D, E, F), Error> { return zip(a, b, c, d, e) .zipWith(f) .map(repack) } /// Zips the values of all the given signals, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func zip(a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal) -> Signal<(A, B, C, D, E, F, G), Error> { return zip(a, b, c, d, e, f) .zipWith(g) .map(repack) } /// Zips the values of all the given signals, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func zip(a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal, _ h: Signal) -> Signal<(A, B, C, D, E, F, G, H), Error> { return zip(a, b, c, d, e, f, g) .zipWith(h) .map(repack) } /// Zips the values of all the given signals, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func zip(a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal, _ h: Signal, _ i: Signal) -> Signal<(A, B, C, D, E, F, G, H, I), Error> { return zip(a, b, c, d, e, f, g, h) .zipWith(i) .map(repack) } /// Zips the values of all the given signals, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func zip(a: Signal, _ b: Signal, _ c: Signal, _ d: Signal, _ e: Signal, _ f: Signal, _ g: Signal, _ h: Signal, _ i: Signal, _ j: Signal) -> Signal<(A, B, C, D, E, F, G, H, I, J), Error> { return zip(a, b, c, d, e, f, g, h, i) .zipWith(j) .map(repack) } /// Zips the values of all the given signals, in the manner described by /// `zipWith`. No events will be sent if the sequence is empty. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func zip>(signals: S) -> Signal<[Value], Error> { var generator = signals.generate() if let first = generator.next() { let initial = first.map { [$0] } return GeneratorSequence(generator).reduce(initial) { signal, next in signal.zipWith(next).map { $0.0 + [$0.1] } } } return .never } extension SignalType { /// Forwards events from `self` until `interval`. Then if signal isn't completed yet, /// fails with `error` on `scheduler`. /// /// If the interval is 0, the timeout will be scheduled immediately. The signal /// must complete synchronously (or on a faster scheduler) to avoid the timeout. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func timeoutWithError(error: Error, afterInterval interval: NSTimeInterval, onScheduler scheduler: DateSchedulerType) -> Signal { precondition(interval >= 0) return Signal { observer in let disposable = CompositeDisposable() let date = scheduler.currentDate.dateByAddingTimeInterval(interval) disposable += scheduler.scheduleAfter(date) { observer.sendFailed(error) } disposable += self.observe(observer) return disposable } } } extension SignalType where Error == NoError { /// Promotes a signal that does not generate failures into one that can. /// /// This does not actually cause failures to be generated for the given signal, /// but makes it easier to combine with other signals that may fail; for /// example, with operators like `combineLatestWith`, `zipWith`, `flatten`, etc. @warn_unused_result(message="Did you forget to call `observe` on the signal?") public func promoteErrors(_: F.Type) -> Signal { return Signal { observer in return self.observe { event in switch event { case let .Next(value): observer.sendNext(value) case .Failed: fatalError("NoError is impossible to construct") case .Completed: observer.sendCompleted() case .Interrupted: observer.sendInterrupted() } } } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Swift/SignalProducer.swift ================================================ import Foundation import Result /// A SignalProducer creates Signals that can produce values of type `Value` and/or /// fail with errors of type `Error`. If no failure should be possible, NoError /// can be specified for `Error`. /// /// SignalProducers can be used to represent operations or tasks, like network /// requests, where each invocation of start() will create a new underlying /// operation. This ensures that consumers will receive the results, versus a /// plain Signal, where the results might be sent before any observers are /// attached. /// /// Because of the behavior of start(), different Signals created from the /// producer may see a different version of Events. The Events may arrive in a /// different order between Signals, or the stream might be completely /// different! public struct SignalProducer { public typealias ProducedSignal = Signal private let startHandler: (Signal.Observer, CompositeDisposable) -> () /// Initializes a SignalProducer that will emit the same events as the given signal. /// /// If the Disposable returned from start() is disposed or a terminating /// event is sent to the observer, the given signal will be /// disposed. public init(signal: S) { self.init { observer, disposable in disposable += signal.observe(observer) } } /// Initializes a SignalProducer that will invoke the given closure once /// for each invocation of start(). /// /// The events that the closure puts into the given observer will become /// the events sent by the started Signal to its observers. /// /// If the Disposable returned from start() is disposed or a terminating /// event is sent to the observer, the given CompositeDisposable will be /// disposed, at which point work should be interrupted and any temporary /// resources cleaned up. public init(_ startHandler: (Signal.Observer, CompositeDisposable) -> ()) { self.startHandler = startHandler } /// Creates a producer for a Signal that will immediately send one value /// then complete. public init(value: Value) { self.init { observer, disposable in observer.sendNext(value) observer.sendCompleted() } } /// Creates a producer for a Signal that will immediately fail with the /// given error. public init(error: Error) { self.init { observer, disposable in observer.sendFailed(error) } } /// Creates a producer for a Signal that will immediately send one value /// then complete, or immediately fail, depending on the given Result. public init(result: Result) { switch result { case let .Success(value): self.init(value: value) case let .Failure(error): self.init(error: error) } } /// Creates a producer for a Signal that will immediately send the values /// from the given sequence, then complete. public init(values: S) { self.init { observer, disposable in for value in values { observer.sendNext(value) if disposable.disposed { break } } observer.sendCompleted() } } /// A producer for a Signal that will immediately complete without sending /// any values. public static var empty: SignalProducer { return self.init { observer, disposable in observer.sendCompleted() } } /// A producer for a Signal that never sends any events to its observers. public static var never: SignalProducer { return self.init { _ in return } } /// Creates a queue for events that replays them when new signals are /// created from the returned producer. /// /// When values are put into the returned observer (observer), they will be /// added to an internal buffer. If the buffer is already at capacity, /// the earliest (oldest) value will be dropped to make room for the new /// value. /// /// Signals created from the returned producer will stay alive until a /// terminating event is added to the queue. If the queue does not contain /// such an event when the Signal is started, all values sent to the /// returned observer will be automatically forwarded to the Signal’s /// observers until a terminating event is received. /// /// After a terminating event has been added to the queue, the observer /// will not add any further events. This _does not_ count against the /// value capacity so no buffered values will be dropped on termination. public static func buffer(capacity: Int) -> (SignalProducer, Signal.Observer) { precondition(capacity >= 0, "Invalid capacity: \(capacity)") // This is effectively used as a synchronous mutex, but permitting // limited recursive locking (see below). // // The queue is a "variable" just so we can use its address as the key // and the value for dispatch_queue_set_specific(). var queue = dispatch_queue_create("org.reactivecocoa.ReactiveCocoa.SignalProducer.buffer", DISPATCH_QUEUE_SERIAL) dispatch_queue_set_specific(queue, &queue, &queue, nil) // Used as an atomic variable so we can remove observers without needing // to run on the queue. let state: Atomic> = Atomic(BufferState()) let producer = self.init { observer, disposable in // Assigned to when replay() is invoked synchronously below. var token: RemovalToken? let replay: () -> () = { let originalState = state.modify { state in var mutableState = state token = mutableState.observers?.insert(observer) return mutableState } originalState.values.forEach(observer.sendNext) if let terminationEvent = originalState.terminationEvent { observer.action(terminationEvent) } } // Prevent other threads from sending events while we're replaying, // but don't deadlock if we're replaying in response to a buffer // event observed elsewhere. // // In other words, this permits limited signal recursion for the // specific case of replaying past events. if dispatch_get_specific(&queue) != nil { replay() } else { dispatch_sync(queue, replay) } if let token = token { disposable.addDisposable { state.modify { state in var mutableState = state mutableState.observers?.removeValueForToken(token) return mutableState } } } } let bufferingObserver: Signal.Observer = Observer { event in // Send serially with respect to other senders, and never while // another thread is in the process of replaying. dispatch_sync(queue) { let originalState = state.modify { state in var mutableState = state if let value = event.value { mutableState.addValue(value, upToCapacity: capacity) } else { // Disconnect all observers and prevent future // attachments. mutableState.terminationEvent = event mutableState.observers = nil } return mutableState } if let observers = originalState.observers { for observer in observers { observer.action(event) } } } } return (producer, bufferingObserver) } /// Creates a SignalProducer that will attempt the given operation once for /// each invocation of start(). /// /// Upon success, the started signal will send the resulting value then /// complete. Upon failure, the started signal will fail with the error that /// occurred. public static func attempt(operation: () -> Result) -> SignalProducer { return self.init { observer, disposable in operation().analysis(ifSuccess: { value in observer.sendNext(value) observer.sendCompleted() }, ifFailure: { error in observer.sendFailed(error) }) } } /// Creates a Signal from the producer, passes it into the given closure, /// then starts sending events on the Signal when the closure has returned. /// /// The closure will also receive a disposable which can be used to /// interrupt the work associated with the signal and immediately send an /// `Interrupted` event. public func startWithSignal(@noescape setUp: (Signal, Disposable) -> ()) { let (signal, observer) = Signal.pipe() // Disposes of the work associated with the SignalProducer and any // upstream producers. let producerDisposable = CompositeDisposable() // Directly disposed of when start() or startWithSignal() is disposed. let cancelDisposable = ActionDisposable { observer.sendInterrupted() producerDisposable.dispose() } setUp(signal, cancelDisposable) if cancelDisposable.disposed { return } let wrapperObserver: Signal.Observer = Observer { event in observer.action(event) if event.isTerminating { // Dispose only after notifying the Signal, so disposal // logic is consistently the last thing to run. producerDisposable.dispose() } } startHandler(wrapperObserver, producerDisposable) } } private struct BufferState { // All values in the buffer. var values: [Value] = [] // Any terminating event sent to the buffer. // // This will be nil if termination has not occurred. var terminationEvent: Event? // The observers currently attached to the buffered producer, or nil if the // producer was terminated. var observers: Bag.Observer>? = Bag() // Appends a new value to the buffer, trimming it down to the given capacity // if necessary. mutating func addValue(value: Value, upToCapacity capacity: Int) { values.append(value) let overflow = values.count - capacity if overflow > 0 { values.removeRange(0.. { get } /// Creates a Signal from the producer, passes it into the given closure, /// then starts sending events on the Signal when the closure has returned. func startWithSignal(@noescape setUp: (Signal, Disposable) -> ()) } extension SignalProducer: SignalProducerType { public var producer: SignalProducer { return self } } extension SignalProducerType { /// Creates a Signal from the producer, then attaches the given observer to /// the Signal as an observer. /// /// Returns a Disposable which can be used to interrupt the work associated /// with the signal and immediately send an `Interrupted` event. public func start(observer: Signal.Observer = Signal.Observer()) -> Disposable { var disposable: Disposable! startWithSignal { signal, innerDisposable in signal.observe(observer) disposable = innerDisposable } return disposable } /// Convenience override for start(_:) to allow trailing-closure style /// invocations. public func start(observerAction: Signal.Observer.Action) -> Disposable { return start(Observer(observerAction)) } /// Creates a Signal from the producer, then adds exactly one observer to /// the Signal, which will invoke the given callback when `next` events are /// received. /// /// Returns a Disposable which can be used to interrupt the work associated /// with the Signal, and prevent any future callbacks from being invoked. public func startWithNext(next: Value -> ()) -> Disposable { return start(Observer(next: next)) } /// Creates a Signal from the producer, then adds exactly one observer to /// the Signal, which will invoke the given callback when a `completed` event is /// received. /// /// Returns a Disposable which can be used to interrupt the work associated /// with the Signal. public func startWithCompleted(completed: () -> ()) -> Disposable { return start(Observer(completed: completed)) } /// Creates a Signal from the producer, then adds exactly one observer to /// the Signal, which will invoke the given callback when a `failed` event is /// received. /// /// Returns a Disposable which can be used to interrupt the work associated /// with the Signal. public func startWithFailed(failed: Error -> ()) -> Disposable { return start(Observer(failed: failed)) } /// Creates a Signal from the producer, then adds exactly one observer to /// the Signal, which will invoke the given callback when an `interrupted` event is /// received. /// /// Returns a Disposable which can be used to interrupt the work associated /// with the Signal. public func startWithInterrupted(interrupted: () -> ()) -> Disposable { return start(Observer(interrupted: interrupted)) } /// Lifts an unary Signal operator to operate upon SignalProducers instead. /// /// In other words, this will create a new SignalProducer which will apply /// the given Signal operator to _every_ created Signal, just as if the /// operator had been applied to each Signal yielded from start(). @warn_unused_result(message="Did you forget to call `start` on the producer?") public func lift(transform: Signal -> Signal) -> SignalProducer { return SignalProducer { observer, outerDisposable in self.startWithSignal { signal, innerDisposable in outerDisposable.addDisposable(innerDisposable) transform(signal).observe(observer) } } } /// Lifts a binary Signal operator to operate upon SignalProducers instead. /// /// In other words, this will create a new SignalProducer which will apply /// the given Signal operator to _every_ Signal created from the two /// producers, just as if the operator had been applied to each Signal /// yielded from start(). /// /// Note: starting the returned producer will start the receiver of the operator, /// which may not be adviseable for some operators. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func lift(transform: Signal -> Signal -> Signal) -> SignalProducer -> SignalProducer { return liftRight(transform) } /// Right-associative lifting of a binary signal operator over producers. That /// is, the argument producer will be started before the receiver. When both /// producers are synchronous this order can be important depending on the operator /// to generate correct results. @warn_unused_result(message="Did you forget to call `start` on the producer?") private func liftRight(transform: Signal -> Signal -> Signal) -> SignalProducer -> SignalProducer { return { otherProducer in return SignalProducer { observer, outerDisposable in self.startWithSignal { signal, disposable in outerDisposable.addDisposable(disposable) otherProducer.startWithSignal { otherSignal, otherDisposable in outerDisposable.addDisposable(otherDisposable) transform(signal)(otherSignal).observe(observer) } } } } } /// Left-associative lifting of a binary signal operator over producers. That /// is, the receiver will be started before the argument producer. When both /// producers are synchronous this order can be important depending on the operator /// to generate correct results. @warn_unused_result(message="Did you forget to call `start` on the producer?") private func liftLeft(transform: Signal -> Signal -> Signal) -> SignalProducer -> SignalProducer { return { otherProducer in return SignalProducer { observer, outerDisposable in otherProducer.startWithSignal { otherSignal, otherDisposable in outerDisposable.addDisposable(otherDisposable) self.startWithSignal { signal, disposable in outerDisposable.addDisposable(disposable) transform(signal)(otherSignal).observe(observer) } } } } } /// Lifts a binary Signal operator to operate upon a Signal and a SignalProducer instead. /// /// In other words, this will create a new SignalProducer which will apply /// the given Signal operator to _every_ Signal created from the two /// producers, just as if the operator had been applied to each Signal /// yielded from start(). @warn_unused_result(message="Did you forget to call `start` on the producer?") public func lift(transform: Signal -> Signal -> Signal) -> Signal -> SignalProducer { return { otherSignal in return SignalProducer { observer, outerDisposable in self.startWithSignal { signal, disposable in outerDisposable += disposable outerDisposable += transform(signal)(otherSignal).observe(observer) } } } } /// Maps each value in the producer to a new value. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func map(transform: Value -> U) -> SignalProducer { return lift { $0.map(transform) } } /// Maps errors in the producer to a new error. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func mapError(transform: Error -> F) -> SignalProducer { return lift { $0.mapError(transform) } } /// Preserves only the values of the producer that pass the given predicate. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func filter(predicate: Value -> Bool) -> SignalProducer { return lift { $0.filter(predicate) } } /// Returns a producer that will yield the first `count` values from the /// input producer. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func take(count: Int) -> SignalProducer { return lift { $0.take(count) } } /// Returns a signal that will yield an array of values when `signal` completes. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func collect() -> SignalProducer<[Value], Error> { return lift { $0.collect() } } /// Forwards all events onto the given scheduler, instead of whichever /// scheduler they originally arrived upon. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func observeOn(scheduler: SchedulerType) -> SignalProducer { return lift { $0.observeOn(scheduler) } } /// Combines the latest value of the receiver with the latest value from /// the given producer. /// /// The returned producer will not send a value until both inputs have sent at /// least one value each. If either producer is interrupted, the returned producer /// will also be interrupted. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func combineLatestWith(otherProducer: SignalProducer) -> SignalProducer<(Value, U), Error> { return liftRight(Signal.combineLatestWith)(otherProducer) } /// Combines the latest value of the receiver with the latest value from /// the given signal. /// /// The returned producer will not send a value until both inputs have sent at /// least one value each. If either input is interrupted, the returned producer /// will also be interrupted. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func combineLatestWith(otherSignal: Signal) -> SignalProducer<(Value, U), Error> { return lift(Signal.combineLatestWith)(otherSignal) } /// Delays `Next` and `Completed` events by the given interval, forwarding /// them on the given scheduler. /// /// `Failed` and `Interrupted` events are always scheduled immediately. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func delay(interval: NSTimeInterval, onScheduler scheduler: DateSchedulerType) -> SignalProducer { return lift { $0.delay(interval, onScheduler: scheduler) } } /// Returns a producer that will skip the first `count` values, then forward /// everything afterward. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func skip(count: Int) -> SignalProducer { return lift { $0.skip(count) } } /// Treats all Events from the input producer as plain values, allowing them to be /// manipulated just like any other value. /// /// In other words, this brings Events “into the monad.” /// /// When a Completed or Failed event is received, the resulting producer will send /// the Event itself and then complete. When an Interrupted event is received, /// the resulting producer will send the Event itself and then interrupt. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func materialize() -> SignalProducer, NoError> { return lift { $0.materialize() } } /// Forwards the latest value from `self` whenever `sampler` sends a Next /// event. /// /// If `sampler` fires before a value has been observed on `self`, nothing /// happens. /// /// Returns a producer that will send values from `self`, sampled (possibly /// multiple times) by `sampler`, then complete once both input producers have /// completed, or interrupt if either input producer is interrupted. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func sampleOn(sampler: SignalProducer<(), NoError>) -> SignalProducer { return liftLeft(Signal.sampleOn)(sampler) } /// Forwards the latest value from `self` whenever `sampler` sends a Next /// event. /// /// If `sampler` fires before a value has been observed on `self`, nothing /// happens. /// /// Returns a producer that will send values from `self`, sampled (possibly /// multiple times) by `sampler`, then complete once both inputs have /// completed, or interrupt if either input is interrupted. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func sampleOn(sampler: Signal<(), NoError>) -> SignalProducer { return lift(Signal.sampleOn)(sampler) } /// Forwards events from `self` until `trigger` sends a Next or Completed /// event, at which point the returned producer will complete. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func takeUntil(trigger: SignalProducer<(), NoError>) -> SignalProducer { return liftRight(Signal.takeUntil)(trigger) } /// Forwards events from `self` until `trigger` sends a Next or Completed /// event, at which point the returned producer will complete. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func takeUntil(trigger: Signal<(), NoError>) -> SignalProducer { return lift(Signal.takeUntil)(trigger) } /// Does not forward any values from `self` until `trigger` sends a Next or /// Completed, at which point the returned signal behaves exactly like `signal`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func skipUntil(trigger: SignalProducer<(), NoError>) -> SignalProducer { return liftRight(Signal.skipUntil)(trigger) } /// Does not forward any values from `self` until `trigger` sends a Next or /// Completed, at which point the returned signal behaves exactly like `signal`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func skipUntil(trigger: Signal<(), NoError>) -> SignalProducer { return lift(Signal.skipUntil)(trigger) } /// Forwards events from `self` with history: values of the returned producer /// are a tuple whose first member is the previous value and whose second member /// is the current value. `initial` is supplied as the first member when `self` /// sends its first value. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func combinePrevious(initial: Value) -> SignalProducer<(Value, Value), Error> { return lift { $0.combinePrevious(initial) } } /// Like `scan`, but sends only the final value and then immediately completes. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func reduce(initial: U, _ combine: (U, Value) -> U) -> SignalProducer { return lift { $0.reduce(initial, combine) } } /// Aggregates `self`'s values into a single combined value. When `self` emits /// its first value, `combine` is invoked with `initial` as the first argument and /// that emitted value as the second argument. The result is emitted from the /// producer returned from `scan`. That result is then passed to `combine` as the /// first argument when the next value is emitted, and so on. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func scan(initial: U, _ combine: (U, Value) -> U) -> SignalProducer { return lift { $0.scan(initial, combine) } } /// Forwards only those values from `self` which do not pass `isRepeat` with /// respect to the previous value. The first value is always forwarded. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func skipRepeats(isRepeat: (Value, Value) -> Bool) -> SignalProducer { return lift { $0.skipRepeats(isRepeat) } } /// Does not forward any values from `self` until `predicate` returns false, /// at which point the returned signal behaves exactly like `self`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func skipWhile(predicate: Value -> Bool) -> SignalProducer { return lift { $0.skipWhile(predicate) } } /// Forwards events from `self` until `replacement` begins sending events. /// /// Returns a producer which passes through `Next`, `Failed`, and `Interrupted` /// events from `self` until `replacement` sends an event, at which point the /// returned producer will send that event and switch to passing through events /// from `replacement` instead, regardless of whether `self` has sent events /// already. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func takeUntilReplacement(replacement: SignalProducer) -> SignalProducer { return liftRight(Signal.takeUntilReplacement)(replacement) } /// Forwards events from `self` until `replacement` begins sending events. /// /// Returns a producer which passes through `Next`, `Error`, and `Interrupted` /// events from `self` until `replacement` sends an event, at which point the /// returned producer will send that event and switch to passing through events /// from `replacement` instead, regardless of whether `self` has sent events /// already. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func takeUntilReplacement(replacement: Signal) -> SignalProducer { return lift(Signal.takeUntilReplacement)(replacement) } /// Waits until `self` completes and then forwards the final `count` values /// on the returned producer. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func takeLast(count: Int) -> SignalProducer { return lift { $0.takeLast(count) } } /// Forwards any values from `self` until `predicate` returns false, /// at which point the returned producer will complete. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func takeWhile(predicate: Value -> Bool) -> SignalProducer { return lift { $0.takeWhile(predicate) } } /// Zips elements of two producers into pairs. The elements of any Nth pair /// are the Nth elements of the two input producers. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func zipWith(otherProducer: SignalProducer) -> SignalProducer<(Value, U), Error> { return liftRight(Signal.zipWith)(otherProducer) } /// Zips elements of this producer and a signal into pairs. The elements of /// any Nth pair are the Nth elements of the two. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func zipWith(otherSignal: Signal) -> SignalProducer<(Value, U), Error> { return lift(Signal.zipWith)(otherSignal) } /// Applies `operation` to values from `self` with `Success`ful results /// forwarded on the returned producer and `Failure`s sent as `Failed` events. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func attempt(operation: Value -> Result<(), Error>) -> SignalProducer { return lift { $0.attempt(operation) } } /// Applies `operation` to values from `self` with `Success`ful results mapped /// on the returned producer and `Failure`s sent as `Failed` events. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func attemptMap(operation: Value -> Result) -> SignalProducer { return lift { $0.attemptMap(operation) } } /// Throttle values sent by the receiver, so that at least `interval` /// seconds pass between each, then forwards them on the given scheduler. /// /// If multiple values are received before the interval has elapsed, the /// latest value is the one that will be passed on. /// /// If `self` terminates while a value is being throttled, that value /// will be discarded and the returned producer will terminate immediately. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func throttle(interval: NSTimeInterval, onScheduler scheduler: DateSchedulerType) -> SignalProducer { return lift { $0.throttle(interval, onScheduler: scheduler) } } /// Forwards events from `self` until `interval`. Then if producer isn't completed yet, /// fails with `error` on `scheduler`. /// /// If the interval is 0, the timeout will be scheduled immediately. The producer /// must complete synchronously (or on a faster scheduler) to avoid the timeout. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func timeoutWithError(error: Error, afterInterval interval: NSTimeInterval, onScheduler scheduler: DateSchedulerType) -> SignalProducer { return lift { $0.timeoutWithError(error, afterInterval: interval, onScheduler: scheduler) } } } extension SignalProducerType where Value: OptionalType { /// Unwraps non-`nil` values and forwards them on the returned signal, `nil` /// values are dropped. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func ignoreNil() -> SignalProducer { return lift { $0.ignoreNil() } } } extension SignalProducerType where Value: EventType, Error == NoError { /// The inverse of materialize(), this will translate a signal of `Event` /// _values_ into a signal of those events themselves. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func dematerialize() -> SignalProducer { return lift { $0.dematerialize() } } } extension SignalProducerType where Error == NoError { /// Promotes a producer that does not generate failures into one that can. /// /// This does not actually cause failers to be generated for the given producer, /// but makes it easier to combine with other producers that may fail; for /// example, with operators like `combineLatestWith`, `zipWith`, `flatten`, etc. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func promoteErrors(_: F.Type) -> SignalProducer { return lift { $0.promoteErrors(F) } } } extension SignalProducerType where Value: Equatable { /// Forwards only those values from `self` which are not duplicates of the /// immedately preceding value. The first value is always forwarded. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func skipRepeats() -> SignalProducer { return lift { $0.skipRepeats() } } } /// Creates a repeating timer of the given interval, with a reasonable /// default leeway, sending updates on the given scheduler. /// /// This timer will never complete naturally, so all invocations of start() must /// be disposed to avoid leaks. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func timer(interval: NSTimeInterval, onScheduler scheduler: DateSchedulerType) -> SignalProducer { // Apple's "Power Efficiency Guide for Mac Apps" recommends a leeway of // at least 10% of the timer interval. return timer(interval, onScheduler: scheduler, withLeeway: interval * 0.1) } /// Creates a repeating timer of the given interval, sending updates on the /// given scheduler. /// /// This timer will never complete naturally, so all invocations of start() must /// be disposed to avoid leaks. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func timer(interval: NSTimeInterval, onScheduler scheduler: DateSchedulerType, withLeeway leeway: NSTimeInterval) -> SignalProducer { precondition(interval >= 0) precondition(leeway >= 0) return SignalProducer { observer, compositeDisposable in compositeDisposable += scheduler.scheduleAfter(scheduler.currentDate.dateByAddingTimeInterval(interval), repeatingEvery: interval, withLeeway: leeway) { observer.sendNext(scheduler.currentDate) } } } extension SignalProducerType { /// Injects side effects to be performed upon the specified signal events. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func on(started started: (() -> ())? = nil, event: (Event -> ())? = nil, failed: (Error -> ())? = nil, completed: (() -> ())? = nil, interrupted: (() -> ())? = nil, terminated: (() -> ())? = nil, disposed: (() -> ())? = nil, next: (Value -> ())? = nil) -> SignalProducer { return SignalProducer { observer, compositeDisposable in started?() self.startWithSignal { signal, disposable in compositeDisposable += disposable compositeDisposable += signal .on( event: event, failed: failed, completed: completed, interrupted: interrupted, terminated: terminated, disposed: disposed, next: next ) .observe(observer) } } } /// Starts the returned signal on the given Scheduler. /// /// This implies that any side effects embedded in the producer will be /// performed on the given scheduler as well. /// /// Events may still be sent upon other schedulers—this merely affects where /// the `start()` method is run. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func startOn(scheduler: SchedulerType) -> SignalProducer { return SignalProducer { observer, compositeDisposable in compositeDisposable += scheduler.schedule { self.startWithSignal { signal, signalDisposable in compositeDisposable.addDisposable(signalDisposable) signal.observe(observer) } } } } } /// Combines the values of all the given producers, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func combineLatest(a: SignalProducer, _ b: SignalProducer) -> SignalProducer<(A, B), Error> { return a.combineLatestWith(b) } /// Combines the values of all the given producers, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func combineLatest(a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer) -> SignalProducer<(A, B, C), Error> { return combineLatest(a, b) .combineLatestWith(c) .map(repack) } /// Combines the values of all the given producers, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func combineLatest(a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer) -> SignalProducer<(A, B, C, D), Error> { return combineLatest(a, b, c) .combineLatestWith(d) .map(repack) } /// Combines the values of all the given producers, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func combineLatest(a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer) -> SignalProducer<(A, B, C, D, E), Error> { return combineLatest(a, b, c, d) .combineLatestWith(e) .map(repack) } /// Combines the values of all the given producers, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func combineLatest(a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer, _ f: SignalProducer) -> SignalProducer<(A, B, C, D, E, F), Error> { return combineLatest(a, b, c, d, e) .combineLatestWith(f) .map(repack) } /// Combines the values of all the given producers, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func combineLatest(a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer, _ f: SignalProducer, _ g: SignalProducer) -> SignalProducer<(A, B, C, D, E, F, G), Error> { return combineLatest(a, b, c, d, e, f) .combineLatestWith(g) .map(repack) } /// Combines the values of all the given producers, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func combineLatest(a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer, _ f: SignalProducer, _ g: SignalProducer, _ h: SignalProducer) -> SignalProducer<(A, B, C, D, E, F, G, H), Error> { return combineLatest(a, b, c, d, e, f, g) .combineLatestWith(h) .map(repack) } /// Combines the values of all the given producers, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func combineLatest(a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer, _ f: SignalProducer, _ g: SignalProducer, _ h: SignalProducer, _ i: SignalProducer) -> SignalProducer<(A, B, C, D, E, F, G, H, I), Error> { return combineLatest(a, b, c, d, e, f, g, h) .combineLatestWith(i) .map(repack) } /// Combines the values of all the given producers, in the manner described by /// `combineLatestWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func combineLatest(a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer, _ f: SignalProducer, _ g: SignalProducer, _ h: SignalProducer, _ i: SignalProducer, _ j: SignalProducer) -> SignalProducer<(A, B, C, D, E, F, G, H, I, J), Error> { return combineLatest(a, b, c, d, e, f, g, h, i) .combineLatestWith(j) .map(repack) } /// Combines the values of all the given producers, in the manner described by /// `combineLatestWith`. Will return an empty `SignalProducer` if the sequence is empty. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func combineLatest>(producers: S) -> SignalProducer<[Value], Error> { var generator = producers.generate() if let first = generator.next() { let initial = first.map { [$0] } return GeneratorSequence(generator).reduce(initial) { producer, next in producer.combineLatestWith(next).map { $0.0 + [$0.1] } } } return .empty } /// Zips the values of all the given producers, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func zip(a: SignalProducer, _ b: SignalProducer) -> SignalProducer<(A, B), Error> { return a.zipWith(b) } /// Zips the values of all the given producers, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func zip(a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer) -> SignalProducer<(A, B, C), Error> { return zip(a, b) .zipWith(c) .map(repack) } /// Zips the values of all the given producers, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func zip(a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer) -> SignalProducer<(A, B, C, D), Error> { return zip(a, b, c) .zipWith(d) .map(repack) } /// Zips the values of all the given producers, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func zip(a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer) -> SignalProducer<(A, B, C, D, E), Error> { return zip(a, b, c, d) .zipWith(e) .map(repack) } /// Zips the values of all the given producers, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func zip(a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer, _ f: SignalProducer) -> SignalProducer<(A, B, C, D, E, F), Error> { return zip(a, b, c, d, e) .zipWith(f) .map(repack) } /// Zips the values of all the given producers, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func zip(a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer, _ f: SignalProducer, _ g: SignalProducer) -> SignalProducer<(A, B, C, D, E, F, G), Error> { return zip(a, b, c, d, e, f) .zipWith(g) .map(repack) } /// Zips the values of all the given producers, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func zip(a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer, _ f: SignalProducer, _ g: SignalProducer, _ h: SignalProducer) -> SignalProducer<(A, B, C, D, E, F, G, H), Error> { return zip(a, b, c, d, e, f, g) .zipWith(h) .map(repack) } /// Zips the values of all the given producers, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func zip(a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer, _ f: SignalProducer, _ g: SignalProducer, _ h: SignalProducer, _ i: SignalProducer) -> SignalProducer<(A, B, C, D, E, F, G, H, I), Error> { return zip(a, b, c, d, e, f, g, h) .zipWith(i) .map(repack) } /// Zips the values of all the given producers, in the manner described by /// `zipWith`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func zip(a: SignalProducer, _ b: SignalProducer, _ c: SignalProducer, _ d: SignalProducer, _ e: SignalProducer, _ f: SignalProducer, _ g: SignalProducer, _ h: SignalProducer, _ i: SignalProducer, _ j: SignalProducer) -> SignalProducer<(A, B, C, D, E, F, G, H, I, J), Error> { return zip(a, b, c, d, e, f, g, h, i) .zipWith(j) .map(repack) } /// Zips the values of all the given producers, in the manner described by /// `zipWith`. Will return an empty `SignalProducer` if the sequence is empty. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func zip>(producers: S) -> SignalProducer<[Value], Error> { var generator = producers.generate() if let first = generator.next() { let initial = first.map { [$0] } return GeneratorSequence(generator).reduce(initial) { producer, next in producer.zipWith(next).map { $0.0 + [$0.1] } } } return .empty } extension SignalProducerType { /// Repeats `self` a total of `count` times. Repeating `1` times results in /// an equivalent signal producer. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func times(count: Int) -> SignalProducer { precondition(count >= 0) if count == 0 { return .empty } else if count == 1 { return producer } return SignalProducer { observer, disposable in let serialDisposable = SerialDisposable() disposable.addDisposable(serialDisposable) func iterate(current: Int) { self.startWithSignal { signal, signalDisposable in serialDisposable.innerDisposable = signalDisposable signal.observe { event in if case .Completed = event { let remainingTimes = current - 1 if remainingTimes > 0 { iterate(remainingTimes) } else { observer.sendCompleted() } } else { observer.action(event) } } } } iterate(count) } } /// Ignores failures up to `count` times. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func retry(count: Int) -> SignalProducer { precondition(count >= 0) if count == 0 { return producer } else { return flatMapError { _ in self.retry(count - 1) } } } /// Waits for completion of `producer`, *then* forwards all events from /// `replacement`. Any failure sent from `producer` is forwarded immediately, in /// which case `replacement` will not be started, and none of its events will be /// be forwarded. All values sent from `producer` are ignored. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func then(replacement: SignalProducer) -> SignalProducer { let relay = SignalProducer { observer, observerDisposable in self.startWithSignal { signal, signalDisposable in observerDisposable.addDisposable(signalDisposable) signal.observe { event in switch event { case let .Failed(error): observer.sendFailed(error) case .Completed: observer.sendCompleted() case .Interrupted: observer.sendInterrupted() case .Next: break } } } } return relay.concat(replacement) } /// Starts the producer, then blocks, waiting for the first value. @warn_unused_result(message="Did you forget to check the result?") public func first() -> Result? { return take(1).single() } /// Starts the producer, then blocks, waiting for events: Next and Completed. /// When a single value or error is sent, the returned `Result` will represent /// those cases. However, when no values are sent, or when more than one value /// is sent, `nil` will be returned. @warn_unused_result(message="Did you forget to check the result?") public func single() -> Result? { let semaphore = dispatch_semaphore_create(0) var result: Result? take(2).start { event in switch event { case let .Next(value): if result != nil { // Move into failure state after recieving another value. result = nil return } result = .Success(value) case let .Failed(error): result = .Failure(error) dispatch_semaphore_signal(semaphore) case .Completed, .Interrupted: dispatch_semaphore_signal(semaphore) } } dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) return result } /// Starts the producer, then blocks, waiting for the last value. @warn_unused_result(message="Did you forget to check the result?") public func last() -> Result? { return takeLast(1).single() } /// Starts the producer, then blocks, waiting for completion. @warn_unused_result(message="Did you forget to check the result?") public func wait() -> Result<(), Error> { return then(SignalProducer<(), Error>(value: ())).last() ?? .Success(()) } /// Creates a new `SignalProducer` that will multicast values emitted by /// the underlying producer, up to `capacity`. /// This means that all clients of this `SignalProducer` will see the same version /// of the emitted values/errors. /// /// The underlying `SignalProducer` will not be started until `self` is started /// for the first time. When subscribing to this producer, all previous values /// (up to `capacity`) will be emitted, followed by any new values. /// /// If you find yourself needing *the current value* (the last buffered value) /// you should consider using `PropertyType` instead, which, unlike this operator, /// will guarantee at compile time that there's always a buffered value. /// This operator is not recommended in most cases, as it will introduce an implicit /// relationship between the original client and the rest, so consider alternatives /// like `PropertyType`, `SignalProducer.buffer`, or representing your stream using /// a `Signal` instead. /// /// This operator is only recommended when you absolutely need to introduce /// a layer of caching in front of another `SignalProducer`. /// /// This operator has the same semantics as `SignalProducer.buffer`. @warn_unused_result(message="Did you forget to call `start` on the producer?") public func replayLazily(capacity: Int) -> SignalProducer { precondition(capacity >= 0, "Invalid capacity: \(capacity)") var producer: SignalProducer? var producerObserver: SignalProducer.ProducedSignal.Observer? let lock = NSLock() lock.name = "org.reactivecocoa.ReactiveCocoa.SignalProducer.replayLazily" // This will go "out of scope" when the returned `SignalProducer` goes out of scope. // This lets us know when we're supposed to dispose the underlying producer. // This is necessary because `struct`s don't have `deinit`. let token = NSObject() return SignalProducer { observer, disposable in let initializedProducer: SignalProducer let initializedObserver: SignalProducer.ProducedSignal.Observer let shouldStartUnderlyingProducer: Bool lock.lock() if let producer = producer, producerObserver = producerObserver { (initializedProducer, initializedObserver) = (producer, producerObserver) shouldStartUnderlyingProducer = false } else { let (producerTemp, observerTemp) = SignalProducer.buffer(capacity) (producer, producerObserver) = (producerTemp, observerTemp) (initializedProducer, initializedObserver) = (producerTemp, observerTemp) shouldStartUnderlyingProducer = true } lock.unlock() // subscribe `observer` before starting the underlying producer. disposable += initializedProducer.start(observer) if shouldStartUnderlyingProducer { self.producer .takeUntil(token.willDeallocSignal) .start(initializedObserver) } } } } private extension NSObject { var willDeallocSignal: SignalProducer<(), NoError> { return self .rac_willDeallocSignal() .toSignalProducer() .map { _ in () } .mapError { error in fatalError("Unexpected error: \(error)") () } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa/Swift/TupleExtensions.swift ================================================ // // TupleExtensions.swift // ReactiveCocoa // // Created by Justin Spahr-Summers on 2014-12-20. // Copyright (c) 2014 GitHub. All rights reserved. // /// Adds a value into an N-tuple, returning an (N+1)-tuple. /// /// Supports creating tuples up to 10 elements long. internal func repack(t: (A, B), value: C) -> (A, B, C) { return (t.0, t.1, value) } internal func repack(t: (A, B, C), value: D) -> (A, B, C, D) { return (t.0, t.1, t.2, value) } internal func repack(t: (A, B, C, D), value: E) -> (A, B, C, D, E) { return (t.0, t.1, t.2, t.3, value) } internal func repack(t: (A, B, C, D, E), value: F) -> (A, B, C, D, E, F) { return (t.0, t.1, t.2, t.3, t.4, value) } internal func repack(t: (A, B, C, D, E, F), value: G) -> (A, B, C, D, E, F, G) { return (t.0, t.1, t.2, t.3, t.4, t.5, value) } internal func repack(t: (A, B, C, D, E, F, G), value: H) -> (A, B, C, D, E, F, G, H) { return (t.0, t.1, t.2, t.3, t.4, t.5, t.6, value) } internal func repack(t: (A, B, C, D, E, F, G, H), value: I) -> (A, B, C, D, E, F, G, H, I) { return (t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, value) } internal func repack(t: (A, B, C, D, E, F, G, H, I), value: J) -> (A, B, C, D, E, F, G, H, I, J) { return (t.0, t.1, t.2, t.3, t.4, t.5, t.6, t.7, t.8, value) } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 02D2602A1C1D6DAF003ACC61 /* SignalLifetimeSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02D260291C1D6DAF003ACC61 /* SignalLifetimeSpec.swift */; }; 02D2602B1C1D6DB8003ACC61 /* SignalLifetimeSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02D260291C1D6DAF003ACC61 /* SignalLifetimeSpec.swift */; }; 314304171ACA8B1E00595017 /* MKAnnotationView+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 314304151ACA8B1E00595017 /* MKAnnotationView+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; 314304181ACA8B1E00595017 /* MKAnnotationView+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 314304161ACA8B1E00595017 /* MKAnnotationView+RACSignalSupport.m */; }; 579504331BB8A34200A5E482 /* BagSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312EF19EF2A7700984962 /* BagSpec.swift */; }; 579504341BB8A34300A5E482 /* BagSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312EF19EF2A7700984962 /* BagSpec.swift */; }; 57A4D1B11BA13D7A00F7D4B1 /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = D871D69E1B3B29A40070F16C /* Optional.swift */; }; 57A4D1B21BA13D7A00F7D4B1 /* RACCompoundDisposableProvider.d in Sources */ = {isa = PBXBuildFile; fileRef = D037646A19EDA41200A782A9 /* RACCompoundDisposableProvider.d */; }; 57A4D1B31BA13D7A00F7D4B1 /* RACSignalProvider.d in Sources */ = {isa = PBXBuildFile; fileRef = D03764A319EDA41200A782A9 /* RACSignalProvider.d */; }; 57A4D1B41BA13D7A00F7D4B1 /* Disposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312BE19EF2A5800984962 /* Disposable.swift */; }; 57A4D1B61BA13D7A00F7D4B1 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54B51A69A3DB00AD8286 /* Event.swift */; }; 57A4D1B71BA13D7A00F7D4B1 /* ObjectiveCBridging.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312C419EF2A5800984962 /* ObjectiveCBridging.swift */; }; 57A4D1B81BA13D7A00F7D4B1 /* Scheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312C819EF2A5800984962 /* Scheduler.swift */; }; 57A4D1B91BA13D7A00F7D4B1 /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54AF1A69A2AC00AD8286 /* Action.swift */; }; 57A4D1BA1BA13D7A00F7D4B1 /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54B01A69A2AC00AD8286 /* Property.swift */; }; 57A4D1BB1BA13D7A00F7D4B1 /* Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54B11A69A2AC00AD8286 /* Signal.swift */; }; 57A4D1BC1BA13D7A00F7D4B1 /* SignalProducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54B21A69A2AC00AD8286 /* SignalProducer.swift */; }; 57A4D1BD1BA13D7A00F7D4B1 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312BB19EF2A5800984962 /* Atomic.swift */; }; 57A4D1BE1BA13D7A00F7D4B1 /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312BC19EF2A5800984962 /* Bag.swift */; }; 57A4D1BF1BA13D7A00F7D4B1 /* TupleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00004081A46864E000E7D41 /* TupleExtensions.swift */; }; 57A4D1C01BA13D7A00F7D4B1 /* FoundationExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B4A3C19F4C39A009E02AC /* FoundationExtensions.swift */; }; 57A4D1C11BA13D7A00F7D4B1 /* EXTRuntimeExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037666819EDA57100A782A9 /* EXTRuntimeExtensions.m */; }; 57A4D1C21BA13D7A00F7D4B1 /* NSArray+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037642B19EDA41200A782A9 /* NSArray+RACSequenceAdditions.m */; }; 57A4D1C31BA13D7A00F7D4B1 /* NSData+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643119EDA41200A782A9 /* NSData+RACSupport.m */; }; 57A4D1C41BA13D7A00F7D4B1 /* NSDictionary+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643319EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.m */; }; 57A4D1C51BA13D7A00F7D4B1 /* NSEnumerator+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643519EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.m */; }; 57A4D1C61BA13D7A00F7D4B1 /* NSFileHandle+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643719EDA41200A782A9 /* NSFileHandle+RACSupport.m */; }; 57A4D1C71BA13D7A00F7D4B1 /* NSIndexSet+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643919EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.m */; }; 57A4D1C81BA13D7A00F7D4B1 /* NSInvocation+RACTypeParsing.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643B19EDA41200A782A9 /* NSInvocation+RACTypeParsing.m */; }; 57A4D1C91BA13D7A00F7D4B1 /* NSNotificationCenter+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643D19EDA41200A782A9 /* NSNotificationCenter+RACSupport.m */; }; 57A4D1CA1BA13D7A00F7D4B1 /* NSObject+RACDeallocating.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644119EDA41200A782A9 /* NSObject+RACDeallocating.m */; }; 57A4D1CB1BA13D7A00F7D4B1 /* NSObject+RACDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644319EDA41200A782A9 /* NSObject+RACDescription.m */; }; 57A4D1CC1BA13D7A00F7D4B1 /* NSObject+RACKVOWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644519EDA41200A782A9 /* NSObject+RACKVOWrapper.m */; }; 57A4D1CD1BA13D7A00F7D4B1 /* NSObject+RACLifting.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644719EDA41200A782A9 /* NSObject+RACLifting.m */; }; 57A4D1CE1BA13D7A00F7D4B1 /* NSObject+RACPropertySubscribing.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644919EDA41200A782A9 /* NSObject+RACPropertySubscribing.m */; }; 57A4D1CF1BA13D7A00F7D4B1 /* NSObject+RACSelectorSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644B19EDA41200A782A9 /* NSObject+RACSelectorSignal.m */; }; 57A4D1D01BA13D7A00F7D4B1 /* NSOrderedSet+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644D19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.m */; }; 57A4D1D11BA13D7A00F7D4B1 /* NSSet+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644F19EDA41200A782A9 /* NSSet+RACSequenceAdditions.m */; }; 57A4D1D21BA13D7A00F7D4B1 /* NSString+RACKeyPathUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645119EDA41200A782A9 /* NSString+RACKeyPathUtilities.m */; }; 57A4D1D31BA13D7A00F7D4B1 /* NSString+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645319EDA41200A782A9 /* NSString+RACSequenceAdditions.m */; }; 57A4D1D41BA13D7A00F7D4B1 /* NSString+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645519EDA41200A782A9 /* NSString+RACSupport.m */; }; 57A4D1D61BA13D7A00F7D4B1 /* NSUserDefaults+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645B19EDA41200A782A9 /* NSUserDefaults+RACSupport.m */; }; 57A4D1D71BA13D7A00F7D4B1 /* RACArraySequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645D19EDA41200A782A9 /* RACArraySequence.m */; }; 57A4D1D81BA13D7A00F7D4B1 /* RACBehaviorSubject.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646119EDA41200A782A9 /* RACBehaviorSubject.m */; }; 57A4D1D91BA13D7A00F7D4B1 /* RACBlockTrampoline.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646319EDA41200A782A9 /* RACBlockTrampoline.m */; }; 57A4D1DA1BA13D7A00F7D4B1 /* RACChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646519EDA41200A782A9 /* RACChannel.m */; }; 57A4D1DB1BA13D7A00F7D4B1 /* RACCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646719EDA41200A782A9 /* RACCommand.m */; }; 57A4D1DC1BA13D7A00F7D4B1 /* RACCompoundDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646919EDA41200A782A9 /* RACCompoundDisposable.m */; }; 57A4D1DD1BA13D7A00F7D4B1 /* RACDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646C19EDA41200A782A9 /* RACDelegateProxy.m */; }; 57A4D1DE1BA13D7A00F7D4B1 /* RACDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646E19EDA41200A782A9 /* RACDisposable.m */; }; 57A4D1DF1BA13D7A00F7D4B1 /* RACDynamicSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647019EDA41200A782A9 /* RACDynamicSequence.m */; }; 57A4D1E01BA13D7A00F7D4B1 /* RACDynamicSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647219EDA41200A782A9 /* RACDynamicSignal.m */; }; 57A4D1E11BA13D7A00F7D4B1 /* RACEagerSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647419EDA41200A782A9 /* RACEagerSequence.m */; }; 57A4D1E21BA13D7A00F7D4B1 /* RACEmptySequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647619EDA41200A782A9 /* RACEmptySequence.m */; }; 57A4D1E31BA13D7A00F7D4B1 /* RACEmptySignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647819EDA41200A782A9 /* RACEmptySignal.m */; }; 57A4D1E41BA13D7A00F7D4B1 /* RACErrorSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647A19EDA41200A782A9 /* RACErrorSignal.m */; }; 57A4D1E51BA13D7A00F7D4B1 /* RACEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647C19EDA41200A782A9 /* RACEvent.m */; }; 57A4D1E61BA13D7A00F7D4B1 /* RACGroupedSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647E19EDA41200A782A9 /* RACGroupedSignal.m */; }; 57A4D1E71BA13D7A00F7D4B1 /* RACImmediateScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648019EDA41200A782A9 /* RACImmediateScheduler.m */; }; 57A4D1E81BA13D7A00F7D4B1 /* RACIndexSetSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648219EDA41200A782A9 /* RACIndexSetSequence.m */; }; 57A4D1E91BA13D7A00F7D4B1 /* RACKVOChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648419EDA41200A782A9 /* RACKVOChannel.m */; }; 57A4D1EA1BA13D7A00F7D4B1 /* RACKVOProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A70657E1A3F88B8001E8354 /* RACKVOProxy.m */; }; 57A4D1EB1BA13D7A00F7D4B1 /* RACKVOTrampoline.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648619EDA41200A782A9 /* RACKVOTrampoline.m */; }; 57A4D1EC1BA13D7A00F7D4B1 /* RACMulticastConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648819EDA41200A782A9 /* RACMulticastConnection.m */; }; 57A4D1ED1BA13D7A00F7D4B1 /* RACObjCRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648B19EDA41200A782A9 /* RACObjCRuntime.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 57A4D1EE1BA13D7A00F7D4B1 /* RACPassthroughSubscriber.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648D19EDA41200A782A9 /* RACPassthroughSubscriber.m */; }; 57A4D1EF1BA13D7A00F7D4B1 /* RACQueueScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648F19EDA41200A782A9 /* RACQueueScheduler.m */; }; 57A4D1F01BA13D7A00F7D4B1 /* RACReplaySubject.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649219EDA41200A782A9 /* RACReplaySubject.m */; }; 57A4D1F11BA13D7A00F7D4B1 /* RACReturnSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649419EDA41200A782A9 /* RACReturnSignal.m */; }; 57A4D1F21BA13D7A00F7D4B1 /* RACScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649619EDA41200A782A9 /* RACScheduler.m */; }; 57A4D1F31BA13D7A00F7D4B1 /* RACScopedDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649A19EDA41200A782A9 /* RACScopedDisposable.m */; }; 57A4D1F41BA13D7A00F7D4B1 /* RACSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649C19EDA41200A782A9 /* RACSequence.m */; }; 57A4D1F51BA13D7A00F7D4B1 /* RACSerialDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649E19EDA41200A782A9 /* RACSerialDisposable.m */; }; 57A4D1F61BA13D7A00F7D4B1 /* RACSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764A019EDA41200A782A9 /* RACSignal.m */; }; 57A4D1F71BA13D7A00F7D4B1 /* RACSignal+Operations.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764A219EDA41200A782A9 /* RACSignal+Operations.m */; }; 57A4D1F81BA13D7A00F7D4B1 /* RACSignalSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764A519EDA41200A782A9 /* RACSignalSequence.m */; }; 57A4D1F91BA13D7A00F7D4B1 /* RACStream.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764A719EDA41200A782A9 /* RACStream.m */; }; 57A4D1FA1BA13D7A00F7D4B1 /* RACStringSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764AA19EDA41200A782A9 /* RACStringSequence.m */; }; 57A4D1FB1BA13D7A00F7D4B1 /* RACSubject.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764AC19EDA41200A782A9 /* RACSubject.m */; }; 57A4D1FC1BA13D7A00F7D4B1 /* RACSubscriber.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764AE19EDA41200A782A9 /* RACSubscriber.m */; }; 57A4D1FD1BA13D7A00F7D4B1 /* RACSubscriptingAssignmentTrampoline.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B119EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.m */; }; 57A4D1FE1BA13D7A00F7D4B1 /* RACSubscriptionScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B319EDA41200A782A9 /* RACSubscriptionScheduler.m */; }; 57A4D1FF1BA13D7A00F7D4B1 /* RACTargetQueueScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B519EDA41200A782A9 /* RACTargetQueueScheduler.m */; }; 57A4D2001BA13D7A00F7D4B1 /* RACTestScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B719EDA41200A782A9 /* RACTestScheduler.m */; }; 57A4D2011BA13D7A00F7D4B1 /* RACTuple.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B919EDA41200A782A9 /* RACTuple.m */; }; 57A4D2021BA13D7A00F7D4B1 /* RACTupleSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764BB19EDA41200A782A9 /* RACTupleSequence.m */; }; 57A4D2031BA13D7A00F7D4B1 /* RACUnarySequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764BD19EDA41200A782A9 /* RACUnarySequence.m */; }; 57A4D2041BA13D7A00F7D4B1 /* RACUnit.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764BF19EDA41200A782A9 /* RACUnit.m */; }; 57A4D2051BA13D7A00F7D4B1 /* RACValueTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764C119EDA41200A782A9 /* RACValueTransformer.m */; }; 57A4D2061BA13D7A00F7D4B1 /* RACDynamicPropertySuperclass.m in Sources */ = {isa = PBXBuildFile; fileRef = D43F279F1A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.m */; }; 57A4D2081BA13D7A00F7D4B1 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDC42E2E1AE7AB8B00965373 /* Result.framework */; }; 57A4D20A1BA13D7A00F7D4B1 /* ReactiveCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = D04725EF19E49ED7006002AA /* ReactiveCocoa.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D20B1BA13D7A00F7D4B1 /* EXTKeyPathCoding.h in Headers */ = {isa = PBXBuildFile; fileRef = D037666619EDA57100A782A9 /* EXTKeyPathCoding.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D20C1BA13D7A00F7D4B1 /* EXTScope.h in Headers */ = {isa = PBXBuildFile; fileRef = D037666919EDA57100A782A9 /* EXTScope.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D20D1BA13D7A00F7D4B1 /* metamacros.h in Headers */ = {isa = PBXBuildFile; fileRef = D037666A19EDA57100A782A9 /* metamacros.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D20E1BA13D7A00F7D4B1 /* NSArray+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037642A19EDA41200A782A9 /* NSArray+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D20F1BA13D7A00F7D4B1 /* NSData+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643019EDA41200A782A9 /* NSData+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2101BA13D7A00F7D4B1 /* NSDictionary+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643219EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2111BA13D7A00F7D4B1 /* NSEnumerator+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643419EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2121BA13D7A00F7D4B1 /* NSFileHandle+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643619EDA41200A782A9 /* NSFileHandle+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2131BA13D7A00F7D4B1 /* NSIndexSet+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643819EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2141BA13D7A00F7D4B1 /* NSNotificationCenter+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643C19EDA41200A782A9 /* NSNotificationCenter+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2151BA13D7A00F7D4B1 /* NSObject+RACDeallocating.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644019EDA41200A782A9 /* NSObject+RACDeallocating.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2161BA13D7A00F7D4B1 /* NSObject+RACLifting.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644619EDA41200A782A9 /* NSObject+RACLifting.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2171BA13D7A00F7D4B1 /* NSObject+RACPropertySubscribing.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644819EDA41200A782A9 /* NSObject+RACPropertySubscribing.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2181BA13D7A00F7D4B1 /* NSObject+RACSelectorSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644A19EDA41200A782A9 /* NSObject+RACSelectorSignal.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2191BA13D7A00F7D4B1 /* NSOrderedSet+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644C19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D21A1BA13D7A00F7D4B1 /* NSSet+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644E19EDA41200A782A9 /* NSSet+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D21B1BA13D7A00F7D4B1 /* NSString+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037645219EDA41200A782A9 /* NSString+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D21C1BA13D7A00F7D4B1 /* NSString+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037645419EDA41200A782A9 /* NSString+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D21E1BA13D7A00F7D4B1 /* NSUserDefaults+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037645A19EDA41200A782A9 /* NSUserDefaults+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D21F1BA13D7A00F7D4B1 /* RACBehaviorSubject.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646019EDA41200A782A9 /* RACBehaviorSubject.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2201BA13D7A00F7D4B1 /* RACChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646419EDA41200A782A9 /* RACChannel.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2211BA13D7A00F7D4B1 /* RACCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646619EDA41200A782A9 /* RACCommand.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2221BA13D7A00F7D4B1 /* RACCompoundDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646819EDA41200A782A9 /* RACCompoundDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2231BA13D7A00F7D4B1 /* RACDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646D19EDA41200A782A9 /* RACDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2241BA13D7A00F7D4B1 /* RACEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = D037647B19EDA41200A782A9 /* RACEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2251BA13D7A00F7D4B1 /* RACGroupedSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = D037647D19EDA41200A782A9 /* RACGroupedSignal.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2261BA13D7A00F7D4B1 /* RACKVOChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = D037648319EDA41200A782A9 /* RACKVOChannel.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2271BA13D7A00F7D4B1 /* RACMulticastConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = D037648719EDA41200A782A9 /* RACMulticastConnection.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2281BA13D7A00F7D4B1 /* RACQueueScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = D037648E19EDA41200A782A9 /* RACQueueScheduler.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2291BA13D7A00F7D4B1 /* RACQueueScheduler+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649019EDA41200A782A9 /* RACQueueScheduler+Subclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D22A1BA13D7A00F7D4B1 /* RACReplaySubject.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649119EDA41200A782A9 /* RACReplaySubject.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D22B1BA13D7A00F7D4B1 /* RACScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649519EDA41200A782A9 /* RACScheduler.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D22C1BA13D7A00F7D4B1 /* RACScheduler+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649819EDA41200A782A9 /* RACScheduler+Subclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D22D1BA13D7A00F7D4B1 /* RACScopedDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649919EDA41200A782A9 /* RACScopedDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D22E1BA13D7A00F7D4B1 /* RACSequence.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649B19EDA41200A782A9 /* RACSequence.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D22F1BA13D7A00F7D4B1 /* RACSerialDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649D19EDA41200A782A9 /* RACSerialDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2301BA13D7A00F7D4B1 /* RACSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649F19EDA41200A782A9 /* RACSignal.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2311BA13D7A00F7D4B1 /* RACSignal+Operations.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764A119EDA41200A782A9 /* RACSignal+Operations.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2321BA13D7A00F7D4B1 /* RACStream.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764A619EDA41200A782A9 /* RACStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2331BA13D7A00F7D4B1 /* RACSubject.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764AB19EDA41200A782A9 /* RACSubject.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2341BA13D7A00F7D4B1 /* RACSubscriber.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764AD19EDA41200A782A9 /* RACSubscriber.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2351BA13D7A00F7D4B1 /* RACSubscriptingAssignmentTrampoline.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764B019EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2361BA13D7A00F7D4B1 /* RACTargetQueueScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764B419EDA41200A782A9 /* RACTargetQueueScheduler.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2371BA13D7A00F7D4B1 /* RACTestScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764B619EDA41200A782A9 /* RACTestScheduler.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2381BA13D7A00F7D4B1 /* RACTuple.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764B819EDA41200A782A9 /* RACTuple.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D2391BA13D7A00F7D4B1 /* RACUnit.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764BE19EDA41200A782A9 /* RACUnit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57A4D23A1BA13D7A00F7D4B1 /* RACDynamicPropertySuperclass.h in Headers */ = {isa = PBXBuildFile; fileRef = D43F279E1A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57D4768D1C42063C00EFE697 /* UIControl+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764CD19EDA41200A782A9 /* UIControl+RACSignalSupport.m */; }; 57D476901C4206D400EFE697 /* UIControl+RACSignalSupportPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764CF19EDA41200A782A9 /* UIControl+RACSignalSupportPrivate.m */; }; 57D476911C4206DA00EFE697 /* UIGestureRecognizer+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764D319EDA41200A782A9 /* UIGestureRecognizer+RACSignalSupport.m */; }; 57D476921C4206DF00EFE697 /* UISegmentedControl+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764D919EDA41200A782A9 /* UISegmentedControl+RACSignalSupport.m */; }; 57D476951C4206EC00EFE697 /* UITableViewCell+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764E119EDA41200A782A9 /* UITableViewCell+RACSignalSupport.m */; }; 57D476961C4206EC00EFE697 /* UITableViewHeaderFooterView+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764E319EDA41200A782A9 /* UITableViewHeaderFooterView+RACSignalSupport.m */; }; 57D476971C4206EC00EFE697 /* UITextField+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764E519EDA41200A782A9 /* UITextField+RACSignalSupport.m */; }; 57D476981C4206EC00EFE697 /* UITextView+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764E719EDA41200A782A9 /* UITextView+RACSignalSupport.m */; }; 57D4769A1C4206F200EFE697 /* UIButton+RACCommandSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764C919EDA41200A782A9 /* UIButton+RACCommandSupport.m */; }; 57D4769B1C4206F200EFE697 /* UICollectionReusableView+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764CB19EDA41200A782A9 /* UICollectionReusableView+RACSignalSupport.m */; }; 57DC89A01C5066D400E367B7 /* UIGestureRecognizer+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764D219EDA41200A782A9 /* UIGestureRecognizer+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57DC89A11C50672B00E367B7 /* UIControl+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764CC19EDA41200A782A9 /* UIControl+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57DC89A21C50673C00E367B7 /* UISegmentedControl+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764D819EDA41200A782A9 /* UISegmentedControl+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57DC89A31C50674300E367B7 /* UITableViewCell+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764E019EDA41200A782A9 /* UITableViewCell+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57DC89A41C50674D00E367B7 /* UITableViewHeaderFooterView+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764E219EDA41200A782A9 /* UITableViewHeaderFooterView+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57DC89A51C50675700E367B7 /* UITextField+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764E419EDA41200A782A9 /* UITextField+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57DC89A61C50675F00E367B7 /* UITextView+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764E619EDA41200A782A9 /* UITextView+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57DC89A71C50679700E367B7 /* UIButton+RACCommandSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764C819EDA41200A782A9 /* UIButton+RACCommandSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57DC89A81C50679E00E367B7 /* UICollectionReusableView+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764CA19EDA41200A782A9 /* UICollectionReusableView+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; 7A7065811A3F88B8001E8354 /* RACKVOProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A70657E1A3F88B8001E8354 /* RACKVOProxy.m */; }; 7A7065821A3F88B8001E8354 /* RACKVOProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A70657E1A3F88B8001E8354 /* RACKVOProxy.m */; }; 7A7065841A3F8967001E8354 /* RACKVOProxySpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A7065831A3F8967001E8354 /* RACKVOProxySpec.m */; }; 7A7065851A3F8967001E8354 /* RACKVOProxySpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A7065831A3F8967001E8354 /* RACKVOProxySpec.m */; }; A1046B7A1BFF5661004D8045 /* EXTRuntimeExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037666719EDA57100A782A9 /* EXTRuntimeExtensions.h */; settings = {ATTRIBUTES = (Private, ); }; }; A1046B7B1BFF5662004D8045 /* EXTRuntimeExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037666719EDA57100A782A9 /* EXTRuntimeExtensions.h */; settings = {ATTRIBUTES = (Private, ); }; }; A1046B7C1BFF5662004D8045 /* EXTRuntimeExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037666719EDA57100A782A9 /* EXTRuntimeExtensions.h */; settings = {ATTRIBUTES = (Private, ); }; }; A1046B7D1BFF5664004D8045 /* EXTRuntimeExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037666719EDA57100A782A9 /* EXTRuntimeExtensions.h */; settings = {ATTRIBUTES = (Private, ); }; }; A9B3155E1B3940750001CB9C /* EXTRuntimeExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037666819EDA57100A782A9 /* EXTRuntimeExtensions.m */; }; A9B315601B3940750001CB9C /* NSArray+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037642B19EDA41200A782A9 /* NSArray+RACSequenceAdditions.m */; }; A9B315631B3940750001CB9C /* NSData+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643119EDA41200A782A9 /* NSData+RACSupport.m */; }; A9B315641B3940750001CB9C /* NSDictionary+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643319EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.m */; }; A9B315651B3940750001CB9C /* NSEnumerator+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643519EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.m */; }; A9B315661B3940750001CB9C /* NSFileHandle+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643719EDA41200A782A9 /* NSFileHandle+RACSupport.m */; }; A9B315671B3940750001CB9C /* NSIndexSet+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643919EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.m */; }; A9B315681B3940750001CB9C /* NSInvocation+RACTypeParsing.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643B19EDA41200A782A9 /* NSInvocation+RACTypeParsing.m */; }; A9B315691B3940750001CB9C /* NSNotificationCenter+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643D19EDA41200A782A9 /* NSNotificationCenter+RACSupport.m */; }; A9B3156B1B3940750001CB9C /* NSObject+RACDeallocating.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644119EDA41200A782A9 /* NSObject+RACDeallocating.m */; }; A9B3156C1B3940750001CB9C /* NSObject+RACDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644319EDA41200A782A9 /* NSObject+RACDescription.m */; }; A9B3156D1B3940750001CB9C /* NSObject+RACKVOWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644519EDA41200A782A9 /* NSObject+RACKVOWrapper.m */; }; A9B3156E1B3940750001CB9C /* NSObject+RACLifting.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644719EDA41200A782A9 /* NSObject+RACLifting.m */; }; A9B3156F1B3940750001CB9C /* NSObject+RACPropertySubscribing.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644919EDA41200A782A9 /* NSObject+RACPropertySubscribing.m */; }; A9B315701B3940750001CB9C /* NSObject+RACSelectorSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644B19EDA41200A782A9 /* NSObject+RACSelectorSignal.m */; }; A9B315711B3940750001CB9C /* NSOrderedSet+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644D19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.m */; }; A9B315721B3940750001CB9C /* NSSet+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644F19EDA41200A782A9 /* NSSet+RACSequenceAdditions.m */; }; A9B315731B3940750001CB9C /* NSString+RACKeyPathUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645119EDA41200A782A9 /* NSString+RACKeyPathUtilities.m */; }; A9B315741B3940750001CB9C /* NSString+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645319EDA41200A782A9 /* NSString+RACSequenceAdditions.m */; }; A9B315751B3940750001CB9C /* NSString+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645519EDA41200A782A9 /* NSString+RACSupport.m */; }; A9B315781B3940750001CB9C /* NSUserDefaults+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645B19EDA41200A782A9 /* NSUserDefaults+RACSupport.m */; }; A9B315791B3940750001CB9C /* RACArraySequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645D19EDA41200A782A9 /* RACArraySequence.m */; }; A9B3157A1B3940750001CB9C /* RACBehaviorSubject.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646119EDA41200A782A9 /* RACBehaviorSubject.m */; }; A9B3157B1B3940750001CB9C /* RACBlockTrampoline.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646319EDA41200A782A9 /* RACBlockTrampoline.m */; }; A9B3157C1B3940750001CB9C /* RACChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646519EDA41200A782A9 /* RACChannel.m */; }; A9B3157D1B3940750001CB9C /* RACCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646719EDA41200A782A9 /* RACCommand.m */; }; A9B3157E1B3940750001CB9C /* RACCompoundDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646919EDA41200A782A9 /* RACCompoundDisposable.m */; }; A9B3157F1B3940750001CB9C /* RACDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646C19EDA41200A782A9 /* RACDelegateProxy.m */; }; A9B315801B3940750001CB9C /* RACDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646E19EDA41200A782A9 /* RACDisposable.m */; }; A9B315811B3940750001CB9C /* RACDynamicSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647019EDA41200A782A9 /* RACDynamicSequence.m */; }; A9B315821B3940750001CB9C /* RACDynamicSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647219EDA41200A782A9 /* RACDynamicSignal.m */; }; A9B315831B3940750001CB9C /* RACEagerSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647419EDA41200A782A9 /* RACEagerSequence.m */; }; A9B315841B3940750001CB9C /* RACEmptySequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647619EDA41200A782A9 /* RACEmptySequence.m */; }; A9B315851B3940750001CB9C /* RACEmptySignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647819EDA41200A782A9 /* RACEmptySignal.m */; }; A9B315861B3940750001CB9C /* RACErrorSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647A19EDA41200A782A9 /* RACErrorSignal.m */; }; A9B315871B3940750001CB9C /* RACEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647C19EDA41200A782A9 /* RACEvent.m */; }; A9B315881B3940750001CB9C /* RACGroupedSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647E19EDA41200A782A9 /* RACGroupedSignal.m */; }; A9B315891B3940750001CB9C /* RACImmediateScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648019EDA41200A782A9 /* RACImmediateScheduler.m */; }; A9B3158A1B3940750001CB9C /* RACIndexSetSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648219EDA41200A782A9 /* RACIndexSetSequence.m */; }; A9B3158B1B3940750001CB9C /* RACKVOChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648419EDA41200A782A9 /* RACKVOChannel.m */; }; A9B3158C1B3940750001CB9C /* RACKVOProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A70657E1A3F88B8001E8354 /* RACKVOProxy.m */; }; A9B3158D1B3940750001CB9C /* RACKVOTrampoline.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648619EDA41200A782A9 /* RACKVOTrampoline.m */; }; A9B3158E1B3940750001CB9C /* RACMulticastConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648819EDA41200A782A9 /* RACMulticastConnection.m */; }; A9B3158F1B3940750001CB9C /* RACObjCRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648B19EDA41200A782A9 /* RACObjCRuntime.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; A9B315901B3940750001CB9C /* RACPassthroughSubscriber.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648D19EDA41200A782A9 /* RACPassthroughSubscriber.m */; }; A9B315911B3940750001CB9C /* RACQueueScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648F19EDA41200A782A9 /* RACQueueScheduler.m */; }; A9B315921B3940750001CB9C /* RACReplaySubject.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649219EDA41200A782A9 /* RACReplaySubject.m */; }; A9B315931B3940750001CB9C /* RACReturnSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649419EDA41200A782A9 /* RACReturnSignal.m */; }; A9B315941B3940750001CB9C /* RACScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649619EDA41200A782A9 /* RACScheduler.m */; }; A9B315951B3940750001CB9C /* RACScopedDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649A19EDA41200A782A9 /* RACScopedDisposable.m */; }; A9B315961B3940750001CB9C /* RACSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649C19EDA41200A782A9 /* RACSequence.m */; }; A9B315971B3940750001CB9C /* RACSerialDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649E19EDA41200A782A9 /* RACSerialDisposable.m */; }; A9B315981B3940750001CB9C /* RACSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764A019EDA41200A782A9 /* RACSignal.m */; }; A9B315991B3940750001CB9C /* RACSignal+Operations.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764A219EDA41200A782A9 /* RACSignal+Operations.m */; }; A9B3159A1B3940750001CB9C /* RACSignalSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764A519EDA41200A782A9 /* RACSignalSequence.m */; }; A9B3159B1B3940750001CB9C /* RACStream.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764A719EDA41200A782A9 /* RACStream.m */; }; A9B3159C1B3940750001CB9C /* RACStringSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764AA19EDA41200A782A9 /* RACStringSequence.m */; }; A9B3159D1B3940750001CB9C /* RACSubject.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764AC19EDA41200A782A9 /* RACSubject.m */; }; A9B3159E1B3940750001CB9C /* RACSubscriber.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764AE19EDA41200A782A9 /* RACSubscriber.m */; }; A9B3159F1B3940750001CB9C /* RACSubscriptingAssignmentTrampoline.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B119EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.m */; }; A9B315A01B3940750001CB9C /* RACSubscriptionScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B319EDA41200A782A9 /* RACSubscriptionScheduler.m */; }; A9B315A11B3940750001CB9C /* RACTargetQueueScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B519EDA41200A782A9 /* RACTargetQueueScheduler.m */; }; A9B315A21B3940750001CB9C /* RACTestScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B719EDA41200A782A9 /* RACTestScheduler.m */; }; A9B315A31B3940750001CB9C /* RACTuple.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B919EDA41200A782A9 /* RACTuple.m */; }; A9B315A41B3940750001CB9C /* RACTupleSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764BB19EDA41200A782A9 /* RACTupleSequence.m */; }; A9B315A51B3940750001CB9C /* RACUnarySequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764BD19EDA41200A782A9 /* RACUnarySequence.m */; }; A9B315A61B3940750001CB9C /* RACUnit.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764BF19EDA41200A782A9 /* RACUnit.m */; }; A9B315A71B3940750001CB9C /* RACValueTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764C119EDA41200A782A9 /* RACValueTransformer.m */; }; A9B315BB1B3940750001CB9C /* RACDynamicPropertySuperclass.m in Sources */ = {isa = PBXBuildFile; fileRef = D43F279F1A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.m */; }; A9B315BC1B3940810001CB9C /* Disposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312BE19EF2A5800984962 /* Disposable.swift */; }; A9B315BE1B3940810001CB9C /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54B51A69A3DB00AD8286 /* Event.swift */; }; A9B315BF1B3940810001CB9C /* ObjectiveCBridging.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312C419EF2A5800984962 /* ObjectiveCBridging.swift */; }; A9B315C01B3940810001CB9C /* Scheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312C819EF2A5800984962 /* Scheduler.swift */; }; A9B315C11B3940810001CB9C /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54AF1A69A2AC00AD8286 /* Action.swift */; }; A9B315C21B3940810001CB9C /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54B01A69A2AC00AD8286 /* Property.swift */; }; A9B315C31B3940810001CB9C /* Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54B11A69A2AC00AD8286 /* Signal.swift */; }; A9B315C41B3940810001CB9C /* SignalProducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54B21A69A2AC00AD8286 /* SignalProducer.swift */; }; A9B315C51B3940810001CB9C /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312BB19EF2A5800984962 /* Atomic.swift */; }; A9B315C61B3940810001CB9C /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312BC19EF2A5800984962 /* Bag.swift */; }; A9B315C71B3940810001CB9C /* TupleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00004081A46864E000E7D41 /* TupleExtensions.swift */; }; A9B315C81B3940810001CB9C /* FoundationExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B4A3C19F4C39A009E02AC /* FoundationExtensions.swift */; }; A9B315C91B3940980001CB9C /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDC42E2E1AE7AB8B00965373 /* Result.framework */; }; A9B315CA1B3940AB0001CB9C /* ReactiveCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = D04725EF19E49ED7006002AA /* ReactiveCocoa.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315CB1B3940AB0001CB9C /* EXTKeyPathCoding.h in Headers */ = {isa = PBXBuildFile; fileRef = D037666619EDA57100A782A9 /* EXTKeyPathCoding.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315CD1B3940AB0001CB9C /* EXTScope.h in Headers */ = {isa = PBXBuildFile; fileRef = D037666919EDA57100A782A9 /* EXTScope.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315CE1B3940AB0001CB9C /* metamacros.h in Headers */ = {isa = PBXBuildFile; fileRef = D037666A19EDA57100A782A9 /* metamacros.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315D01B3940AB0001CB9C /* NSArray+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037642A19EDA41200A782A9 /* NSArray+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315D31B3940AB0001CB9C /* NSData+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643019EDA41200A782A9 /* NSData+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315D41B3940AB0001CB9C /* NSDictionary+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643219EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315D51B3940AB0001CB9C /* NSEnumerator+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643419EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315D61B3940AB0001CB9C /* NSFileHandle+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643619EDA41200A782A9 /* NSFileHandle+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315D71B3940AB0001CB9C /* NSIndexSet+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643819EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315D91B3940AB0001CB9C /* NSNotificationCenter+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643C19EDA41200A782A9 /* NSNotificationCenter+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315DB1B3940AB0001CB9C /* NSObject+RACDeallocating.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644019EDA41200A782A9 /* NSObject+RACDeallocating.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315DE1B3940AB0001CB9C /* NSObject+RACLifting.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644619EDA41200A782A9 /* NSObject+RACLifting.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315DF1B3940AB0001CB9C /* NSObject+RACPropertySubscribing.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644819EDA41200A782A9 /* NSObject+RACPropertySubscribing.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315E01B3940AB0001CB9C /* NSObject+RACSelectorSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644A19EDA41200A782A9 /* NSObject+RACSelectorSignal.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315E11B3940AB0001CB9C /* NSOrderedSet+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644C19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315E21B3940AB0001CB9C /* NSSet+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644E19EDA41200A782A9 /* NSSet+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315E41B3940AB0001CB9C /* NSString+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037645219EDA41200A782A9 /* NSString+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315E51B3940AB0001CB9C /* NSString+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037645419EDA41200A782A9 /* NSString+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315E81B3940AB0001CB9C /* NSUserDefaults+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037645A19EDA41200A782A9 /* NSUserDefaults+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315EA1B3940AB0001CB9C /* RACBehaviorSubject.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646019EDA41200A782A9 /* RACBehaviorSubject.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315EC1B3940AB0001CB9C /* RACChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646419EDA41200A782A9 /* RACChannel.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315ED1B3940AC0001CB9C /* RACCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646619EDA41200A782A9 /* RACCommand.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315EE1B3940AC0001CB9C /* RACCompoundDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646819EDA41200A782A9 /* RACCompoundDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315F01B3940AC0001CB9C /* RACDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646D19EDA41200A782A9 /* RACDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315F71B3940AC0001CB9C /* RACEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = D037647B19EDA41200A782A9 /* RACEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315F81B3940AC0001CB9C /* RACGroupedSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = D037647D19EDA41200A782A9 /* RACGroupedSignal.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315FB1B3940AC0001CB9C /* RACKVOChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = D037648319EDA41200A782A9 /* RACKVOChannel.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B315FE1B3940AC0001CB9C /* RACMulticastConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = D037648719EDA41200A782A9 /* RACMulticastConnection.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B316021B3940AD0001CB9C /* RACQueueScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = D037648E19EDA41200A782A9 /* RACQueueScheduler.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B316031B3940AD0001CB9C /* RACQueueScheduler+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649019EDA41200A782A9 /* RACQueueScheduler+Subclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B316041B3940AD0001CB9C /* RACReplaySubject.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649119EDA41200A782A9 /* RACReplaySubject.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B316061B3940AD0001CB9C /* RACScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649519EDA41200A782A9 /* RACScheduler.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B316081B3940AD0001CB9C /* RACScheduler+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649819EDA41200A782A9 /* RACScheduler+Subclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B316091B3940AD0001CB9C /* RACScopedDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649919EDA41200A782A9 /* RACScopedDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B3160A1B3940AD0001CB9C /* RACSequence.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649B19EDA41200A782A9 /* RACSequence.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B3160B1B3940AD0001CB9C /* RACSerialDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649D19EDA41200A782A9 /* RACSerialDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B3160C1B3940AE0001CB9C /* RACSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649F19EDA41200A782A9 /* RACSignal.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B3160D1B3940AE0001CB9C /* RACSignal+Operations.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764A119EDA41200A782A9 /* RACSignal+Operations.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B3160F1B3940AE0001CB9C /* RACStream.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764A619EDA41200A782A9 /* RACStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B316121B3940AE0001CB9C /* RACSubject.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764AB19EDA41200A782A9 /* RACSubject.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B316131B3940AE0001CB9C /* RACSubscriber.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764AD19EDA41200A782A9 /* RACSubscriber.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B316151B3940AE0001CB9C /* RACSubscriptingAssignmentTrampoline.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764B019EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B316171B3940AF0001CB9C /* RACTargetQueueScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764B419EDA41200A782A9 /* RACTargetQueueScheduler.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B316181B3940AF0001CB9C /* RACTestScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764B619EDA41200A782A9 /* RACTestScheduler.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B316191B3940AF0001CB9C /* RACTuple.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764B819EDA41200A782A9 /* RACTuple.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B3161C1B3940AF0001CB9C /* RACUnit.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764BE19EDA41200A782A9 /* RACUnit.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B316311B3940B20001CB9C /* RACDynamicPropertySuperclass.h in Headers */ = {isa = PBXBuildFile; fileRef = D43F279E1A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; A9B316341B394C7F0001CB9C /* RACCompoundDisposableProvider.d in Sources */ = {isa = PBXBuildFile; fileRef = D037646A19EDA41200A782A9 /* RACCompoundDisposableProvider.d */; }; A9B316351B394C7F0001CB9C /* RACSignalProvider.d in Sources */ = {isa = PBXBuildFile; fileRef = D03764A319EDA41200A782A9 /* RACSignalProvider.d */; }; A9F793341B60D0140026BCBA /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = D871D69E1B3B29A40070F16C /* Optional.swift */; }; B696FB811A7640C00075236D /* TestError.swift in Sources */ = {isa = PBXBuildFile; fileRef = B696FB801A7640C00075236D /* TestError.swift */; }; B696FB821A7640C00075236D /* TestError.swift in Sources */ = {isa = PBXBuildFile; fileRef = B696FB801A7640C00075236D /* TestError.swift */; }; BFA6B94D1A7604D400C846D1 /* SignalProducerNimbleMatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA6B94A1A76044800C846D1 /* SignalProducerNimbleMatchers.swift */; }; BFA6B94E1A7604D500C846D1 /* SignalProducerNimbleMatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFA6B94A1A76044800C846D1 /* SignalProducerNimbleMatchers.swift */; }; CA6F28501C52626B001879D2 /* FlattenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA6F284F1C52626B001879D2 /* FlattenSpec.swift */; }; CA6F28511C52626B001879D2 /* FlattenSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA6F284F1C52626B001879D2 /* FlattenSpec.swift */; }; CDC42E2F1AE7AB8B00965373 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDC42E2E1AE7AB8B00965373 /* Result.framework */; }; CDC42E301AE7AB8B00965373 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDC42E2E1AE7AB8B00965373 /* Result.framework */; }; CDC42E311AE7AB8B00965373 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDC42E2E1AE7AB8B00965373 /* Result.framework */; }; CDC42E331AE7AC6D00965373 /* Result.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = CDC42E2E1AE7AB8B00965373 /* Result.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; CDCD247A1C277EEC00710AEE /* AtomicSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312EE19EF2A7700984962 /* AtomicSpec.swift */; }; CDCD247B1C277EED00710AEE /* AtomicSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312EE19EF2A7700984962 /* AtomicSpec.swift */; }; D00004091A46864E000E7D41 /* TupleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00004081A46864E000E7D41 /* TupleExtensions.swift */; }; D000040A1A46864E000E7D41 /* TupleExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00004081A46864E000E7D41 /* TupleExtensions.swift */; }; D01B7B6219EDD8FE00D26E01 /* Nimble.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = D05E662419EDD82000904ACA /* Nimble.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D01B7B6319EDD8FE00D26E01 /* Quick.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = D037672B19EDA75D00A782A9 /* Quick.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D01B7B6419EDD94B00D26E01 /* ReactiveCocoa.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = D047260C19E49F82006002AA /* ReactiveCocoa.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D021671D1A6CD50500987861 /* ActionSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021671C1A6CD50500987861 /* ActionSpec.swift */; }; D021671E1A6CD50500987861 /* ActionSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021671C1A6CD50500987861 /* ActionSpec.swift */; }; D03764E819EDA41200A782A9 /* NSArray+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037642A19EDA41200A782A9 /* NSArray+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03764E919EDA41200A782A9 /* NSArray+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037642A19EDA41200A782A9 /* NSArray+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03764EA19EDA41200A782A9 /* NSArray+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037642B19EDA41200A782A9 /* NSArray+RACSequenceAdditions.m */; }; D03764EB19EDA41200A782A9 /* NSArray+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037642B19EDA41200A782A9 /* NSArray+RACSequenceAdditions.m */; }; D03764EC19EDA41200A782A9 /* NSControl+RACCommandSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037642C19EDA41200A782A9 /* NSControl+RACCommandSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03764EE19EDA41200A782A9 /* NSControl+RACCommandSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037642D19EDA41200A782A9 /* NSControl+RACCommandSupport.m */; }; D03764F019EDA41200A782A9 /* NSControl+RACTextSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037642E19EDA41200A782A9 /* NSControl+RACTextSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03764F219EDA41200A782A9 /* NSControl+RACTextSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037642F19EDA41200A782A9 /* NSControl+RACTextSignalSupport.m */; }; D03764F419EDA41200A782A9 /* NSData+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643019EDA41200A782A9 /* NSData+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03764F519EDA41200A782A9 /* NSData+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643019EDA41200A782A9 /* NSData+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03764F619EDA41200A782A9 /* NSData+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643119EDA41200A782A9 /* NSData+RACSupport.m */; }; D03764F719EDA41200A782A9 /* NSData+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643119EDA41200A782A9 /* NSData+RACSupport.m */; }; D03764F819EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643219EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03764F919EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643219EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03764FA19EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643319EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.m */; }; D03764FB19EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643319EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.m */; }; D03764FC19EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643419EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03764FD19EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643419EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03764FE19EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643519EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.m */; }; D03764FF19EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643519EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.m */; }; D037650019EDA41200A782A9 /* NSFileHandle+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643619EDA41200A782A9 /* NSFileHandle+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037650119EDA41200A782A9 /* NSFileHandle+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643619EDA41200A782A9 /* NSFileHandle+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037650219EDA41200A782A9 /* NSFileHandle+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643719EDA41200A782A9 /* NSFileHandle+RACSupport.m */; }; D037650319EDA41200A782A9 /* NSFileHandle+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643719EDA41200A782A9 /* NSFileHandle+RACSupport.m */; }; D037650419EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643819EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037650519EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643819EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037650619EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643919EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.m */; }; D037650719EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643919EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.m */; }; D037650A19EDA41200A782A9 /* NSInvocation+RACTypeParsing.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643B19EDA41200A782A9 /* NSInvocation+RACTypeParsing.m */; }; D037650B19EDA41200A782A9 /* NSInvocation+RACTypeParsing.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643B19EDA41200A782A9 /* NSInvocation+RACTypeParsing.m */; }; D037650C19EDA41200A782A9 /* NSNotificationCenter+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643C19EDA41200A782A9 /* NSNotificationCenter+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037650D19EDA41200A782A9 /* NSNotificationCenter+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643C19EDA41200A782A9 /* NSNotificationCenter+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037650E19EDA41200A782A9 /* NSNotificationCenter+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643D19EDA41200A782A9 /* NSNotificationCenter+RACSupport.m */; }; D037650F19EDA41200A782A9 /* NSNotificationCenter+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643D19EDA41200A782A9 /* NSNotificationCenter+RACSupport.m */; }; D037651019EDA41200A782A9 /* NSObject+RACAppKitBindings.h in Headers */ = {isa = PBXBuildFile; fileRef = D037643E19EDA41200A782A9 /* NSObject+RACAppKitBindings.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037651219EDA41200A782A9 /* NSObject+RACAppKitBindings.m in Sources */ = {isa = PBXBuildFile; fileRef = D037643F19EDA41200A782A9 /* NSObject+RACAppKitBindings.m */; }; D037651419EDA41200A782A9 /* NSObject+RACDeallocating.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644019EDA41200A782A9 /* NSObject+RACDeallocating.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037651519EDA41200A782A9 /* NSObject+RACDeallocating.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644019EDA41200A782A9 /* NSObject+RACDeallocating.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037651619EDA41200A782A9 /* NSObject+RACDeallocating.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644119EDA41200A782A9 /* NSObject+RACDeallocating.m */; }; D037651719EDA41200A782A9 /* NSObject+RACDeallocating.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644119EDA41200A782A9 /* NSObject+RACDeallocating.m */; }; D037651A19EDA41200A782A9 /* NSObject+RACDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644319EDA41200A782A9 /* NSObject+RACDescription.m */; }; D037651B19EDA41200A782A9 /* NSObject+RACDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644319EDA41200A782A9 /* NSObject+RACDescription.m */; }; D037651E19EDA41200A782A9 /* NSObject+RACKVOWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644519EDA41200A782A9 /* NSObject+RACKVOWrapper.m */; }; D037651F19EDA41200A782A9 /* NSObject+RACKVOWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644519EDA41200A782A9 /* NSObject+RACKVOWrapper.m */; }; D037652019EDA41200A782A9 /* NSObject+RACLifting.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644619EDA41200A782A9 /* NSObject+RACLifting.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037652119EDA41200A782A9 /* NSObject+RACLifting.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644619EDA41200A782A9 /* NSObject+RACLifting.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037652219EDA41200A782A9 /* NSObject+RACLifting.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644719EDA41200A782A9 /* NSObject+RACLifting.m */; }; D037652319EDA41200A782A9 /* NSObject+RACLifting.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644719EDA41200A782A9 /* NSObject+RACLifting.m */; }; D037652419EDA41200A782A9 /* NSObject+RACPropertySubscribing.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644819EDA41200A782A9 /* NSObject+RACPropertySubscribing.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037652519EDA41200A782A9 /* NSObject+RACPropertySubscribing.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644819EDA41200A782A9 /* NSObject+RACPropertySubscribing.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037652619EDA41200A782A9 /* NSObject+RACPropertySubscribing.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644919EDA41200A782A9 /* NSObject+RACPropertySubscribing.m */; }; D037652719EDA41200A782A9 /* NSObject+RACPropertySubscribing.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644919EDA41200A782A9 /* NSObject+RACPropertySubscribing.m */; }; D037652819EDA41200A782A9 /* NSObject+RACSelectorSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644A19EDA41200A782A9 /* NSObject+RACSelectorSignal.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037652919EDA41200A782A9 /* NSObject+RACSelectorSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644A19EDA41200A782A9 /* NSObject+RACSelectorSignal.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037652A19EDA41200A782A9 /* NSObject+RACSelectorSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644B19EDA41200A782A9 /* NSObject+RACSelectorSignal.m */; }; D037652B19EDA41200A782A9 /* NSObject+RACSelectorSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644B19EDA41200A782A9 /* NSObject+RACSelectorSignal.m */; }; D037652C19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644C19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037652D19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644C19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037652E19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644D19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.m */; }; D037652F19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644D19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.m */; }; D037653019EDA41200A782A9 /* NSSet+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644E19EDA41200A782A9 /* NSSet+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037653119EDA41200A782A9 /* NSSet+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037644E19EDA41200A782A9 /* NSSet+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037653219EDA41200A782A9 /* NSSet+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644F19EDA41200A782A9 /* NSSet+RACSequenceAdditions.m */; }; D037653319EDA41200A782A9 /* NSSet+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037644F19EDA41200A782A9 /* NSSet+RACSequenceAdditions.m */; }; D037653619EDA41200A782A9 /* NSString+RACKeyPathUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645119EDA41200A782A9 /* NSString+RACKeyPathUtilities.m */; }; D037653719EDA41200A782A9 /* NSString+RACKeyPathUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645119EDA41200A782A9 /* NSString+RACKeyPathUtilities.m */; }; D037653819EDA41200A782A9 /* NSString+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037645219EDA41200A782A9 /* NSString+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037653919EDA41200A782A9 /* NSString+RACSequenceAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = D037645219EDA41200A782A9 /* NSString+RACSequenceAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037653A19EDA41200A782A9 /* NSString+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645319EDA41200A782A9 /* NSString+RACSequenceAdditions.m */; }; D037653B19EDA41200A782A9 /* NSString+RACSequenceAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645319EDA41200A782A9 /* NSString+RACSequenceAdditions.m */; }; D037653C19EDA41200A782A9 /* NSString+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037645419EDA41200A782A9 /* NSString+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037653D19EDA41200A782A9 /* NSString+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037645419EDA41200A782A9 /* NSString+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037653E19EDA41200A782A9 /* NSString+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645519EDA41200A782A9 /* NSString+RACSupport.m */; }; D037653F19EDA41200A782A9 /* NSString+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645519EDA41200A782A9 /* NSString+RACSupport.m */; }; D037654019EDA41200A782A9 /* NSText+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037645619EDA41200A782A9 /* NSText+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037654219EDA41200A782A9 /* NSText+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645719EDA41200A782A9 /* NSText+RACSignalSupport.m */; }; D037654419EDA41200A782A9 /* NSURLConnection+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037645819EDA41200A782A9 /* NSURLConnection+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037654519EDA41200A782A9 /* NSURLConnection+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037645819EDA41200A782A9 /* NSURLConnection+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037654619EDA41200A782A9 /* NSURLConnection+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645919EDA41200A782A9 /* NSURLConnection+RACSupport.m */; }; D037654719EDA41200A782A9 /* NSURLConnection+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645919EDA41200A782A9 /* NSURLConnection+RACSupport.m */; }; D037654819EDA41200A782A9 /* NSUserDefaults+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037645A19EDA41200A782A9 /* NSUserDefaults+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037654919EDA41200A782A9 /* NSUserDefaults+RACSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D037645A19EDA41200A782A9 /* NSUserDefaults+RACSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037654A19EDA41200A782A9 /* NSUserDefaults+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645B19EDA41200A782A9 /* NSUserDefaults+RACSupport.m */; }; D037654B19EDA41200A782A9 /* NSUserDefaults+RACSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645B19EDA41200A782A9 /* NSUserDefaults+RACSupport.m */; }; D037654E19EDA41200A782A9 /* RACArraySequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645D19EDA41200A782A9 /* RACArraySequence.m */; }; D037654F19EDA41200A782A9 /* RACArraySequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037645D19EDA41200A782A9 /* RACArraySequence.m */; }; D037655619EDA41200A782A9 /* RACBehaviorSubject.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646119EDA41200A782A9 /* RACBehaviorSubject.m */; }; D037655719EDA41200A782A9 /* RACBehaviorSubject.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646119EDA41200A782A9 /* RACBehaviorSubject.m */; }; D037655A19EDA41200A782A9 /* RACBlockTrampoline.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646319EDA41200A782A9 /* RACBlockTrampoline.m */; }; D037655B19EDA41200A782A9 /* RACBlockTrampoline.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646319EDA41200A782A9 /* RACBlockTrampoline.m */; }; D037655C19EDA41200A782A9 /* RACChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646419EDA41200A782A9 /* RACChannel.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037655D19EDA41200A782A9 /* RACChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646419EDA41200A782A9 /* RACChannel.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037655E19EDA41200A782A9 /* RACChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646519EDA41200A782A9 /* RACChannel.m */; }; D037655F19EDA41200A782A9 /* RACChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646519EDA41200A782A9 /* RACChannel.m */; }; D037656019EDA41200A782A9 /* RACCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646619EDA41200A782A9 /* RACCommand.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037656119EDA41200A782A9 /* RACCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646619EDA41200A782A9 /* RACCommand.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037656219EDA41200A782A9 /* RACCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646719EDA41200A782A9 /* RACCommand.m */; }; D037656319EDA41200A782A9 /* RACCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646719EDA41200A782A9 /* RACCommand.m */; }; D037656419EDA41200A782A9 /* RACCompoundDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646819EDA41200A782A9 /* RACCompoundDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037656519EDA41200A782A9 /* RACCompoundDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646819EDA41200A782A9 /* RACCompoundDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037656619EDA41200A782A9 /* RACCompoundDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646919EDA41200A782A9 /* RACCompoundDisposable.m */; }; D037656719EDA41200A782A9 /* RACCompoundDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646919EDA41200A782A9 /* RACCompoundDisposable.m */; }; D037656819EDA41200A782A9 /* RACCompoundDisposableProvider.d in Sources */ = {isa = PBXBuildFile; fileRef = D037646A19EDA41200A782A9 /* RACCompoundDisposableProvider.d */; }; D037656919EDA41200A782A9 /* RACCompoundDisposableProvider.d in Sources */ = {isa = PBXBuildFile; fileRef = D037646A19EDA41200A782A9 /* RACCompoundDisposableProvider.d */; }; D037656C19EDA41200A782A9 /* RACDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646C19EDA41200A782A9 /* RACDelegateProxy.m */; }; D037656D19EDA41200A782A9 /* RACDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646C19EDA41200A782A9 /* RACDelegateProxy.m */; }; D037656E19EDA41200A782A9 /* RACDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646D19EDA41200A782A9 /* RACDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037656F19EDA41200A782A9 /* RACDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646D19EDA41200A782A9 /* RACDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037657019EDA41200A782A9 /* RACDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646E19EDA41200A782A9 /* RACDisposable.m */; }; D037657119EDA41200A782A9 /* RACDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D037646E19EDA41200A782A9 /* RACDisposable.m */; }; D037657419EDA41200A782A9 /* RACDynamicSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647019EDA41200A782A9 /* RACDynamicSequence.m */; }; D037657519EDA41200A782A9 /* RACDynamicSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647019EDA41200A782A9 /* RACDynamicSequence.m */; }; D037657819EDA41200A782A9 /* RACDynamicSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647219EDA41200A782A9 /* RACDynamicSignal.m */; }; D037657919EDA41200A782A9 /* RACDynamicSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647219EDA41200A782A9 /* RACDynamicSignal.m */; }; D037657C19EDA41200A782A9 /* RACEagerSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647419EDA41200A782A9 /* RACEagerSequence.m */; }; D037657D19EDA41200A782A9 /* RACEagerSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647419EDA41200A782A9 /* RACEagerSequence.m */; }; D037658019EDA41200A782A9 /* RACEmptySequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647619EDA41200A782A9 /* RACEmptySequence.m */; }; D037658119EDA41200A782A9 /* RACEmptySequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647619EDA41200A782A9 /* RACEmptySequence.m */; }; D037658419EDA41200A782A9 /* RACEmptySignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647819EDA41200A782A9 /* RACEmptySignal.m */; }; D037658519EDA41200A782A9 /* RACEmptySignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647819EDA41200A782A9 /* RACEmptySignal.m */; }; D037658819EDA41200A782A9 /* RACErrorSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647A19EDA41200A782A9 /* RACErrorSignal.m */; }; D037658919EDA41200A782A9 /* RACErrorSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647A19EDA41200A782A9 /* RACErrorSignal.m */; }; D037658A19EDA41200A782A9 /* RACEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = D037647B19EDA41200A782A9 /* RACEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037658B19EDA41200A782A9 /* RACEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = D037647B19EDA41200A782A9 /* RACEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037658C19EDA41200A782A9 /* RACEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647C19EDA41200A782A9 /* RACEvent.m */; }; D037658D19EDA41200A782A9 /* RACEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647C19EDA41200A782A9 /* RACEvent.m */; }; D037658E19EDA41200A782A9 /* RACGroupedSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = D037647D19EDA41200A782A9 /* RACGroupedSignal.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037658F19EDA41200A782A9 /* RACGroupedSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = D037647D19EDA41200A782A9 /* RACGroupedSignal.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037659019EDA41200A782A9 /* RACGroupedSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647E19EDA41200A782A9 /* RACGroupedSignal.m */; }; D037659119EDA41200A782A9 /* RACGroupedSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037647E19EDA41200A782A9 /* RACGroupedSignal.m */; }; D037659419EDA41200A782A9 /* RACImmediateScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648019EDA41200A782A9 /* RACImmediateScheduler.m */; }; D037659519EDA41200A782A9 /* RACImmediateScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648019EDA41200A782A9 /* RACImmediateScheduler.m */; }; D037659819EDA41200A782A9 /* RACIndexSetSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648219EDA41200A782A9 /* RACIndexSetSequence.m */; }; D037659919EDA41200A782A9 /* RACIndexSetSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648219EDA41200A782A9 /* RACIndexSetSequence.m */; }; D037659A19EDA41200A782A9 /* RACKVOChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = D037648319EDA41200A782A9 /* RACKVOChannel.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037659B19EDA41200A782A9 /* RACKVOChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = D037648319EDA41200A782A9 /* RACKVOChannel.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037659C19EDA41200A782A9 /* RACKVOChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648419EDA41200A782A9 /* RACKVOChannel.m */; }; D037659D19EDA41200A782A9 /* RACKVOChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648419EDA41200A782A9 /* RACKVOChannel.m */; }; D03765A019EDA41200A782A9 /* RACKVOTrampoline.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648619EDA41200A782A9 /* RACKVOTrampoline.m */; }; D03765A119EDA41200A782A9 /* RACKVOTrampoline.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648619EDA41200A782A9 /* RACKVOTrampoline.m */; }; D03765A219EDA41200A782A9 /* RACMulticastConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = D037648719EDA41200A782A9 /* RACMulticastConnection.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765A319EDA41200A782A9 /* RACMulticastConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = D037648719EDA41200A782A9 /* RACMulticastConnection.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765A419EDA41200A782A9 /* RACMulticastConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648819EDA41200A782A9 /* RACMulticastConnection.m */; }; D03765A519EDA41200A782A9 /* RACMulticastConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648819EDA41200A782A9 /* RACMulticastConnection.m */; }; D03765AA19EDA41200A782A9 /* RACObjCRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648B19EDA41200A782A9 /* RACObjCRuntime.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; D03765AB19EDA41200A782A9 /* RACObjCRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648B19EDA41200A782A9 /* RACObjCRuntime.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; D03765AE19EDA41200A782A9 /* RACPassthroughSubscriber.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648D19EDA41200A782A9 /* RACPassthroughSubscriber.m */; }; D03765AF19EDA41200A782A9 /* RACPassthroughSubscriber.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648D19EDA41200A782A9 /* RACPassthroughSubscriber.m */; }; D03765B019EDA41200A782A9 /* RACQueueScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = D037648E19EDA41200A782A9 /* RACQueueScheduler.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765B119EDA41200A782A9 /* RACQueueScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = D037648E19EDA41200A782A9 /* RACQueueScheduler.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765B219EDA41200A782A9 /* RACQueueScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648F19EDA41200A782A9 /* RACQueueScheduler.m */; }; D03765B319EDA41200A782A9 /* RACQueueScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D037648F19EDA41200A782A9 /* RACQueueScheduler.m */; }; D03765B419EDA41200A782A9 /* RACQueueScheduler+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649019EDA41200A782A9 /* RACQueueScheduler+Subclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765B519EDA41200A782A9 /* RACQueueScheduler+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649019EDA41200A782A9 /* RACQueueScheduler+Subclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765B619EDA41200A782A9 /* RACReplaySubject.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649119EDA41200A782A9 /* RACReplaySubject.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765B719EDA41200A782A9 /* RACReplaySubject.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649119EDA41200A782A9 /* RACReplaySubject.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765B819EDA41200A782A9 /* RACReplaySubject.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649219EDA41200A782A9 /* RACReplaySubject.m */; }; D03765B919EDA41200A782A9 /* RACReplaySubject.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649219EDA41200A782A9 /* RACReplaySubject.m */; }; D03765BC19EDA41200A782A9 /* RACReturnSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649419EDA41200A782A9 /* RACReturnSignal.m */; }; D03765BD19EDA41200A782A9 /* RACReturnSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649419EDA41200A782A9 /* RACReturnSignal.m */; }; D03765BE19EDA41200A782A9 /* RACScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649519EDA41200A782A9 /* RACScheduler.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765BF19EDA41200A782A9 /* RACScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649519EDA41200A782A9 /* RACScheduler.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765C019EDA41200A782A9 /* RACScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649619EDA41200A782A9 /* RACScheduler.m */; }; D03765C119EDA41200A782A9 /* RACScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649619EDA41200A782A9 /* RACScheduler.m */; }; D03765C419EDA41200A782A9 /* RACScheduler+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649819EDA41200A782A9 /* RACScheduler+Subclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765C519EDA41200A782A9 /* RACScheduler+Subclass.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649819EDA41200A782A9 /* RACScheduler+Subclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765C619EDA41200A782A9 /* RACScopedDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649919EDA41200A782A9 /* RACScopedDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765C719EDA41200A782A9 /* RACScopedDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649919EDA41200A782A9 /* RACScopedDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765C819EDA41200A782A9 /* RACScopedDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649A19EDA41200A782A9 /* RACScopedDisposable.m */; }; D03765C919EDA41200A782A9 /* RACScopedDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649A19EDA41200A782A9 /* RACScopedDisposable.m */; }; D03765CA19EDA41200A782A9 /* RACSequence.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649B19EDA41200A782A9 /* RACSequence.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765CB19EDA41200A782A9 /* RACSequence.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649B19EDA41200A782A9 /* RACSequence.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765CC19EDA41200A782A9 /* RACSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649C19EDA41200A782A9 /* RACSequence.m */; }; D03765CD19EDA41200A782A9 /* RACSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649C19EDA41200A782A9 /* RACSequence.m */; }; D03765CE19EDA41200A782A9 /* RACSerialDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649D19EDA41200A782A9 /* RACSerialDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765CF19EDA41200A782A9 /* RACSerialDisposable.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649D19EDA41200A782A9 /* RACSerialDisposable.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765D019EDA41200A782A9 /* RACSerialDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649E19EDA41200A782A9 /* RACSerialDisposable.m */; }; D03765D119EDA41200A782A9 /* RACSerialDisposable.m in Sources */ = {isa = PBXBuildFile; fileRef = D037649E19EDA41200A782A9 /* RACSerialDisposable.m */; }; D03765D219EDA41200A782A9 /* RACSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649F19EDA41200A782A9 /* RACSignal.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765D319EDA41200A782A9 /* RACSignal.h in Headers */ = {isa = PBXBuildFile; fileRef = D037649F19EDA41200A782A9 /* RACSignal.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765D419EDA41200A782A9 /* RACSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764A019EDA41200A782A9 /* RACSignal.m */; }; D03765D519EDA41200A782A9 /* RACSignal.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764A019EDA41200A782A9 /* RACSignal.m */; }; D03765D619EDA41200A782A9 /* RACSignal+Operations.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764A119EDA41200A782A9 /* RACSignal+Operations.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765D719EDA41200A782A9 /* RACSignal+Operations.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764A119EDA41200A782A9 /* RACSignal+Operations.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765D819EDA41200A782A9 /* RACSignal+Operations.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764A219EDA41200A782A9 /* RACSignal+Operations.m */; }; D03765D919EDA41200A782A9 /* RACSignal+Operations.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764A219EDA41200A782A9 /* RACSignal+Operations.m */; }; D03765DA19EDA41200A782A9 /* RACSignalProvider.d in Sources */ = {isa = PBXBuildFile; fileRef = D03764A319EDA41200A782A9 /* RACSignalProvider.d */; }; D03765DB19EDA41200A782A9 /* RACSignalProvider.d in Sources */ = {isa = PBXBuildFile; fileRef = D03764A319EDA41200A782A9 /* RACSignalProvider.d */; }; D03765DE19EDA41200A782A9 /* RACSignalSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764A519EDA41200A782A9 /* RACSignalSequence.m */; }; D03765DF19EDA41200A782A9 /* RACSignalSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764A519EDA41200A782A9 /* RACSignalSequence.m */; }; D03765E019EDA41200A782A9 /* RACStream.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764A619EDA41200A782A9 /* RACStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765E119EDA41200A782A9 /* RACStream.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764A619EDA41200A782A9 /* RACStream.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765E219EDA41200A782A9 /* RACStream.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764A719EDA41200A782A9 /* RACStream.m */; }; D03765E319EDA41200A782A9 /* RACStream.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764A719EDA41200A782A9 /* RACStream.m */; }; D03765E819EDA41200A782A9 /* RACStringSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764AA19EDA41200A782A9 /* RACStringSequence.m */; }; D03765E919EDA41200A782A9 /* RACStringSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764AA19EDA41200A782A9 /* RACStringSequence.m */; }; D03765EA19EDA41200A782A9 /* RACSubject.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764AB19EDA41200A782A9 /* RACSubject.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765EB19EDA41200A782A9 /* RACSubject.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764AB19EDA41200A782A9 /* RACSubject.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765EC19EDA41200A782A9 /* RACSubject.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764AC19EDA41200A782A9 /* RACSubject.m */; }; D03765ED19EDA41200A782A9 /* RACSubject.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764AC19EDA41200A782A9 /* RACSubject.m */; }; D03765EE19EDA41200A782A9 /* RACSubscriber.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764AD19EDA41200A782A9 /* RACSubscriber.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765EF19EDA41200A782A9 /* RACSubscriber.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764AD19EDA41200A782A9 /* RACSubscriber.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765F019EDA41200A782A9 /* RACSubscriber.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764AE19EDA41200A782A9 /* RACSubscriber.m */; }; D03765F119EDA41200A782A9 /* RACSubscriber.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764AE19EDA41200A782A9 /* RACSubscriber.m */; }; D03765F419EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764B019EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765F519EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764B019EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765F619EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B119EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.m */; }; D03765F719EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B119EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.m */; }; D03765FA19EDA41200A782A9 /* RACSubscriptionScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B319EDA41200A782A9 /* RACSubscriptionScheduler.m */; }; D03765FB19EDA41200A782A9 /* RACSubscriptionScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B319EDA41200A782A9 /* RACSubscriptionScheduler.m */; }; D03765FC19EDA41200A782A9 /* RACTargetQueueScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764B419EDA41200A782A9 /* RACTargetQueueScheduler.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765FD19EDA41200A782A9 /* RACTargetQueueScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764B419EDA41200A782A9 /* RACTargetQueueScheduler.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03765FE19EDA41200A782A9 /* RACTargetQueueScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B519EDA41200A782A9 /* RACTargetQueueScheduler.m */; }; D03765FF19EDA41200A782A9 /* RACTargetQueueScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B519EDA41200A782A9 /* RACTargetQueueScheduler.m */; }; D037660019EDA41200A782A9 /* RACTestScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764B619EDA41200A782A9 /* RACTestScheduler.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037660119EDA41200A782A9 /* RACTestScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764B619EDA41200A782A9 /* RACTestScheduler.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037660219EDA41200A782A9 /* RACTestScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B719EDA41200A782A9 /* RACTestScheduler.m */; }; D037660319EDA41200A782A9 /* RACTestScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B719EDA41200A782A9 /* RACTestScheduler.m */; }; D037660419EDA41200A782A9 /* RACTuple.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764B819EDA41200A782A9 /* RACTuple.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037660519EDA41200A782A9 /* RACTuple.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764B819EDA41200A782A9 /* RACTuple.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037660619EDA41200A782A9 /* RACTuple.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B919EDA41200A782A9 /* RACTuple.m */; }; D037660719EDA41200A782A9 /* RACTuple.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764B919EDA41200A782A9 /* RACTuple.m */; }; D037660A19EDA41200A782A9 /* RACTupleSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764BB19EDA41200A782A9 /* RACTupleSequence.m */; }; D037660B19EDA41200A782A9 /* RACTupleSequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764BB19EDA41200A782A9 /* RACTupleSequence.m */; }; D037660E19EDA41200A782A9 /* RACUnarySequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764BD19EDA41200A782A9 /* RACUnarySequence.m */; }; D037660F19EDA41200A782A9 /* RACUnarySequence.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764BD19EDA41200A782A9 /* RACUnarySequence.m */; }; D037661019EDA41200A782A9 /* RACUnit.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764BE19EDA41200A782A9 /* RACUnit.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037661119EDA41200A782A9 /* RACUnit.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764BE19EDA41200A782A9 /* RACUnit.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037661219EDA41200A782A9 /* RACUnit.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764BF19EDA41200A782A9 /* RACUnit.m */; }; D037661319EDA41200A782A9 /* RACUnit.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764BF19EDA41200A782A9 /* RACUnit.m */; }; D037661619EDA41200A782A9 /* RACValueTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764C119EDA41200A782A9 /* RACValueTransformer.m */; }; D037661719EDA41200A782A9 /* RACValueTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764C119EDA41200A782A9 /* RACValueTransformer.m */; }; D037661919EDA41200A782A9 /* UIActionSheet+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764C219EDA41200A782A9 /* UIActionSheet+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037661B19EDA41200A782A9 /* UIActionSheet+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764C319EDA41200A782A9 /* UIActionSheet+RACSignalSupport.m */; }; D037661D19EDA41200A782A9 /* UIAlertView+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764C419EDA41200A782A9 /* UIAlertView+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037661F19EDA41200A782A9 /* UIAlertView+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764C519EDA41200A782A9 /* UIAlertView+RACSignalSupport.m */; }; D037662119EDA41200A782A9 /* UIBarButtonItem+RACCommandSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764C619EDA41200A782A9 /* UIBarButtonItem+RACCommandSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037662319EDA41200A782A9 /* UIBarButtonItem+RACCommandSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764C719EDA41200A782A9 /* UIBarButtonItem+RACCommandSupport.m */; }; D037662519EDA41200A782A9 /* UIButton+RACCommandSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764C819EDA41200A782A9 /* UIButton+RACCommandSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037662719EDA41200A782A9 /* UIButton+RACCommandSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764C919EDA41200A782A9 /* UIButton+RACCommandSupport.m */; }; D037662919EDA41200A782A9 /* UICollectionReusableView+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764CA19EDA41200A782A9 /* UICollectionReusableView+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037662B19EDA41200A782A9 /* UICollectionReusableView+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764CB19EDA41200A782A9 /* UICollectionReusableView+RACSignalSupport.m */; }; D037662D19EDA41200A782A9 /* UIControl+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764CC19EDA41200A782A9 /* UIControl+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037662F19EDA41200A782A9 /* UIControl+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764CD19EDA41200A782A9 /* UIControl+RACSignalSupport.m */; }; D037663319EDA41200A782A9 /* UIControl+RACSignalSupportPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764CF19EDA41200A782A9 /* UIControl+RACSignalSupportPrivate.m */; }; D037663519EDA41200A782A9 /* UIDatePicker+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764D019EDA41200A782A9 /* UIDatePicker+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037663719EDA41200A782A9 /* UIDatePicker+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764D119EDA41200A782A9 /* UIDatePicker+RACSignalSupport.m */; }; D037663919EDA41200A782A9 /* UIGestureRecognizer+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764D219EDA41200A782A9 /* UIGestureRecognizer+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037663B19EDA41200A782A9 /* UIGestureRecognizer+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764D319EDA41200A782A9 /* UIGestureRecognizer+RACSignalSupport.m */; }; D037663D19EDA41200A782A9 /* UIImagePickerController+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764D419EDA41200A782A9 /* UIImagePickerController+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037663F19EDA41200A782A9 /* UIImagePickerController+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764D519EDA41200A782A9 /* UIImagePickerController+RACSignalSupport.m */; }; D037664119EDA41200A782A9 /* UIRefreshControl+RACCommandSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764D619EDA41200A782A9 /* UIRefreshControl+RACCommandSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037664319EDA41200A782A9 /* UIRefreshControl+RACCommandSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764D719EDA41200A782A9 /* UIRefreshControl+RACCommandSupport.m */; }; D037664519EDA41200A782A9 /* UISegmentedControl+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764D819EDA41200A782A9 /* UISegmentedControl+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037664719EDA41200A782A9 /* UISegmentedControl+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764D919EDA41200A782A9 /* UISegmentedControl+RACSignalSupport.m */; }; D037664919EDA41200A782A9 /* UISlider+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764DA19EDA41200A782A9 /* UISlider+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037664B19EDA41200A782A9 /* UISlider+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764DB19EDA41200A782A9 /* UISlider+RACSignalSupport.m */; }; D037664D19EDA41200A782A9 /* UIStepper+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764DC19EDA41200A782A9 /* UIStepper+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037664F19EDA41200A782A9 /* UIStepper+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764DD19EDA41200A782A9 /* UIStepper+RACSignalSupport.m */; }; D037665119EDA41200A782A9 /* UISwitch+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764DE19EDA41200A782A9 /* UISwitch+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037665319EDA41200A782A9 /* UISwitch+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764DF19EDA41200A782A9 /* UISwitch+RACSignalSupport.m */; }; D037665519EDA41200A782A9 /* UITableViewCell+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764E019EDA41200A782A9 /* UITableViewCell+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037665719EDA41200A782A9 /* UITableViewCell+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764E119EDA41200A782A9 /* UITableViewCell+RACSignalSupport.m */; }; D037665919EDA41200A782A9 /* UITableViewHeaderFooterView+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764E219EDA41200A782A9 /* UITableViewHeaderFooterView+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037665B19EDA41200A782A9 /* UITableViewHeaderFooterView+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764E319EDA41200A782A9 /* UITableViewHeaderFooterView+RACSignalSupport.m */; }; D037665D19EDA41200A782A9 /* UITextField+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764E419EDA41200A782A9 /* UITextField+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037665F19EDA41200A782A9 /* UITextField+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764E519EDA41200A782A9 /* UITextField+RACSignalSupport.m */; }; D037666119EDA41200A782A9 /* UITextView+RACSignalSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = D03764E619EDA41200A782A9 /* UITextView+RACSignalSupport.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037666319EDA41200A782A9 /* UITextView+RACSignalSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = D03764E719EDA41200A782A9 /* UITextView+RACSignalSupport.m */; }; D037666419EDA43C00A782A9 /* ReactiveCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = D04725EF19E49ED7006002AA /* ReactiveCocoa.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037666B19EDA57100A782A9 /* EXTKeyPathCoding.h in Headers */ = {isa = PBXBuildFile; fileRef = D037666619EDA57100A782A9 /* EXTKeyPathCoding.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037666C19EDA57100A782A9 /* EXTKeyPathCoding.h in Headers */ = {isa = PBXBuildFile; fileRef = D037666619EDA57100A782A9 /* EXTKeyPathCoding.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037666F19EDA57100A782A9 /* EXTRuntimeExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037666819EDA57100A782A9 /* EXTRuntimeExtensions.m */; }; D037667019EDA57100A782A9 /* EXTRuntimeExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = D037666819EDA57100A782A9 /* EXTRuntimeExtensions.m */; }; D037667119EDA57100A782A9 /* EXTScope.h in Headers */ = {isa = PBXBuildFile; fileRef = D037666919EDA57100A782A9 /* EXTScope.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037667219EDA57100A782A9 /* EXTScope.h in Headers */ = {isa = PBXBuildFile; fileRef = D037666919EDA57100A782A9 /* EXTScope.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037667319EDA57100A782A9 /* metamacros.h in Headers */ = {isa = PBXBuildFile; fileRef = D037666A19EDA57100A782A9 /* metamacros.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037667419EDA57100A782A9 /* metamacros.h in Headers */ = {isa = PBXBuildFile; fileRef = D037666A19EDA57100A782A9 /* metamacros.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03766B919EDA60000A782A9 /* NSControllerRACSupportSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037667619EDA60000A782A9 /* NSControllerRACSupportSpec.m */; }; D03766BD19EDA60000A782A9 /* NSEnumeratorRACSequenceAdditionsSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037667819EDA60000A782A9 /* NSEnumeratorRACSequenceAdditionsSpec.m */; }; D03766BE19EDA60000A782A9 /* NSEnumeratorRACSequenceAdditionsSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037667819EDA60000A782A9 /* NSEnumeratorRACSequenceAdditionsSpec.m */; }; D03766BF19EDA60000A782A9 /* NSNotificationCenterRACSupportSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037667919EDA60000A782A9 /* NSNotificationCenterRACSupportSpec.m */; }; D03766C019EDA60000A782A9 /* NSNotificationCenterRACSupportSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037667919EDA60000A782A9 /* NSNotificationCenterRACSupportSpec.m */; }; D03766C119EDA60000A782A9 /* NSObjectRACAppKitBindingsSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037667A19EDA60000A782A9 /* NSObjectRACAppKitBindingsSpec.m */; }; D03766C319EDA60000A782A9 /* NSObjectRACDeallocatingSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037667B19EDA60000A782A9 /* NSObjectRACDeallocatingSpec.m */; }; D03766C419EDA60000A782A9 /* NSObjectRACDeallocatingSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037667B19EDA60000A782A9 /* NSObjectRACDeallocatingSpec.m */; }; D03766C519EDA60000A782A9 /* NSObjectRACLiftingSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037667C19EDA60000A782A9 /* NSObjectRACLiftingSpec.m */; }; D03766C619EDA60000A782A9 /* NSObjectRACLiftingSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037667C19EDA60000A782A9 /* NSObjectRACLiftingSpec.m */; }; D03766C719EDA60000A782A9 /* NSObjectRACPropertySubscribingExamples.m in Sources */ = {isa = PBXBuildFile; fileRef = D037667E19EDA60000A782A9 /* NSObjectRACPropertySubscribingExamples.m */; }; D03766C819EDA60000A782A9 /* NSObjectRACPropertySubscribingExamples.m in Sources */ = {isa = PBXBuildFile; fileRef = D037667E19EDA60000A782A9 /* NSObjectRACPropertySubscribingExamples.m */; }; D03766C919EDA60000A782A9 /* NSObjectRACPropertySubscribingSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037667F19EDA60000A782A9 /* NSObjectRACPropertySubscribingSpec.m */; }; D03766CA19EDA60000A782A9 /* NSObjectRACPropertySubscribingSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037667F19EDA60000A782A9 /* NSObjectRACPropertySubscribingSpec.m */; }; D03766CB19EDA60000A782A9 /* NSObjectRACSelectorSignalSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668019EDA60000A782A9 /* NSObjectRACSelectorSignalSpec.m */; }; D03766CC19EDA60000A782A9 /* NSObjectRACSelectorSignalSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668019EDA60000A782A9 /* NSObjectRACSelectorSignalSpec.m */; }; D03766CD19EDA60000A782A9 /* NSStringRACKeyPathUtilitiesSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668119EDA60000A782A9 /* NSStringRACKeyPathUtilitiesSpec.m */; }; D03766CE19EDA60000A782A9 /* NSStringRACKeyPathUtilitiesSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668119EDA60000A782A9 /* NSStringRACKeyPathUtilitiesSpec.m */; }; D03766D119EDA60000A782A9 /* NSURLConnectionRACSupportSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668319EDA60000A782A9 /* NSURLConnectionRACSupportSpec.m */; }; D03766D219EDA60000A782A9 /* NSURLConnectionRACSupportSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668319EDA60000A782A9 /* NSURLConnectionRACSupportSpec.m */; }; D03766D319EDA60000A782A9 /* NSUserDefaultsRACSupportSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668419EDA60000A782A9 /* NSUserDefaultsRACSupportSpec.m */; }; D03766D419EDA60000A782A9 /* NSUserDefaultsRACSupportSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668419EDA60000A782A9 /* NSUserDefaultsRACSupportSpec.m */; }; D03766D719EDA60000A782A9 /* RACBlockTrampolineSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668619EDA60000A782A9 /* RACBlockTrampolineSpec.m */; }; D03766D819EDA60000A782A9 /* RACBlockTrampolineSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668619EDA60000A782A9 /* RACBlockTrampolineSpec.m */; }; D03766D919EDA60000A782A9 /* RACChannelExamples.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668819EDA60000A782A9 /* RACChannelExamples.m */; }; D03766DA19EDA60000A782A9 /* RACChannelExamples.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668819EDA60000A782A9 /* RACChannelExamples.m */; }; D03766DB19EDA60000A782A9 /* RACChannelSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668919EDA60000A782A9 /* RACChannelSpec.m */; }; D03766DC19EDA60000A782A9 /* RACChannelSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668919EDA60000A782A9 /* RACChannelSpec.m */; }; D03766DD19EDA60000A782A9 /* RACCommandSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668A19EDA60000A782A9 /* RACCommandSpec.m */; }; D03766DE19EDA60000A782A9 /* RACCommandSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668A19EDA60000A782A9 /* RACCommandSpec.m */; }; D03766DF19EDA60000A782A9 /* RACCompoundDisposableSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668B19EDA60000A782A9 /* RACCompoundDisposableSpec.m */; }; D03766E019EDA60000A782A9 /* RACCompoundDisposableSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668B19EDA60000A782A9 /* RACCompoundDisposableSpec.m */; }; D03766E119EDA60000A782A9 /* RACControlCommandExamples.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668D19EDA60000A782A9 /* RACControlCommandExamples.m */; }; D03766E219EDA60000A782A9 /* RACControlCommandExamples.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668D19EDA60000A782A9 /* RACControlCommandExamples.m */; }; D03766E319EDA60000A782A9 /* RACDelegateProxySpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668E19EDA60000A782A9 /* RACDelegateProxySpec.m */; }; D03766E419EDA60000A782A9 /* RACDelegateProxySpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668E19EDA60000A782A9 /* RACDelegateProxySpec.m */; }; D03766E519EDA60000A782A9 /* RACDisposableSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668F19EDA60000A782A9 /* RACDisposableSpec.m */; }; D03766E619EDA60000A782A9 /* RACDisposableSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037668F19EDA60000A782A9 /* RACDisposableSpec.m */; }; D03766E719EDA60000A782A9 /* RACEventSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669019EDA60000A782A9 /* RACEventSpec.m */; }; D03766E819EDA60000A782A9 /* RACEventSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669019EDA60000A782A9 /* RACEventSpec.m */; }; D03766E919EDA60000A782A9 /* RACKVOChannelSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669119EDA60000A782A9 /* RACKVOChannelSpec.m */; }; D03766EA19EDA60000A782A9 /* RACKVOChannelSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669119EDA60000A782A9 /* RACKVOChannelSpec.m */; }; D03766EB19EDA60000A782A9 /* RACKVOWrapperSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669219EDA60000A782A9 /* RACKVOWrapperSpec.m */; }; D03766EC19EDA60000A782A9 /* RACKVOWrapperSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669219EDA60000A782A9 /* RACKVOWrapperSpec.m */; }; D03766ED19EDA60000A782A9 /* RACMulticastConnectionSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669319EDA60000A782A9 /* RACMulticastConnectionSpec.m */; }; D03766EE19EDA60000A782A9 /* RACMulticastConnectionSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669319EDA60000A782A9 /* RACMulticastConnectionSpec.m */; }; D03766EF19EDA60000A782A9 /* RACPropertySignalExamples.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669519EDA60000A782A9 /* RACPropertySignalExamples.m */; }; D03766F019EDA60000A782A9 /* RACPropertySignalExamples.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669519EDA60000A782A9 /* RACPropertySignalExamples.m */; }; D03766F119EDA60000A782A9 /* RACSchedulerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669619EDA60000A782A9 /* RACSchedulerSpec.m */; }; D03766F219EDA60000A782A9 /* RACSchedulerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669619EDA60000A782A9 /* RACSchedulerSpec.m */; }; D03766F319EDA60000A782A9 /* RACSequenceAdditionsSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669719EDA60000A782A9 /* RACSequenceAdditionsSpec.m */; }; D03766F419EDA60000A782A9 /* RACSequenceAdditionsSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669719EDA60000A782A9 /* RACSequenceAdditionsSpec.m */; }; D03766F519EDA60000A782A9 /* RACSequenceExamples.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669919EDA60000A782A9 /* RACSequenceExamples.m */; }; D03766F619EDA60000A782A9 /* RACSequenceExamples.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669919EDA60000A782A9 /* RACSequenceExamples.m */; }; D03766F719EDA60000A782A9 /* RACSequenceSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669A19EDA60000A782A9 /* RACSequenceSpec.m */; }; D03766F819EDA60000A782A9 /* RACSequenceSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669A19EDA60000A782A9 /* RACSequenceSpec.m */; }; D03766F919EDA60000A782A9 /* RACSerialDisposableSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669B19EDA60000A782A9 /* RACSerialDisposableSpec.m */; }; D03766FA19EDA60000A782A9 /* RACSerialDisposableSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669B19EDA60000A782A9 /* RACSerialDisposableSpec.m */; }; D03766FB19EDA60000A782A9 /* RACSignalSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669C19EDA60000A782A9 /* RACSignalSpec.m */; }; D03766FC19EDA60000A782A9 /* RACSignalSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D037669C19EDA60000A782A9 /* RACSignalSpec.m */; }; D03766FF19EDA60000A782A9 /* RACStreamExamples.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766A019EDA60000A782A9 /* RACStreamExamples.m */; }; D037670019EDA60000A782A9 /* RACStreamExamples.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766A019EDA60000A782A9 /* RACStreamExamples.m */; }; D037670119EDA60000A782A9 /* RACSubclassObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766A219EDA60000A782A9 /* RACSubclassObject.m */; }; D037670219EDA60000A782A9 /* RACSubclassObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766A219EDA60000A782A9 /* RACSubclassObject.m */; }; D037670319EDA60000A782A9 /* RACSubjectSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766A319EDA60000A782A9 /* RACSubjectSpec.m */; }; D037670419EDA60000A782A9 /* RACSubjectSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766A319EDA60000A782A9 /* RACSubjectSpec.m */; }; D037670519EDA60000A782A9 /* RACSubscriberExamples.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766A519EDA60000A782A9 /* RACSubscriberExamples.m */; }; D037670619EDA60000A782A9 /* RACSubscriberExamples.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766A519EDA60000A782A9 /* RACSubscriberExamples.m */; }; D037670719EDA60000A782A9 /* RACSubscriberSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766A619EDA60000A782A9 /* RACSubscriberSpec.m */; }; D037670819EDA60000A782A9 /* RACSubscriberSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766A619EDA60000A782A9 /* RACSubscriberSpec.m */; }; D037670919EDA60000A782A9 /* RACSubscriptingAssignmentTrampolineSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766A719EDA60000A782A9 /* RACSubscriptingAssignmentTrampolineSpec.m */; }; D037670A19EDA60000A782A9 /* RACSubscriptingAssignmentTrampolineSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766A719EDA60000A782A9 /* RACSubscriptingAssignmentTrampolineSpec.m */; }; D037670B19EDA60000A782A9 /* RACTargetQueueSchedulerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766A819EDA60000A782A9 /* RACTargetQueueSchedulerSpec.m */; }; D037670C19EDA60000A782A9 /* RACTargetQueueSchedulerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766A819EDA60000A782A9 /* RACTargetQueueSchedulerSpec.m */; }; D037671519EDA60000A782A9 /* RACTupleSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766B019EDA60000A782A9 /* RACTupleSpec.m */; }; D037671619EDA60000A782A9 /* RACTupleSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766B019EDA60000A782A9 /* RACTupleSpec.m */; }; D037671719EDA60000A782A9 /* test-data.json in Resources */ = {isa = PBXBuildFile; fileRef = D03766B119EDA60000A782A9 /* test-data.json */; }; D037671819EDA60000A782A9 /* test-data.json in Resources */ = {isa = PBXBuildFile; fileRef = D03766B119EDA60000A782A9 /* test-data.json */; }; D037671A19EDA60000A782A9 /* UIActionSheetRACSupportSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766B219EDA60000A782A9 /* UIActionSheetRACSupportSpec.m */; }; D037671C19EDA60000A782A9 /* UIAlertViewRACSupportSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766B319EDA60000A782A9 /* UIAlertViewRACSupportSpec.m */; }; D037671E19EDA60000A782A9 /* UIBarButtonItemRACSupportSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766B419EDA60000A782A9 /* UIBarButtonItemRACSupportSpec.m */; }; D037672019EDA60000A782A9 /* UIButtonRACSupportSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766B519EDA60000A782A9 /* UIButtonRACSupportSpec.m */; }; D037672419EDA60000A782A9 /* UIImagePickerControllerRACSupportSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D03766B719EDA60000A782A9 /* UIImagePickerControllerRACSupportSpec.m */; }; D037672719EDA63400A782A9 /* RACBehaviorSubject.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646019EDA41200A782A9 /* RACBehaviorSubject.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037672819EDA63500A782A9 /* RACBehaviorSubject.h in Headers */ = {isa = PBXBuildFile; fileRef = D037646019EDA41200A782A9 /* RACBehaviorSubject.h */; settings = {ATTRIBUTES = (Public, ); }; }; D037672D19EDA75D00A782A9 /* Quick.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D037672B19EDA75D00A782A9 /* Quick.framework */; }; D037672F19EDA78B00A782A9 /* Quick.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D037672B19EDA75D00A782A9 /* Quick.framework */; }; D03B4A3D19F4C39A009E02AC /* FoundationExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B4A3C19F4C39A009E02AC /* FoundationExtensions.swift */; }; D03B4A3E19F4C39A009E02AC /* FoundationExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B4A3C19F4C39A009E02AC /* FoundationExtensions.swift */; }; D04725F019E49ED7006002AA /* ReactiveCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = D04725EF19E49ED7006002AA /* ReactiveCocoa.h */; settings = {ATTRIBUTES = (Public, ); }; }; D04725F619E49ED7006002AA /* ReactiveCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D04725EA19E49ED7006002AA /* ReactiveCocoa.framework */; }; D047261719E49F82006002AA /* ReactiveCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D047260C19E49F82006002AA /* ReactiveCocoa.framework */; }; D05E662519EDD82000904ACA /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D05E662419EDD82000904ACA /* Nimble.framework */; }; D05E662619EDD83000904ACA /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D05E662419EDD82000904ACA /* Nimble.framework */; }; D08C54B31A69A2AE00AD8286 /* Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54B11A69A2AC00AD8286 /* Signal.swift */; }; D08C54B41A69A2AF00AD8286 /* Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54B11A69A2AC00AD8286 /* Signal.swift */; }; D08C54B61A69A3DB00AD8286 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54B51A69A3DB00AD8286 /* Event.swift */; }; D08C54B71A69A3DB00AD8286 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54B51A69A3DB00AD8286 /* Event.swift */; }; D08C54B81A69A9D000AD8286 /* SignalProducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54B21A69A2AC00AD8286 /* SignalProducer.swift */; }; D08C54B91A69A9D100AD8286 /* SignalProducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54B21A69A2AC00AD8286 /* SignalProducer.swift */; }; D08C54BA1A69C54300AD8286 /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54B01A69A2AC00AD8286 /* Property.swift */; }; D08C54BB1A69C54400AD8286 /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54B01A69A2AC00AD8286 /* Property.swift */; }; D0A226081A72E0E900D33B74 /* SignalSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A226071A72E0E900D33B74 /* SignalSpec.swift */; }; D0A226091A72E0E900D33B74 /* SignalSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A226071A72E0E900D33B74 /* SignalSpec.swift */; }; D0A2260B1A72E6C500D33B74 /* SignalProducerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A2260A1A72E6C500D33B74 /* SignalProducerSpec.swift */; }; D0A2260C1A72E6C500D33B74 /* SignalProducerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A2260A1A72E6C500D33B74 /* SignalProducerSpec.swift */; }; D0A2260E1A72F16D00D33B74 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A2260D1A72F16D00D33B74 /* PropertySpec.swift */; }; D0A2260F1A72F16D00D33B74 /* PropertySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A2260D1A72F16D00D33B74 /* PropertySpec.swift */; }; D0A226111A72F30B00D33B74 /* ObjectiveCBridgingSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A226101A72F30B00D33B74 /* ObjectiveCBridgingSpec.swift */; }; D0A226121A72F30B00D33B74 /* ObjectiveCBridgingSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A226101A72F30B00D33B74 /* ObjectiveCBridgingSpec.swift */; }; D0C312CD19EF2A5800984962 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312BB19EF2A5800984962 /* Atomic.swift */; }; D0C312CE19EF2A5800984962 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312BB19EF2A5800984962 /* Atomic.swift */; }; D0C312CF19EF2A5800984962 /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312BC19EF2A5800984962 /* Bag.swift */; }; D0C312D019EF2A5800984962 /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312BC19EF2A5800984962 /* Bag.swift */; }; D0C312D319EF2A5800984962 /* Disposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312BE19EF2A5800984962 /* Disposable.swift */; }; D0C312D419EF2A5800984962 /* Disposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312BE19EF2A5800984962 /* Disposable.swift */; }; D0C312DF19EF2A5800984962 /* ObjectiveCBridging.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312C419EF2A5800984962 /* ObjectiveCBridging.swift */; }; D0C312E019EF2A5800984962 /* ObjectiveCBridging.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312C419EF2A5800984962 /* ObjectiveCBridging.swift */; }; D0C312E719EF2A5800984962 /* Scheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312C819EF2A5800984962 /* Scheduler.swift */; }; D0C312E819EF2A5800984962 /* Scheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312C819EF2A5800984962 /* Scheduler.swift */; }; D0C3130C19EF2B1F00984962 /* DisposableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312F019EF2A7700984962 /* DisposableSpec.swift */; }; D0C3130E19EF2B1F00984962 /* SchedulerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312F219EF2A7700984962 /* SchedulerSpec.swift */; }; D0C3131219EF2B2000984962 /* DisposableSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312F019EF2A7700984962 /* DisposableSpec.swift */; }; D0C3131419EF2B2000984962 /* SchedulerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C312F219EF2A7700984962 /* SchedulerSpec.swift */; }; D0C3131E19EF2D9700984962 /* RACTestExampleScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C3131819EF2D9700984962 /* RACTestExampleScheduler.m */; }; D0C3131F19EF2D9700984962 /* RACTestExampleScheduler.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C3131819EF2D9700984962 /* RACTestExampleScheduler.m */; }; D0C3132019EF2D9700984962 /* RACTestObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C3131A19EF2D9700984962 /* RACTestObject.m */; }; D0C3132119EF2D9700984962 /* RACTestObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C3131A19EF2D9700984962 /* RACTestObject.m */; }; D0C3132219EF2D9700984962 /* RACTestSchedulerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C3131B19EF2D9700984962 /* RACTestSchedulerSpec.m */; }; D0C3132319EF2D9700984962 /* RACTestSchedulerSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C3131B19EF2D9700984962 /* RACTestSchedulerSpec.m */; }; D0C3132519EF2D9700984962 /* RACTestUIButton.m in Sources */ = {isa = PBXBuildFile; fileRef = D0C3131D19EF2D9700984962 /* RACTestUIButton.m */; }; D0D11AB91A6AE87700C1F8B1 /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54AF1A69A2AC00AD8286 /* Action.swift */; }; D0D11ABA1A6AE87700C1F8B1 /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08C54AF1A69A2AC00AD8286 /* Action.swift */; }; D43F27A01A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.h in Headers */ = {isa = PBXBuildFile; fileRef = D43F279E1A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; D43F27A11A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.h in Headers */ = {isa = PBXBuildFile; fileRef = D43F279E1A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.h */; settings = {ATTRIBUTES = (Public, ); }; }; D43F27A21A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.m in Sources */ = {isa = PBXBuildFile; fileRef = D43F279F1A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.m */; }; D43F27A31A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.m in Sources */ = {isa = PBXBuildFile; fileRef = D43F279F1A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.m */; }; D8024DB21B2E1BB0005E6B9A /* SignalProducerLiftingSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8024DB11B2E1BB0005E6B9A /* SignalProducerLiftingSpec.swift */; }; D8024DB31B2E1BB0005E6B9A /* SignalProducerLiftingSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8024DB11B2E1BB0005E6B9A /* SignalProducerLiftingSpec.swift */; }; D8170FC11B100EBC004192AD /* FoundationExtensionsSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8170FC01B100EBC004192AD /* FoundationExtensionsSpec.swift */; }; D8170FC21B100EBC004192AD /* FoundationExtensionsSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8170FC01B100EBC004192AD /* FoundationExtensionsSpec.swift */; }; D85C652A1C0D84C7005A77AD /* Flatten.swift in Sources */ = {isa = PBXBuildFile; fileRef = D85C65291C0D84C7005A77AD /* Flatten.swift */; }; D85C652B1C0E70E3005A77AD /* Flatten.swift in Sources */ = {isa = PBXBuildFile; fileRef = D85C65291C0D84C7005A77AD /* Flatten.swift */; }; D85C652C1C0E70E4005A77AD /* Flatten.swift in Sources */ = {isa = PBXBuildFile; fileRef = D85C65291C0D84C7005A77AD /* Flatten.swift */; }; D85C652D1C0E70E5005A77AD /* Flatten.swift in Sources */ = {isa = PBXBuildFile; fileRef = D85C65291C0D84C7005A77AD /* Flatten.swift */; }; D871D69F1B3B29A40070F16C /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = D871D69E1B3B29A40070F16C /* Optional.swift */; }; D8E84A671B3B32FB00C3E831 /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = D871D69E1B3B29A40070F16C /* Optional.swift */; }; EBCC7DBC1BBF010C00A2AE92 /* Observer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBCC7DBB1BBF010C00A2AE92 /* Observer.swift */; }; EBCC7DBD1BBF01E100A2AE92 /* Observer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBCC7DBB1BBF010C00A2AE92 /* Observer.swift */; }; EBCC7DBE1BBF01E200A2AE92 /* Observer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBCC7DBB1BBF010C00A2AE92 /* Observer.swift */; }; EBCC7DBF1BBF01E200A2AE92 /* Observer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBCC7DBB1BBF010C00A2AE92 /* Observer.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ D04725F719E49ED7006002AA /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D04725E119E49ED7006002AA /* Project object */; proxyType = 1; remoteGlobalIDString = D04725E919E49ED7006002AA; remoteInfo = ReactiveCocoa; }; D047261819E49F82006002AA /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D04725E119E49ED7006002AA /* Project object */; proxyType = 1; remoteGlobalIDString = D047260B19E49F82006002AA; remoteInfo = ReactiveCocoa; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ D01B7B6119EDD8F600D26E01 /* Copy Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( CDC42E331AE7AC6D00965373 /* Result.framework in Copy Frameworks */, D01B7B6219EDD8FE00D26E01 /* Nimble.framework in Copy Frameworks */, D01B7B6319EDD8FE00D26E01 /* Quick.framework in Copy Frameworks */, D01B7B6419EDD94B00D26E01 /* ReactiveCocoa.framework in Copy Frameworks */, ); name = "Copy Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 02D260291C1D6DAF003ACC61 /* SignalLifetimeSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalLifetimeSpec.swift; sourceTree = ""; }; 314304151ACA8B1E00595017 /* MKAnnotationView+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MKAnnotationView+RACSignalSupport.h"; sourceTree = ""; }; 314304161ACA8B1E00595017 /* MKAnnotationView+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MKAnnotationView+RACSignalSupport.m"; sourceTree = ""; }; 57A4D2411BA13D7A00F7D4B1 /* ReactiveCocoa.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ReactiveCocoa.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 57A4D2441BA13F9700F7D4B1 /* tvOS-Application.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "tvOS-Application.xcconfig"; sourceTree = ""; }; 57A4D2451BA13F9700F7D4B1 /* tvOS-Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "tvOS-Base.xcconfig"; sourceTree = ""; }; 57A4D2461BA13F9700F7D4B1 /* tvOS-Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "tvOS-Framework.xcconfig"; sourceTree = ""; }; 57A4D2471BA13F9700F7D4B1 /* tvOS-StaticLibrary.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "tvOS-StaticLibrary.xcconfig"; sourceTree = ""; }; 7A70657D1A3F88B8001E8354 /* RACKVOProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACKVOProxy.h; sourceTree = ""; }; 7A70657E1A3F88B8001E8354 /* RACKVOProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACKVOProxy.m; sourceTree = ""; }; 7A7065831A3F8967001E8354 /* RACKVOProxySpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACKVOProxySpec.m; sourceTree = ""; }; A97451331B3A935E00F48E55 /* watchOS-Application.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "watchOS-Application.xcconfig"; sourceTree = ""; }; A97451341B3A935E00F48E55 /* watchOS-Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "watchOS-Base.xcconfig"; sourceTree = ""; }; A97451351B3A935E00F48E55 /* watchOS-Framework.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "watchOS-Framework.xcconfig"; sourceTree = ""; }; A97451361B3A935E00F48E55 /* watchOS-StaticLibrary.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "watchOS-StaticLibrary.xcconfig"; sourceTree = ""; }; A9B315541B3940610001CB9C /* ReactiveCocoa.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ReactiveCocoa.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B696FB801A7640C00075236D /* TestError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestError.swift; sourceTree = ""; }; BFA6B94A1A76044800C846D1 /* SignalProducerNimbleMatchers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SignalProducerNimbleMatchers.swift; path = Swift/SignalProducerNimbleMatchers.swift; sourceTree = ""; }; CA6F284F1C52626B001879D2 /* FlattenSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlattenSpec.swift; sourceTree = ""; }; CD183E811AED1E0E00848F5D /* Box.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Box.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CDC42E2E1AE7AB8B00965373 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Result.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D00004081A46864E000E7D41 /* TupleExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TupleExtensions.swift; sourceTree = ""; }; D021671C1A6CD50500987861 /* ActionSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = ActionSpec.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; D037642A19EDA41200A782A9 /* NSArray+RACSequenceAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+RACSequenceAdditions.h"; sourceTree = ""; }; D037642B19EDA41200A782A9 /* NSArray+RACSequenceAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+RACSequenceAdditions.m"; sourceTree = ""; }; D037642C19EDA41200A782A9 /* NSControl+RACCommandSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSControl+RACCommandSupport.h"; sourceTree = ""; }; D037642D19EDA41200A782A9 /* NSControl+RACCommandSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSControl+RACCommandSupport.m"; sourceTree = ""; }; D037642E19EDA41200A782A9 /* NSControl+RACTextSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSControl+RACTextSignalSupport.h"; sourceTree = ""; }; D037642F19EDA41200A782A9 /* NSControl+RACTextSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSControl+RACTextSignalSupport.m"; sourceTree = ""; }; D037643019EDA41200A782A9 /* NSData+RACSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+RACSupport.h"; sourceTree = ""; }; D037643119EDA41200A782A9 /* NSData+RACSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+RACSupport.m"; sourceTree = ""; }; D037643219EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+RACSequenceAdditions.h"; sourceTree = ""; }; D037643319EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+RACSequenceAdditions.m"; sourceTree = ""; }; D037643419EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSEnumerator+RACSequenceAdditions.h"; sourceTree = ""; }; D037643519EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSEnumerator+RACSequenceAdditions.m"; sourceTree = ""; }; D037643619EDA41200A782A9 /* NSFileHandle+RACSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSFileHandle+RACSupport.h"; sourceTree = ""; }; D037643719EDA41200A782A9 /* NSFileHandle+RACSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSFileHandle+RACSupport.m"; sourceTree = ""; }; D037643819EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSIndexSet+RACSequenceAdditions.h"; sourceTree = ""; }; D037643919EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSIndexSet+RACSequenceAdditions.m"; sourceTree = ""; }; D037643A19EDA41200A782A9 /* NSInvocation+RACTypeParsing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSInvocation+RACTypeParsing.h"; sourceTree = ""; }; D037643B19EDA41200A782A9 /* NSInvocation+RACTypeParsing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSInvocation+RACTypeParsing.m"; sourceTree = ""; }; D037643C19EDA41200A782A9 /* NSNotificationCenter+RACSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+RACSupport.h"; sourceTree = ""; }; D037643D19EDA41200A782A9 /* NSNotificationCenter+RACSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSNotificationCenter+RACSupport.m"; sourceTree = ""; }; D037643E19EDA41200A782A9 /* NSObject+RACAppKitBindings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+RACAppKitBindings.h"; sourceTree = ""; }; D037643F19EDA41200A782A9 /* NSObject+RACAppKitBindings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+RACAppKitBindings.m"; sourceTree = ""; }; D037644019EDA41200A782A9 /* NSObject+RACDeallocating.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+RACDeallocating.h"; sourceTree = ""; }; D037644119EDA41200A782A9 /* NSObject+RACDeallocating.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+RACDeallocating.m"; sourceTree = ""; }; D037644219EDA41200A782A9 /* NSObject+RACDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+RACDescription.h"; sourceTree = ""; }; D037644319EDA41200A782A9 /* NSObject+RACDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+RACDescription.m"; sourceTree = ""; }; D037644419EDA41200A782A9 /* NSObject+RACKVOWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+RACKVOWrapper.h"; sourceTree = ""; }; D037644519EDA41200A782A9 /* NSObject+RACKVOWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+RACKVOWrapper.m"; sourceTree = ""; }; D037644619EDA41200A782A9 /* NSObject+RACLifting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+RACLifting.h"; sourceTree = ""; }; D037644719EDA41200A782A9 /* NSObject+RACLifting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+RACLifting.m"; sourceTree = ""; }; D037644819EDA41200A782A9 /* NSObject+RACPropertySubscribing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+RACPropertySubscribing.h"; sourceTree = ""; }; D037644919EDA41200A782A9 /* NSObject+RACPropertySubscribing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+RACPropertySubscribing.m"; sourceTree = ""; }; D037644A19EDA41200A782A9 /* NSObject+RACSelectorSignal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+RACSelectorSignal.h"; sourceTree = ""; }; D037644B19EDA41200A782A9 /* NSObject+RACSelectorSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+RACSelectorSignal.m"; sourceTree = ""; }; D037644C19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSOrderedSet+RACSequenceAdditions.h"; sourceTree = ""; }; D037644D19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSOrderedSet+RACSequenceAdditions.m"; sourceTree = ""; }; D037644E19EDA41200A782A9 /* NSSet+RACSequenceAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSSet+RACSequenceAdditions.h"; sourceTree = ""; }; D037644F19EDA41200A782A9 /* NSSet+RACSequenceAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSSet+RACSequenceAdditions.m"; sourceTree = ""; }; D037645019EDA41200A782A9 /* NSString+RACKeyPathUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+RACKeyPathUtilities.h"; sourceTree = ""; }; D037645119EDA41200A782A9 /* NSString+RACKeyPathUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+RACKeyPathUtilities.m"; sourceTree = ""; }; D037645219EDA41200A782A9 /* NSString+RACSequenceAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+RACSequenceAdditions.h"; sourceTree = ""; }; D037645319EDA41200A782A9 /* NSString+RACSequenceAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+RACSequenceAdditions.m"; sourceTree = ""; }; D037645419EDA41200A782A9 /* NSString+RACSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+RACSupport.h"; sourceTree = ""; }; D037645519EDA41200A782A9 /* NSString+RACSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+RACSupport.m"; sourceTree = ""; }; D037645619EDA41200A782A9 /* NSText+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSText+RACSignalSupport.h"; sourceTree = ""; }; D037645719EDA41200A782A9 /* NSText+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSText+RACSignalSupport.m"; sourceTree = ""; }; D037645819EDA41200A782A9 /* NSURLConnection+RACSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURLConnection+RACSupport.h"; sourceTree = ""; }; D037645919EDA41200A782A9 /* NSURLConnection+RACSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURLConnection+RACSupport.m"; sourceTree = ""; }; D037645A19EDA41200A782A9 /* NSUserDefaults+RACSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSUserDefaults+RACSupport.h"; sourceTree = ""; }; D037645B19EDA41200A782A9 /* NSUserDefaults+RACSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSUserDefaults+RACSupport.m"; sourceTree = ""; }; D037645C19EDA41200A782A9 /* RACArraySequence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACArraySequence.h; sourceTree = ""; }; D037645D19EDA41200A782A9 /* RACArraySequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACArraySequence.m; sourceTree = ""; }; D037646019EDA41200A782A9 /* RACBehaviorSubject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACBehaviorSubject.h; sourceTree = ""; }; D037646119EDA41200A782A9 /* RACBehaviorSubject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACBehaviorSubject.m; sourceTree = ""; }; D037646219EDA41200A782A9 /* RACBlockTrampoline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACBlockTrampoline.h; sourceTree = ""; }; D037646319EDA41200A782A9 /* RACBlockTrampoline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACBlockTrampoline.m; sourceTree = ""; }; D037646419EDA41200A782A9 /* RACChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACChannel.h; sourceTree = ""; }; D037646519EDA41200A782A9 /* RACChannel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACChannel.m; sourceTree = ""; }; D037646619EDA41200A782A9 /* RACCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACCommand.h; sourceTree = ""; }; D037646719EDA41200A782A9 /* RACCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACCommand.m; sourceTree = ""; }; D037646819EDA41200A782A9 /* RACCompoundDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACCompoundDisposable.h; sourceTree = ""; }; D037646919EDA41200A782A9 /* RACCompoundDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACCompoundDisposable.m; sourceTree = ""; }; D037646A19EDA41200A782A9 /* RACCompoundDisposableProvider.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; path = RACCompoundDisposableProvider.d; sourceTree = ""; }; D037646B19EDA41200A782A9 /* RACDelegateProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACDelegateProxy.h; sourceTree = ""; }; D037646C19EDA41200A782A9 /* RACDelegateProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACDelegateProxy.m; sourceTree = ""; }; D037646D19EDA41200A782A9 /* RACDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACDisposable.h; sourceTree = ""; }; D037646E19EDA41200A782A9 /* RACDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACDisposable.m; sourceTree = ""; }; D037646F19EDA41200A782A9 /* RACDynamicSequence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACDynamicSequence.h; sourceTree = ""; }; D037647019EDA41200A782A9 /* RACDynamicSequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACDynamicSequence.m; sourceTree = ""; }; D037647119EDA41200A782A9 /* RACDynamicSignal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACDynamicSignal.h; sourceTree = ""; }; D037647219EDA41200A782A9 /* RACDynamicSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACDynamicSignal.m; sourceTree = ""; }; D037647319EDA41200A782A9 /* RACEagerSequence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACEagerSequence.h; sourceTree = ""; }; D037647419EDA41200A782A9 /* RACEagerSequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACEagerSequence.m; sourceTree = ""; }; D037647519EDA41200A782A9 /* RACEmptySequence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACEmptySequence.h; sourceTree = ""; }; D037647619EDA41200A782A9 /* RACEmptySequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACEmptySequence.m; sourceTree = ""; }; D037647719EDA41200A782A9 /* RACEmptySignal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACEmptySignal.h; sourceTree = ""; }; D037647819EDA41200A782A9 /* RACEmptySignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACEmptySignal.m; sourceTree = ""; }; D037647919EDA41200A782A9 /* RACErrorSignal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACErrorSignal.h; sourceTree = ""; }; D037647A19EDA41200A782A9 /* RACErrorSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACErrorSignal.m; sourceTree = ""; }; D037647B19EDA41200A782A9 /* RACEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACEvent.h; sourceTree = ""; }; D037647C19EDA41200A782A9 /* RACEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACEvent.m; sourceTree = ""; }; D037647D19EDA41200A782A9 /* RACGroupedSignal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACGroupedSignal.h; sourceTree = ""; }; D037647E19EDA41200A782A9 /* RACGroupedSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACGroupedSignal.m; sourceTree = ""; }; D037647F19EDA41200A782A9 /* RACImmediateScheduler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACImmediateScheduler.h; sourceTree = ""; }; D037648019EDA41200A782A9 /* RACImmediateScheduler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACImmediateScheduler.m; sourceTree = ""; }; D037648119EDA41200A782A9 /* RACIndexSetSequence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACIndexSetSequence.h; sourceTree = ""; }; D037648219EDA41200A782A9 /* RACIndexSetSequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACIndexSetSequence.m; sourceTree = ""; }; D037648319EDA41200A782A9 /* RACKVOChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACKVOChannel.h; sourceTree = ""; }; D037648419EDA41200A782A9 /* RACKVOChannel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACKVOChannel.m; sourceTree = ""; }; D037648519EDA41200A782A9 /* RACKVOTrampoline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACKVOTrampoline.h; sourceTree = ""; }; D037648619EDA41200A782A9 /* RACKVOTrampoline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACKVOTrampoline.m; sourceTree = ""; }; D037648719EDA41200A782A9 /* RACMulticastConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACMulticastConnection.h; sourceTree = ""; }; D037648819EDA41200A782A9 /* RACMulticastConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACMulticastConnection.m; sourceTree = ""; }; D037648919EDA41200A782A9 /* RACMulticastConnection+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RACMulticastConnection+Private.h"; sourceTree = ""; }; D037648A19EDA41200A782A9 /* RACObjCRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACObjCRuntime.h; sourceTree = ""; }; D037648B19EDA41200A782A9 /* RACObjCRuntime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACObjCRuntime.m; sourceTree = ""; }; D037648C19EDA41200A782A9 /* RACPassthroughSubscriber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACPassthroughSubscriber.h; sourceTree = ""; }; D037648D19EDA41200A782A9 /* RACPassthroughSubscriber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACPassthroughSubscriber.m; sourceTree = ""; }; D037648E19EDA41200A782A9 /* RACQueueScheduler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACQueueScheduler.h; sourceTree = ""; }; D037648F19EDA41200A782A9 /* RACQueueScheduler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACQueueScheduler.m; sourceTree = ""; }; D037649019EDA41200A782A9 /* RACQueueScheduler+Subclass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RACQueueScheduler+Subclass.h"; sourceTree = ""; }; D037649119EDA41200A782A9 /* RACReplaySubject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACReplaySubject.h; sourceTree = ""; }; D037649219EDA41200A782A9 /* RACReplaySubject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACReplaySubject.m; sourceTree = ""; }; D037649319EDA41200A782A9 /* RACReturnSignal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACReturnSignal.h; sourceTree = ""; }; D037649419EDA41200A782A9 /* RACReturnSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACReturnSignal.m; sourceTree = ""; }; D037649519EDA41200A782A9 /* RACScheduler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACScheduler.h; sourceTree = ""; }; D037649619EDA41200A782A9 /* RACScheduler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACScheduler.m; sourceTree = ""; }; D037649719EDA41200A782A9 /* RACScheduler+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RACScheduler+Private.h"; sourceTree = ""; }; D037649819EDA41200A782A9 /* RACScheduler+Subclass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RACScheduler+Subclass.h"; sourceTree = ""; }; D037649919EDA41200A782A9 /* RACScopedDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACScopedDisposable.h; sourceTree = ""; }; D037649A19EDA41200A782A9 /* RACScopedDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACScopedDisposable.m; sourceTree = ""; }; D037649B19EDA41200A782A9 /* RACSequence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACSequence.h; sourceTree = ""; }; D037649C19EDA41200A782A9 /* RACSequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSequence.m; sourceTree = ""; }; D037649D19EDA41200A782A9 /* RACSerialDisposable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACSerialDisposable.h; sourceTree = ""; }; D037649E19EDA41200A782A9 /* RACSerialDisposable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSerialDisposable.m; sourceTree = ""; }; D037649F19EDA41200A782A9 /* RACSignal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACSignal.h; sourceTree = ""; }; D03764A019EDA41200A782A9 /* RACSignal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSignal.m; sourceTree = ""; }; D03764A119EDA41200A782A9 /* RACSignal+Operations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RACSignal+Operations.h"; sourceTree = ""; }; D03764A219EDA41200A782A9 /* RACSignal+Operations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RACSignal+Operations.m"; sourceTree = ""; }; D03764A319EDA41200A782A9 /* RACSignalProvider.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; path = RACSignalProvider.d; sourceTree = ""; }; D03764A419EDA41200A782A9 /* RACSignalSequence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACSignalSequence.h; sourceTree = ""; }; D03764A519EDA41200A782A9 /* RACSignalSequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSignalSequence.m; sourceTree = ""; }; D03764A619EDA41200A782A9 /* RACStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACStream.h; sourceTree = ""; }; D03764A719EDA41200A782A9 /* RACStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACStream.m; sourceTree = ""; }; D03764A819EDA41200A782A9 /* RACStream+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RACStream+Private.h"; sourceTree = ""; }; D03764A919EDA41200A782A9 /* RACStringSequence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACStringSequence.h; sourceTree = ""; }; D03764AA19EDA41200A782A9 /* RACStringSequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACStringSequence.m; sourceTree = ""; }; D03764AB19EDA41200A782A9 /* RACSubject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACSubject.h; sourceTree = ""; }; D03764AC19EDA41200A782A9 /* RACSubject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSubject.m; sourceTree = ""; }; D03764AD19EDA41200A782A9 /* RACSubscriber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACSubscriber.h; sourceTree = ""; }; D03764AE19EDA41200A782A9 /* RACSubscriber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSubscriber.m; sourceTree = ""; }; D03764AF19EDA41200A782A9 /* RACSubscriber+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RACSubscriber+Private.h"; sourceTree = ""; }; D03764B019EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACSubscriptingAssignmentTrampoline.h; sourceTree = ""; }; D03764B119EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSubscriptingAssignmentTrampoline.m; sourceTree = ""; }; D03764B219EDA41200A782A9 /* RACSubscriptionScheduler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACSubscriptionScheduler.h; sourceTree = ""; }; D03764B319EDA41200A782A9 /* RACSubscriptionScheduler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSubscriptionScheduler.m; sourceTree = ""; }; D03764B419EDA41200A782A9 /* RACTargetQueueScheduler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACTargetQueueScheduler.h; sourceTree = ""; }; D03764B519EDA41200A782A9 /* RACTargetQueueScheduler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACTargetQueueScheduler.m; sourceTree = ""; }; D03764B619EDA41200A782A9 /* RACTestScheduler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACTestScheduler.h; sourceTree = ""; }; D03764B719EDA41200A782A9 /* RACTestScheduler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACTestScheduler.m; sourceTree = ""; }; D03764B819EDA41200A782A9 /* RACTuple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACTuple.h; sourceTree = ""; }; D03764B919EDA41200A782A9 /* RACTuple.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACTuple.m; sourceTree = ""; }; D03764BA19EDA41200A782A9 /* RACTupleSequence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACTupleSequence.h; sourceTree = ""; }; D03764BB19EDA41200A782A9 /* RACTupleSequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACTupleSequence.m; sourceTree = ""; }; D03764BC19EDA41200A782A9 /* RACUnarySequence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACUnarySequence.h; sourceTree = ""; }; D03764BD19EDA41200A782A9 /* RACUnarySequence.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACUnarySequence.m; sourceTree = ""; }; D03764BE19EDA41200A782A9 /* RACUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACUnit.h; sourceTree = ""; }; D03764BF19EDA41200A782A9 /* RACUnit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACUnit.m; sourceTree = ""; }; D03764C019EDA41200A782A9 /* RACValueTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACValueTransformer.h; sourceTree = ""; }; D03764C119EDA41200A782A9 /* RACValueTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACValueTransformer.m; sourceTree = ""; }; D03764C219EDA41200A782A9 /* UIActionSheet+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIActionSheet+RACSignalSupport.h"; sourceTree = ""; }; D03764C319EDA41200A782A9 /* UIActionSheet+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIActionSheet+RACSignalSupport.m"; sourceTree = ""; }; D03764C419EDA41200A782A9 /* UIAlertView+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertView+RACSignalSupport.h"; sourceTree = ""; }; D03764C519EDA41200A782A9 /* UIAlertView+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertView+RACSignalSupport.m"; sourceTree = ""; }; D03764C619EDA41200A782A9 /* UIBarButtonItem+RACCommandSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIBarButtonItem+RACCommandSupport.h"; sourceTree = ""; }; D03764C719EDA41200A782A9 /* UIBarButtonItem+RACCommandSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIBarButtonItem+RACCommandSupport.m"; sourceTree = ""; }; D03764C819EDA41200A782A9 /* UIButton+RACCommandSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIButton+RACCommandSupport.h"; sourceTree = ""; }; D03764C919EDA41200A782A9 /* UIButton+RACCommandSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIButton+RACCommandSupport.m"; sourceTree = ""; }; D03764CA19EDA41200A782A9 /* UICollectionReusableView+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UICollectionReusableView+RACSignalSupport.h"; sourceTree = ""; }; D03764CB19EDA41200A782A9 /* UICollectionReusableView+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UICollectionReusableView+RACSignalSupport.m"; sourceTree = ""; }; D03764CC19EDA41200A782A9 /* UIControl+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIControl+RACSignalSupport.h"; sourceTree = ""; }; D03764CD19EDA41200A782A9 /* UIControl+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIControl+RACSignalSupport.m"; sourceTree = ""; }; D03764CE19EDA41200A782A9 /* UIControl+RACSignalSupportPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIControl+RACSignalSupportPrivate.h"; sourceTree = ""; }; D03764CF19EDA41200A782A9 /* UIControl+RACSignalSupportPrivate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIControl+RACSignalSupportPrivate.m"; sourceTree = ""; }; D03764D019EDA41200A782A9 /* UIDatePicker+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIDatePicker+RACSignalSupport.h"; sourceTree = ""; }; D03764D119EDA41200A782A9 /* UIDatePicker+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIDatePicker+RACSignalSupport.m"; sourceTree = ""; }; D03764D219EDA41200A782A9 /* UIGestureRecognizer+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIGestureRecognizer+RACSignalSupport.h"; sourceTree = ""; }; D03764D319EDA41200A782A9 /* UIGestureRecognizer+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIGestureRecognizer+RACSignalSupport.m"; sourceTree = ""; }; D03764D419EDA41200A782A9 /* UIImagePickerController+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImagePickerController+RACSignalSupport.h"; sourceTree = ""; }; D03764D519EDA41200A782A9 /* UIImagePickerController+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImagePickerController+RACSignalSupport.m"; sourceTree = ""; }; D03764D619EDA41200A782A9 /* UIRefreshControl+RACCommandSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIRefreshControl+RACCommandSupport.h"; sourceTree = ""; }; D03764D719EDA41200A782A9 /* UIRefreshControl+RACCommandSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIRefreshControl+RACCommandSupport.m"; sourceTree = ""; }; D03764D819EDA41200A782A9 /* UISegmentedControl+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UISegmentedControl+RACSignalSupport.h"; sourceTree = ""; }; D03764D919EDA41200A782A9 /* UISegmentedControl+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UISegmentedControl+RACSignalSupport.m"; sourceTree = ""; }; D03764DA19EDA41200A782A9 /* UISlider+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UISlider+RACSignalSupport.h"; sourceTree = ""; }; D03764DB19EDA41200A782A9 /* UISlider+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UISlider+RACSignalSupport.m"; sourceTree = ""; }; D03764DC19EDA41200A782A9 /* UIStepper+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIStepper+RACSignalSupport.h"; sourceTree = ""; }; D03764DD19EDA41200A782A9 /* UIStepper+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIStepper+RACSignalSupport.m"; sourceTree = ""; }; D03764DE19EDA41200A782A9 /* UISwitch+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UISwitch+RACSignalSupport.h"; sourceTree = ""; }; D03764DF19EDA41200A782A9 /* UISwitch+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UISwitch+RACSignalSupport.m"; sourceTree = ""; }; D03764E019EDA41200A782A9 /* UITableViewCell+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableViewCell+RACSignalSupport.h"; sourceTree = ""; }; D03764E119EDA41200A782A9 /* UITableViewCell+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableViewCell+RACSignalSupport.m"; sourceTree = ""; }; D03764E219EDA41200A782A9 /* UITableViewHeaderFooterView+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableViewHeaderFooterView+RACSignalSupport.h"; sourceTree = ""; }; D03764E319EDA41200A782A9 /* UITableViewHeaderFooterView+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableViewHeaderFooterView+RACSignalSupport.m"; sourceTree = ""; }; D03764E419EDA41200A782A9 /* UITextField+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITextField+RACSignalSupport.h"; sourceTree = ""; }; D03764E519EDA41200A782A9 /* UITextField+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITextField+RACSignalSupport.m"; sourceTree = ""; }; D03764E619EDA41200A782A9 /* UITextView+RACSignalSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITextView+RACSignalSupport.h"; sourceTree = ""; }; D03764E719EDA41200A782A9 /* UITextView+RACSignalSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITextView+RACSignalSupport.m"; sourceTree = ""; }; D037666619EDA57100A782A9 /* EXTKeyPathCoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EXTKeyPathCoding.h; sourceTree = ""; }; D037666719EDA57100A782A9 /* EXTRuntimeExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EXTRuntimeExtensions.h; sourceTree = ""; }; D037666819EDA57100A782A9 /* EXTRuntimeExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EXTRuntimeExtensions.m; sourceTree = ""; }; D037666919EDA57100A782A9 /* EXTScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EXTScope.h; sourceTree = ""; }; D037666A19EDA57100A782A9 /* metamacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = metamacros.h; sourceTree = ""; }; D037667619EDA60000A782A9 /* NSControllerRACSupportSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSControllerRACSupportSpec.m; sourceTree = ""; }; D037667819EDA60000A782A9 /* NSEnumeratorRACSequenceAdditionsSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSEnumeratorRACSequenceAdditionsSpec.m; sourceTree = ""; }; D037667919EDA60000A782A9 /* NSNotificationCenterRACSupportSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSNotificationCenterRACSupportSpec.m; sourceTree = ""; }; D037667A19EDA60000A782A9 /* NSObjectRACAppKitBindingsSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSObjectRACAppKitBindingsSpec.m; sourceTree = ""; }; D037667B19EDA60000A782A9 /* NSObjectRACDeallocatingSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSObjectRACDeallocatingSpec.m; sourceTree = ""; }; D037667C19EDA60000A782A9 /* NSObjectRACLiftingSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSObjectRACLiftingSpec.m; sourceTree = ""; }; D037667D19EDA60000A782A9 /* NSObjectRACPropertySubscribingExamples.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSObjectRACPropertySubscribingExamples.h; sourceTree = ""; }; D037667E19EDA60000A782A9 /* NSObjectRACPropertySubscribingExamples.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSObjectRACPropertySubscribingExamples.m; sourceTree = ""; }; D037667F19EDA60000A782A9 /* NSObjectRACPropertySubscribingSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSObjectRACPropertySubscribingSpec.m; sourceTree = ""; }; D037668019EDA60000A782A9 /* NSObjectRACSelectorSignalSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSObjectRACSelectorSignalSpec.m; sourceTree = ""; }; D037668119EDA60000A782A9 /* NSStringRACKeyPathUtilitiesSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSStringRACKeyPathUtilitiesSpec.m; sourceTree = ""; }; D037668319EDA60000A782A9 /* NSURLConnectionRACSupportSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSURLConnectionRACSupportSpec.m; sourceTree = ""; }; D037668419EDA60000A782A9 /* NSUserDefaultsRACSupportSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSUserDefaultsRACSupportSpec.m; sourceTree = ""; }; D037668619EDA60000A782A9 /* RACBlockTrampolineSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACBlockTrampolineSpec.m; sourceTree = ""; }; D037668719EDA60000A782A9 /* RACChannelExamples.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACChannelExamples.h; sourceTree = ""; }; D037668819EDA60000A782A9 /* RACChannelExamples.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACChannelExamples.m; sourceTree = ""; }; D037668919EDA60000A782A9 /* RACChannelSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACChannelSpec.m; sourceTree = ""; }; D037668A19EDA60000A782A9 /* RACCommandSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACCommandSpec.m; sourceTree = ""; }; D037668B19EDA60000A782A9 /* RACCompoundDisposableSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACCompoundDisposableSpec.m; sourceTree = ""; }; D037668C19EDA60000A782A9 /* RACControlCommandExamples.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACControlCommandExamples.h; sourceTree = ""; }; D037668D19EDA60000A782A9 /* RACControlCommandExamples.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACControlCommandExamples.m; sourceTree = ""; }; D037668E19EDA60000A782A9 /* RACDelegateProxySpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACDelegateProxySpec.m; sourceTree = ""; }; D037668F19EDA60000A782A9 /* RACDisposableSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACDisposableSpec.m; sourceTree = ""; }; D037669019EDA60000A782A9 /* RACEventSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACEventSpec.m; sourceTree = ""; }; D037669119EDA60000A782A9 /* RACKVOChannelSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACKVOChannelSpec.m; sourceTree = ""; }; D037669219EDA60000A782A9 /* RACKVOWrapperSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACKVOWrapperSpec.m; sourceTree = ""; }; D037669319EDA60000A782A9 /* RACMulticastConnectionSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACMulticastConnectionSpec.m; sourceTree = ""; }; D037669419EDA60000A782A9 /* RACPropertySignalExamples.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACPropertySignalExamples.h; sourceTree = ""; }; D037669519EDA60000A782A9 /* RACPropertySignalExamples.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACPropertySignalExamples.m; sourceTree = ""; }; D037669619EDA60000A782A9 /* RACSchedulerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSchedulerSpec.m; sourceTree = ""; }; D037669719EDA60000A782A9 /* RACSequenceAdditionsSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSequenceAdditionsSpec.m; sourceTree = ""; }; D037669819EDA60000A782A9 /* RACSequenceExamples.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACSequenceExamples.h; sourceTree = ""; }; D037669919EDA60000A782A9 /* RACSequenceExamples.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSequenceExamples.m; sourceTree = ""; }; D037669A19EDA60000A782A9 /* RACSequenceSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSequenceSpec.m; sourceTree = ""; }; D037669B19EDA60000A782A9 /* RACSerialDisposableSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSerialDisposableSpec.m; sourceTree = ""; }; D037669C19EDA60000A782A9 /* RACSignalSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSignalSpec.m; sourceTree = ""; }; D037669F19EDA60000A782A9 /* RACStreamExamples.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACStreamExamples.h; sourceTree = ""; }; D03766A019EDA60000A782A9 /* RACStreamExamples.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACStreamExamples.m; sourceTree = ""; }; D03766A119EDA60000A782A9 /* RACSubclassObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACSubclassObject.h; sourceTree = ""; }; D03766A219EDA60000A782A9 /* RACSubclassObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSubclassObject.m; sourceTree = ""; }; D03766A319EDA60000A782A9 /* RACSubjectSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSubjectSpec.m; sourceTree = ""; }; D03766A419EDA60000A782A9 /* RACSubscriberExamples.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACSubscriberExamples.h; sourceTree = ""; }; D03766A519EDA60000A782A9 /* RACSubscriberExamples.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSubscriberExamples.m; sourceTree = ""; }; D03766A619EDA60000A782A9 /* RACSubscriberSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSubscriberSpec.m; sourceTree = ""; }; D03766A719EDA60000A782A9 /* RACSubscriptingAssignmentTrampolineSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACSubscriptingAssignmentTrampolineSpec.m; sourceTree = ""; }; D03766A819EDA60000A782A9 /* RACTargetQueueSchedulerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACTargetQueueSchedulerSpec.m; sourceTree = ""; }; D03766B019EDA60000A782A9 /* RACTupleSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACTupleSpec.m; sourceTree = ""; }; D03766B119EDA60000A782A9 /* test-data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "test-data.json"; sourceTree = ""; }; D03766B219EDA60000A782A9 /* UIActionSheetRACSupportSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIActionSheetRACSupportSpec.m; sourceTree = ""; }; D03766B319EDA60000A782A9 /* UIAlertViewRACSupportSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIAlertViewRACSupportSpec.m; sourceTree = ""; }; D03766B419EDA60000A782A9 /* UIBarButtonItemRACSupportSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIBarButtonItemRACSupportSpec.m; sourceTree = ""; }; D03766B519EDA60000A782A9 /* UIButtonRACSupportSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIButtonRACSupportSpec.m; sourceTree = ""; }; D03766B719EDA60000A782A9 /* UIImagePickerControllerRACSupportSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIImagePickerControllerRACSupportSpec.m; sourceTree = ""; }; D037672B19EDA75D00A782A9 /* Quick.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Quick.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D03B4A3C19F4C39A009E02AC /* FoundationExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FoundationExtensions.swift; sourceTree = ""; }; D04725EA19E49ED7006002AA /* ReactiveCocoa.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ReactiveCocoa.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D04725EE19E49ED7006002AA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D04725EF19E49ED7006002AA /* ReactiveCocoa.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ReactiveCocoa.h; sourceTree = ""; }; D04725F519E49ED7006002AA /* ReactiveCocoaTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReactiveCocoaTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D04725FB19E49ED7006002AA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D047260C19E49F82006002AA /* ReactiveCocoa.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ReactiveCocoa.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D047261619E49F82006002AA /* ReactiveCocoaTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReactiveCocoaTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D047262719E49FE8006002AA /* Common.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Common.xcconfig; sourceTree = ""; }; D047262919E49FE8006002AA /* Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; D047262A19E49FE8006002AA /* Profile.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Profile.xcconfig; sourceTree = ""; }; D047262B19E49FE8006002AA /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; D047262C19E49FE8006002AA /* Test.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Test.xcconfig; sourceTree = ""; }; D047262E19E49FE8006002AA /* Application.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Application.xcconfig; sourceTree = ""; }; D047262F19E49FE8006002AA /* Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Framework.xcconfig; sourceTree = ""; }; D047263019E49FE8006002AA /* StaticLibrary.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = StaticLibrary.xcconfig; sourceTree = ""; }; D047263219E49FE8006002AA /* iOS-Application.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "iOS-Application.xcconfig"; sourceTree = ""; }; D047263319E49FE8006002AA /* iOS-Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "iOS-Base.xcconfig"; sourceTree = ""; }; D047263419E49FE8006002AA /* iOS-Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "iOS-Framework.xcconfig"; sourceTree = ""; }; D047263519E49FE8006002AA /* iOS-StaticLibrary.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "iOS-StaticLibrary.xcconfig"; sourceTree = ""; }; D047263719E49FE8006002AA /* Mac-Application.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Mac-Application.xcconfig"; sourceTree = ""; }; D047263819E49FE8006002AA /* Mac-Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Mac-Base.xcconfig"; sourceTree = ""; }; D047263919E49FE8006002AA /* Mac-DynamicLibrary.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Mac-DynamicLibrary.xcconfig"; sourceTree = ""; }; D047263A19E49FE8006002AA /* Mac-Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Mac-Framework.xcconfig"; sourceTree = ""; }; D047263B19E49FE8006002AA /* Mac-StaticLibrary.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Mac-StaticLibrary.xcconfig"; sourceTree = ""; }; D047263C19E49FE8006002AA /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; D05E662419EDD82000904ACA /* Nimble.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Nimble.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D08C54AF1A69A2AC00AD8286 /* Action.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Action.swift; sourceTree = ""; }; D08C54B01A69A2AC00AD8286 /* Property.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Property.swift; sourceTree = ""; }; D08C54B11A69A2AC00AD8286 /* Signal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Signal.swift; sourceTree = ""; }; D08C54B21A69A2AC00AD8286 /* SignalProducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignalProducer.swift; sourceTree = ""; }; D08C54B51A69A3DB00AD8286 /* Event.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Event.swift; sourceTree = ""; }; D0A226071A72E0E900D33B74 /* SignalSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = SignalSpec.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; D0A2260A1A72E6C500D33B74 /* SignalProducerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = SignalProducerSpec.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; D0A2260D1A72F16D00D33B74 /* PropertySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = PropertySpec.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; D0A226101A72F30B00D33B74 /* ObjectiveCBridgingSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = ObjectiveCBridgingSpec.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; D0C312BB19EF2A5800984962 /* Atomic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = ""; }; D0C312BC19EF2A5800984962 /* Bag.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bag.swift; sourceTree = ""; }; D0C312BE19EF2A5800984962 /* Disposable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Disposable.swift; sourceTree = ""; }; D0C312C419EF2A5800984962 /* ObjectiveCBridging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectiveCBridging.swift; sourceTree = ""; }; D0C312C819EF2A5800984962 /* Scheduler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Scheduler.swift; sourceTree = ""; }; D0C312EE19EF2A7700984962 /* AtomicSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AtomicSpec.swift; sourceTree = ""; }; D0C312EF19EF2A7700984962 /* BagSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BagSpec.swift; sourceTree = ""; }; D0C312F019EF2A7700984962 /* DisposableSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisposableSpec.swift; sourceTree = ""; }; D0C312F219EF2A7700984962 /* SchedulerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SchedulerSpec.swift; sourceTree = ""; }; D0C3131719EF2D9700984962 /* RACTestExampleScheduler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACTestExampleScheduler.h; sourceTree = ""; }; D0C3131819EF2D9700984962 /* RACTestExampleScheduler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACTestExampleScheduler.m; sourceTree = ""; }; D0C3131919EF2D9700984962 /* RACTestObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACTestObject.h; sourceTree = ""; }; D0C3131A19EF2D9700984962 /* RACTestObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACTestObject.m; sourceTree = ""; }; D0C3131B19EF2D9700984962 /* RACTestSchedulerSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACTestSchedulerSpec.m; sourceTree = ""; }; D0C3131C19EF2D9700984962 /* RACTestUIButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACTestUIButton.h; sourceTree = ""; }; D0C3131D19EF2D9700984962 /* RACTestUIButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACTestUIButton.m; sourceTree = ""; }; D43F279E1A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RACDynamicPropertySuperclass.h; sourceTree = ""; }; D43F279F1A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RACDynamicPropertySuperclass.m; sourceTree = ""; }; D8024DB11B2E1BB0005E6B9A /* SignalProducerLiftingSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = SignalProducerLiftingSpec.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; D8170FC01B100EBC004192AD /* FoundationExtensionsSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FoundationExtensionsSpec.swift; sourceTree = ""; }; D85C65291C0D84C7005A77AD /* Flatten.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Flatten.swift; sourceTree = ""; }; D871D69E1B3B29A40070F16C /* Optional.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Optional.swift; sourceTree = ""; }; EBCC7DBB1BBF010C00A2AE92 /* Observer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Observer.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 57A4D2071BA13D7A00F7D4B1 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 57A4D2081BA13D7A00F7D4B1 /* Result.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; A9B315501B3940610001CB9C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( A9B315C91B3940980001CB9C /* Result.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; D04725E619E49ED7006002AA /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( CDC42E2F1AE7AB8B00965373 /* Result.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; D04725F219E49ED7006002AA /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( CDC42E301AE7AB8B00965373 /* Result.framework in Frameworks */, D05E662519EDD82000904ACA /* Nimble.framework in Frameworks */, D037672D19EDA75D00A782A9 /* Quick.framework in Frameworks */, D04725F619E49ED7006002AA /* ReactiveCocoa.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; D047260819E49F82006002AA /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( CDC42E311AE7AB8B00965373 /* Result.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; D047261319E49F82006002AA /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( D05E662619EDD83000904ACA /* Nimble.framework in Frameworks */, D037672F19EDA78B00A782A9 /* Quick.framework in Frameworks */, D047261719E49F82006002AA /* ReactiveCocoa.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 57A4D2431BA13F9700F7D4B1 /* tvOS */ = { isa = PBXGroup; children = ( 57A4D2441BA13F9700F7D4B1 /* tvOS-Application.xcconfig */, 57A4D2451BA13F9700F7D4B1 /* tvOS-Base.xcconfig */, 57A4D2461BA13F9700F7D4B1 /* tvOS-Framework.xcconfig */, 57A4D2471BA13F9700F7D4B1 /* tvOS-StaticLibrary.xcconfig */, ); path = tvOS; sourceTree = ""; }; A97451321B3A935E00F48E55 /* watchOS */ = { isa = PBXGroup; children = ( A97451331B3A935E00F48E55 /* watchOS-Application.xcconfig */, A97451341B3A935E00F48E55 /* watchOS-Base.xcconfig */, A97451351B3A935E00F48E55 /* watchOS-Framework.xcconfig */, A97451361B3A935E00F48E55 /* watchOS-StaticLibrary.xcconfig */, ); path = watchOS; sourceTree = ""; }; D037642919EDA3B600A782A9 /* Objective-C */ = { isa = PBXGroup; children = ( D037666519EDA57100A782A9 /* extobjc */, 314304151ACA8B1E00595017 /* MKAnnotationView+RACSignalSupport.h */, 314304161ACA8B1E00595017 /* MKAnnotationView+RACSignalSupport.m */, D037642A19EDA41200A782A9 /* NSArray+RACSequenceAdditions.h */, D037642B19EDA41200A782A9 /* NSArray+RACSequenceAdditions.m */, D037642C19EDA41200A782A9 /* NSControl+RACCommandSupport.h */, D037642D19EDA41200A782A9 /* NSControl+RACCommandSupport.m */, D037642E19EDA41200A782A9 /* NSControl+RACTextSignalSupport.h */, D037642F19EDA41200A782A9 /* NSControl+RACTextSignalSupport.m */, D037643019EDA41200A782A9 /* NSData+RACSupport.h */, D037643119EDA41200A782A9 /* NSData+RACSupport.m */, D037643219EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.h */, D037643319EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.m */, D037643419EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.h */, D037643519EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.m */, D037643619EDA41200A782A9 /* NSFileHandle+RACSupport.h */, D037643719EDA41200A782A9 /* NSFileHandle+RACSupport.m */, D037643819EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.h */, D037643919EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.m */, D037643A19EDA41200A782A9 /* NSInvocation+RACTypeParsing.h */, D037643B19EDA41200A782A9 /* NSInvocation+RACTypeParsing.m */, D037643C19EDA41200A782A9 /* NSNotificationCenter+RACSupport.h */, D037643D19EDA41200A782A9 /* NSNotificationCenter+RACSupport.m */, D037643E19EDA41200A782A9 /* NSObject+RACAppKitBindings.h */, D037643F19EDA41200A782A9 /* NSObject+RACAppKitBindings.m */, D037644019EDA41200A782A9 /* NSObject+RACDeallocating.h */, D037644119EDA41200A782A9 /* NSObject+RACDeallocating.m */, D037644219EDA41200A782A9 /* NSObject+RACDescription.h */, D037644319EDA41200A782A9 /* NSObject+RACDescription.m */, D037644419EDA41200A782A9 /* NSObject+RACKVOWrapper.h */, D037644519EDA41200A782A9 /* NSObject+RACKVOWrapper.m */, D037644619EDA41200A782A9 /* NSObject+RACLifting.h */, D037644719EDA41200A782A9 /* NSObject+RACLifting.m */, D037644819EDA41200A782A9 /* NSObject+RACPropertySubscribing.h */, D037644919EDA41200A782A9 /* NSObject+RACPropertySubscribing.m */, D037644A19EDA41200A782A9 /* NSObject+RACSelectorSignal.h */, D037644B19EDA41200A782A9 /* NSObject+RACSelectorSignal.m */, D037644C19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.h */, D037644D19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.m */, D037644E19EDA41200A782A9 /* NSSet+RACSequenceAdditions.h */, D037644F19EDA41200A782A9 /* NSSet+RACSequenceAdditions.m */, D037645019EDA41200A782A9 /* NSString+RACKeyPathUtilities.h */, D037645119EDA41200A782A9 /* NSString+RACKeyPathUtilities.m */, D037645219EDA41200A782A9 /* NSString+RACSequenceAdditions.h */, D037645319EDA41200A782A9 /* NSString+RACSequenceAdditions.m */, D037645419EDA41200A782A9 /* NSString+RACSupport.h */, D037645519EDA41200A782A9 /* NSString+RACSupport.m */, D037645619EDA41200A782A9 /* NSText+RACSignalSupport.h */, D037645719EDA41200A782A9 /* NSText+RACSignalSupport.m */, D037645819EDA41200A782A9 /* NSURLConnection+RACSupport.h */, D037645919EDA41200A782A9 /* NSURLConnection+RACSupport.m */, D037645A19EDA41200A782A9 /* NSUserDefaults+RACSupport.h */, D037645B19EDA41200A782A9 /* NSUserDefaults+RACSupport.m */, D037645C19EDA41200A782A9 /* RACArraySequence.h */, D037645D19EDA41200A782A9 /* RACArraySequence.m */, D037646019EDA41200A782A9 /* RACBehaviorSubject.h */, D037646119EDA41200A782A9 /* RACBehaviorSubject.m */, D037646219EDA41200A782A9 /* RACBlockTrampoline.h */, D037646319EDA41200A782A9 /* RACBlockTrampoline.m */, D037646419EDA41200A782A9 /* RACChannel.h */, D037646519EDA41200A782A9 /* RACChannel.m */, D037646619EDA41200A782A9 /* RACCommand.h */, D037646719EDA41200A782A9 /* RACCommand.m */, D037646819EDA41200A782A9 /* RACCompoundDisposable.h */, D037646919EDA41200A782A9 /* RACCompoundDisposable.m */, D037646A19EDA41200A782A9 /* RACCompoundDisposableProvider.d */, D037646B19EDA41200A782A9 /* RACDelegateProxy.h */, D037646C19EDA41200A782A9 /* RACDelegateProxy.m */, D037646D19EDA41200A782A9 /* RACDisposable.h */, D037646E19EDA41200A782A9 /* RACDisposable.m */, D037646F19EDA41200A782A9 /* RACDynamicSequence.h */, D037647019EDA41200A782A9 /* RACDynamicSequence.m */, D037647119EDA41200A782A9 /* RACDynamicSignal.h */, D037647219EDA41200A782A9 /* RACDynamicSignal.m */, D037647319EDA41200A782A9 /* RACEagerSequence.h */, D037647419EDA41200A782A9 /* RACEagerSequence.m */, D037647519EDA41200A782A9 /* RACEmptySequence.h */, D037647619EDA41200A782A9 /* RACEmptySequence.m */, D037647719EDA41200A782A9 /* RACEmptySignal.h */, D037647819EDA41200A782A9 /* RACEmptySignal.m */, D037647919EDA41200A782A9 /* RACErrorSignal.h */, D037647A19EDA41200A782A9 /* RACErrorSignal.m */, D037647B19EDA41200A782A9 /* RACEvent.h */, D037647C19EDA41200A782A9 /* RACEvent.m */, D037647D19EDA41200A782A9 /* RACGroupedSignal.h */, D037647E19EDA41200A782A9 /* RACGroupedSignal.m */, D037647F19EDA41200A782A9 /* RACImmediateScheduler.h */, D037648019EDA41200A782A9 /* RACImmediateScheduler.m */, D037648119EDA41200A782A9 /* RACIndexSetSequence.h */, D037648219EDA41200A782A9 /* RACIndexSetSequence.m */, D037648319EDA41200A782A9 /* RACKVOChannel.h */, D037648419EDA41200A782A9 /* RACKVOChannel.m */, 7A70657D1A3F88B8001E8354 /* RACKVOProxy.h */, 7A70657E1A3F88B8001E8354 /* RACKVOProxy.m */, D037648519EDA41200A782A9 /* RACKVOTrampoline.h */, D037648619EDA41200A782A9 /* RACKVOTrampoline.m */, D037648719EDA41200A782A9 /* RACMulticastConnection.h */, D037648819EDA41200A782A9 /* RACMulticastConnection.m */, D037648919EDA41200A782A9 /* RACMulticastConnection+Private.h */, D037648A19EDA41200A782A9 /* RACObjCRuntime.h */, D037648B19EDA41200A782A9 /* RACObjCRuntime.m */, D037648C19EDA41200A782A9 /* RACPassthroughSubscriber.h */, D037648D19EDA41200A782A9 /* RACPassthroughSubscriber.m */, D037648E19EDA41200A782A9 /* RACQueueScheduler.h */, D037648F19EDA41200A782A9 /* RACQueueScheduler.m */, D037649019EDA41200A782A9 /* RACQueueScheduler+Subclass.h */, D037649119EDA41200A782A9 /* RACReplaySubject.h */, D037649219EDA41200A782A9 /* RACReplaySubject.m */, D037649319EDA41200A782A9 /* RACReturnSignal.h */, D037649419EDA41200A782A9 /* RACReturnSignal.m */, D037649519EDA41200A782A9 /* RACScheduler.h */, D037649619EDA41200A782A9 /* RACScheduler.m */, D037649719EDA41200A782A9 /* RACScheduler+Private.h */, D037649819EDA41200A782A9 /* RACScheduler+Subclass.h */, D037649919EDA41200A782A9 /* RACScopedDisposable.h */, D037649A19EDA41200A782A9 /* RACScopedDisposable.m */, D037649B19EDA41200A782A9 /* RACSequence.h */, D037649C19EDA41200A782A9 /* RACSequence.m */, D037649D19EDA41200A782A9 /* RACSerialDisposable.h */, D037649E19EDA41200A782A9 /* RACSerialDisposable.m */, D037649F19EDA41200A782A9 /* RACSignal.h */, D03764A019EDA41200A782A9 /* RACSignal.m */, D03764A119EDA41200A782A9 /* RACSignal+Operations.h */, D03764A219EDA41200A782A9 /* RACSignal+Operations.m */, D03764A319EDA41200A782A9 /* RACSignalProvider.d */, D03764A419EDA41200A782A9 /* RACSignalSequence.h */, D03764A519EDA41200A782A9 /* RACSignalSequence.m */, D03764A619EDA41200A782A9 /* RACStream.h */, D03764A719EDA41200A782A9 /* RACStream.m */, D03764A819EDA41200A782A9 /* RACStream+Private.h */, D03764A919EDA41200A782A9 /* RACStringSequence.h */, D03764AA19EDA41200A782A9 /* RACStringSequence.m */, D03764AB19EDA41200A782A9 /* RACSubject.h */, D03764AC19EDA41200A782A9 /* RACSubject.m */, D03764AD19EDA41200A782A9 /* RACSubscriber.h */, D03764AE19EDA41200A782A9 /* RACSubscriber.m */, D03764AF19EDA41200A782A9 /* RACSubscriber+Private.h */, D03764B019EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.h */, D03764B119EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.m */, D03764B219EDA41200A782A9 /* RACSubscriptionScheduler.h */, D03764B319EDA41200A782A9 /* RACSubscriptionScheduler.m */, D03764B419EDA41200A782A9 /* RACTargetQueueScheduler.h */, D03764B519EDA41200A782A9 /* RACTargetQueueScheduler.m */, D03764B619EDA41200A782A9 /* RACTestScheduler.h */, D03764B719EDA41200A782A9 /* RACTestScheduler.m */, D03764B819EDA41200A782A9 /* RACTuple.h */, D03764B919EDA41200A782A9 /* RACTuple.m */, D03764BA19EDA41200A782A9 /* RACTupleSequence.h */, D03764BB19EDA41200A782A9 /* RACTupleSequence.m */, D03764BC19EDA41200A782A9 /* RACUnarySequence.h */, D03764BD19EDA41200A782A9 /* RACUnarySequence.m */, D03764BE19EDA41200A782A9 /* RACUnit.h */, D03764BF19EDA41200A782A9 /* RACUnit.m */, D03764C019EDA41200A782A9 /* RACValueTransformer.h */, D03764C119EDA41200A782A9 /* RACValueTransformer.m */, D03764C219EDA41200A782A9 /* UIActionSheet+RACSignalSupport.h */, D03764C319EDA41200A782A9 /* UIActionSheet+RACSignalSupport.m */, D03764C419EDA41200A782A9 /* UIAlertView+RACSignalSupport.h */, D03764C519EDA41200A782A9 /* UIAlertView+RACSignalSupport.m */, D03764C619EDA41200A782A9 /* UIBarButtonItem+RACCommandSupport.h */, D03764C719EDA41200A782A9 /* UIBarButtonItem+RACCommandSupport.m */, D03764C819EDA41200A782A9 /* UIButton+RACCommandSupport.h */, D03764C919EDA41200A782A9 /* UIButton+RACCommandSupport.m */, D03764CA19EDA41200A782A9 /* UICollectionReusableView+RACSignalSupport.h */, D03764CB19EDA41200A782A9 /* UICollectionReusableView+RACSignalSupport.m */, D03764CC19EDA41200A782A9 /* UIControl+RACSignalSupport.h */, D03764CD19EDA41200A782A9 /* UIControl+RACSignalSupport.m */, D03764CE19EDA41200A782A9 /* UIControl+RACSignalSupportPrivate.h */, D03764CF19EDA41200A782A9 /* UIControl+RACSignalSupportPrivate.m */, D03764D019EDA41200A782A9 /* UIDatePicker+RACSignalSupport.h */, D03764D119EDA41200A782A9 /* UIDatePicker+RACSignalSupport.m */, D03764D219EDA41200A782A9 /* UIGestureRecognizer+RACSignalSupport.h */, D03764D319EDA41200A782A9 /* UIGestureRecognizer+RACSignalSupport.m */, D03764D419EDA41200A782A9 /* UIImagePickerController+RACSignalSupport.h */, D03764D519EDA41200A782A9 /* UIImagePickerController+RACSignalSupport.m */, D03764D619EDA41200A782A9 /* UIRefreshControl+RACCommandSupport.h */, D03764D719EDA41200A782A9 /* UIRefreshControl+RACCommandSupport.m */, D03764D819EDA41200A782A9 /* UISegmentedControl+RACSignalSupport.h */, D03764D919EDA41200A782A9 /* UISegmentedControl+RACSignalSupport.m */, D03764DA19EDA41200A782A9 /* UISlider+RACSignalSupport.h */, D03764DB19EDA41200A782A9 /* UISlider+RACSignalSupport.m */, D03764DC19EDA41200A782A9 /* UIStepper+RACSignalSupport.h */, D03764DD19EDA41200A782A9 /* UIStepper+RACSignalSupport.m */, D03764DE19EDA41200A782A9 /* UISwitch+RACSignalSupport.h */, D03764DF19EDA41200A782A9 /* UISwitch+RACSignalSupport.m */, D03764E019EDA41200A782A9 /* UITableViewCell+RACSignalSupport.h */, D03764E119EDA41200A782A9 /* UITableViewCell+RACSignalSupport.m */, D03764E219EDA41200A782A9 /* UITableViewHeaderFooterView+RACSignalSupport.h */, D03764E319EDA41200A782A9 /* UITableViewHeaderFooterView+RACSignalSupport.m */, D03764E419EDA41200A782A9 /* UITextField+RACSignalSupport.h */, D03764E519EDA41200A782A9 /* UITextField+RACSignalSupport.m */, D03764E619EDA41200A782A9 /* UITextView+RACSignalSupport.h */, D03764E719EDA41200A782A9 /* UITextView+RACSignalSupport.m */, D43F279E1A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.h */, D43F279F1A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.m */, ); path = "Objective-C"; sourceTree = ""; }; D037666519EDA57100A782A9 /* extobjc */ = { isa = PBXGroup; children = ( D037666619EDA57100A782A9 /* EXTKeyPathCoding.h */, D037666719EDA57100A782A9 /* EXTRuntimeExtensions.h */, D037666819EDA57100A782A9 /* EXTRuntimeExtensions.m */, D037666919EDA57100A782A9 /* EXTScope.h */, D037666A19EDA57100A782A9 /* metamacros.h */, ); path = extobjc; sourceTree = ""; }; D037667519EDA5D900A782A9 /* Objective-C */ = { isa = PBXGroup; children = ( D037667619EDA60000A782A9 /* NSControllerRACSupportSpec.m */, D037667819EDA60000A782A9 /* NSEnumeratorRACSequenceAdditionsSpec.m */, D037667919EDA60000A782A9 /* NSNotificationCenterRACSupportSpec.m */, D037667A19EDA60000A782A9 /* NSObjectRACAppKitBindingsSpec.m */, D037667B19EDA60000A782A9 /* NSObjectRACDeallocatingSpec.m */, D037667C19EDA60000A782A9 /* NSObjectRACLiftingSpec.m */, D037667D19EDA60000A782A9 /* NSObjectRACPropertySubscribingExamples.h */, D037667E19EDA60000A782A9 /* NSObjectRACPropertySubscribingExamples.m */, D037667F19EDA60000A782A9 /* NSObjectRACPropertySubscribingSpec.m */, D037668019EDA60000A782A9 /* NSObjectRACSelectorSignalSpec.m */, D037668119EDA60000A782A9 /* NSStringRACKeyPathUtilitiesSpec.m */, D037668319EDA60000A782A9 /* NSURLConnectionRACSupportSpec.m */, D037668419EDA60000A782A9 /* NSUserDefaultsRACSupportSpec.m */, D037668619EDA60000A782A9 /* RACBlockTrampolineSpec.m */, D037668719EDA60000A782A9 /* RACChannelExamples.h */, D037668819EDA60000A782A9 /* RACChannelExamples.m */, D037668919EDA60000A782A9 /* RACChannelSpec.m */, D037668A19EDA60000A782A9 /* RACCommandSpec.m */, D037668B19EDA60000A782A9 /* RACCompoundDisposableSpec.m */, D037668C19EDA60000A782A9 /* RACControlCommandExamples.h */, D037668D19EDA60000A782A9 /* RACControlCommandExamples.m */, D037668E19EDA60000A782A9 /* RACDelegateProxySpec.m */, D037668F19EDA60000A782A9 /* RACDisposableSpec.m */, D037669019EDA60000A782A9 /* RACEventSpec.m */, D037669119EDA60000A782A9 /* RACKVOChannelSpec.m */, 7A7065831A3F8967001E8354 /* RACKVOProxySpec.m */, D037669219EDA60000A782A9 /* RACKVOWrapperSpec.m */, D037669319EDA60000A782A9 /* RACMulticastConnectionSpec.m */, D037669419EDA60000A782A9 /* RACPropertySignalExamples.h */, D037669519EDA60000A782A9 /* RACPropertySignalExamples.m */, D037669619EDA60000A782A9 /* RACSchedulerSpec.m */, D037669719EDA60000A782A9 /* RACSequenceAdditionsSpec.m */, D037669819EDA60000A782A9 /* RACSequenceExamples.h */, D037669919EDA60000A782A9 /* RACSequenceExamples.m */, D037669A19EDA60000A782A9 /* RACSequenceSpec.m */, D037669B19EDA60000A782A9 /* RACSerialDisposableSpec.m */, D037669C19EDA60000A782A9 /* RACSignalSpec.m */, D037669F19EDA60000A782A9 /* RACStreamExamples.h */, D03766A019EDA60000A782A9 /* RACStreamExamples.m */, D03766A119EDA60000A782A9 /* RACSubclassObject.h */, D03766A219EDA60000A782A9 /* RACSubclassObject.m */, D03766A319EDA60000A782A9 /* RACSubjectSpec.m */, D03766A419EDA60000A782A9 /* RACSubscriberExamples.h */, D03766A519EDA60000A782A9 /* RACSubscriberExamples.m */, D03766A619EDA60000A782A9 /* RACSubscriberSpec.m */, D03766A719EDA60000A782A9 /* RACSubscriptingAssignmentTrampolineSpec.m */, D03766A819EDA60000A782A9 /* RACTargetQueueSchedulerSpec.m */, D03766B019EDA60000A782A9 /* RACTupleSpec.m */, D03766B219EDA60000A782A9 /* UIActionSheetRACSupportSpec.m */, D03766B319EDA60000A782A9 /* UIAlertViewRACSupportSpec.m */, D03766B419EDA60000A782A9 /* UIBarButtonItemRACSupportSpec.m */, D03766B519EDA60000A782A9 /* UIButtonRACSupportSpec.m */, D03766B719EDA60000A782A9 /* UIImagePickerControllerRACSupportSpec.m */, D0C3131719EF2D9700984962 /* RACTestExampleScheduler.h */, D0C3131819EF2D9700984962 /* RACTestExampleScheduler.m */, D0C3131919EF2D9700984962 /* RACTestObject.h */, D0C3131A19EF2D9700984962 /* RACTestObject.m */, D0C3131B19EF2D9700984962 /* RACTestSchedulerSpec.m */, D0C3131C19EF2D9700984962 /* RACTestUIButton.h */, D0C3131D19EF2D9700984962 /* RACTestUIButton.m */, ); path = "Objective-C"; sourceTree = ""; }; D03B4A3919F4C25F009E02AC /* Signals */ = { isa = PBXGroup; children = ( D08C54AF1A69A2AC00AD8286 /* Action.swift */, D85C65291C0D84C7005A77AD /* Flatten.swift */, D08C54B01A69A2AC00AD8286 /* Property.swift */, D08C54B11A69A2AC00AD8286 /* Signal.swift */, D08C54B21A69A2AC00AD8286 /* SignalProducer.swift */, ); name = Signals; sourceTree = ""; }; D03B4A3A19F4C26D009E02AC /* Internal Utilities */ = { isa = PBXGroup; children = ( D00004081A46864E000E7D41 /* TupleExtensions.swift */, ); name = "Internal Utilities"; sourceTree = ""; }; D03B4A3B19F4C281009E02AC /* Extensions */ = { isa = PBXGroup; children = ( D03B4A3C19F4C39A009E02AC /* FoundationExtensions.swift */, ); name = Extensions; sourceTree = ""; }; D04725E019E49ED7006002AA = { isa = PBXGroup; children = ( D04725EC19E49ED7006002AA /* ReactiveCocoa */, D04725F919E49ED7006002AA /* ReactiveCocoaTests */, D047262519E49FE8006002AA /* Configuration */, D04725EB19E49ED7006002AA /* Products */, ); sourceTree = ""; usesTabs = 1; }; D04725EB19E49ED7006002AA /* Products */ = { isa = PBXGroup; children = ( D04725EA19E49ED7006002AA /* ReactiveCocoa.framework */, D04725F519E49ED7006002AA /* ReactiveCocoaTests.xctest */, D047260C19E49F82006002AA /* ReactiveCocoa.framework */, D047261619E49F82006002AA /* ReactiveCocoaTests.xctest */, A9B315541B3940610001CB9C /* ReactiveCocoa.framework */, 57A4D2411BA13D7A00F7D4B1 /* ReactiveCocoa.framework */, ); name = Products; sourceTree = ""; }; D04725EC19E49ED7006002AA /* ReactiveCocoa */ = { isa = PBXGroup; children = ( D04725EF19E49ED7006002AA /* ReactiveCocoa.h */, D0C312B919EF2A3000984962 /* Swift */, D037642919EDA3B600A782A9 /* Objective-C */, D04725ED19E49ED7006002AA /* Supporting Files */, ); path = ReactiveCocoa; sourceTree = ""; }; D04725ED19E49ED7006002AA /* Supporting Files */ = { isa = PBXGroup; children = ( CD183E811AED1E0E00848F5D /* Box.framework */, CDC42E2E1AE7AB8B00965373 /* Result.framework */, D04725EE19E49ED7006002AA /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; D04725F919E49ED7006002AA /* ReactiveCocoaTests */ = { isa = PBXGroup; children = ( D0C312ED19EF2A6F00984962 /* Swift */, D037667519EDA5D900A782A9 /* Objective-C */, D04725FA19E49ED7006002AA /* Supporting Files */, ); path = ReactiveCocoaTests; sourceTree = ""; }; D04725FA19E49ED7006002AA /* Supporting Files */ = { isa = PBXGroup; children = ( D05E662419EDD82000904ACA /* Nimble.framework */, D037672B19EDA75D00A782A9 /* Quick.framework */, D03766B119EDA60000A782A9 /* test-data.json */, BFA6B94A1A76044800C846D1 /* SignalProducerNimbleMatchers.swift */, D04725FB19E49ED7006002AA /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; D047262519E49FE8006002AA /* Configuration */ = { isa = PBXGroup; children = ( D047262619E49FE8006002AA /* Base */, D047263119E49FE8006002AA /* iOS */, D047263619E49FE8006002AA /* Mac OS X */, A97451321B3A935E00F48E55 /* watchOS */, 57A4D2431BA13F9700F7D4B1 /* tvOS */, D047263C19E49FE8006002AA /* README.md */, ); name = Configuration; path = Carthage/Checkouts/xcconfigs; sourceTree = ""; }; D047262619E49FE8006002AA /* Base */ = { isa = PBXGroup; children = ( D047262719E49FE8006002AA /* Common.xcconfig */, D047262819E49FE8006002AA /* Configurations */, D047262D19E49FE8006002AA /* Targets */, ); path = Base; sourceTree = ""; }; D047262819E49FE8006002AA /* Configurations */ = { isa = PBXGroup; children = ( D047262919E49FE8006002AA /* Debug.xcconfig */, D047262A19E49FE8006002AA /* Profile.xcconfig */, D047262B19E49FE8006002AA /* Release.xcconfig */, D047262C19E49FE8006002AA /* Test.xcconfig */, ); path = Configurations; sourceTree = ""; }; D047262D19E49FE8006002AA /* Targets */ = { isa = PBXGroup; children = ( D047262E19E49FE8006002AA /* Application.xcconfig */, D047262F19E49FE8006002AA /* Framework.xcconfig */, D047263019E49FE8006002AA /* StaticLibrary.xcconfig */, ); path = Targets; sourceTree = ""; }; D047263119E49FE8006002AA /* iOS */ = { isa = PBXGroup; children = ( D047263219E49FE8006002AA /* iOS-Application.xcconfig */, D047263319E49FE8006002AA /* iOS-Base.xcconfig */, D047263419E49FE8006002AA /* iOS-Framework.xcconfig */, D047263519E49FE8006002AA /* iOS-StaticLibrary.xcconfig */, ); path = iOS; sourceTree = ""; }; D047263619E49FE8006002AA /* Mac OS X */ = { isa = PBXGroup; children = ( D047263719E49FE8006002AA /* Mac-Application.xcconfig */, D047263819E49FE8006002AA /* Mac-Base.xcconfig */, D047263919E49FE8006002AA /* Mac-DynamicLibrary.xcconfig */, D047263A19E49FE8006002AA /* Mac-Framework.xcconfig */, D047263B19E49FE8006002AA /* Mac-StaticLibrary.xcconfig */, ); path = "Mac OS X"; sourceTree = ""; }; D0C312B919EF2A3000984962 /* Swift */ = { isa = PBXGroup; children = ( D0C312BB19EF2A5800984962 /* Atomic.swift */, D0C312BC19EF2A5800984962 /* Bag.swift */, D0C312BE19EF2A5800984962 /* Disposable.swift */, D08C54B51A69A3DB00AD8286 /* Event.swift */, D0C312C419EF2A5800984962 /* ObjectiveCBridging.swift */, EBCC7DBB1BBF010C00A2AE92 /* Observer.swift */, D871D69E1B3B29A40070F16C /* Optional.swift */, D0C312C819EF2A5800984962 /* Scheduler.swift */, D03B4A3919F4C25F009E02AC /* Signals */, D03B4A3A19F4C26D009E02AC /* Internal Utilities */, D03B4A3B19F4C281009E02AC /* Extensions */, ); path = Swift; sourceTree = ""; }; D0C312ED19EF2A6F00984962 /* Swift */ = { isa = PBXGroup; children = ( D021671C1A6CD50500987861 /* ActionSpec.swift */, D0C312EE19EF2A7700984962 /* AtomicSpec.swift */, D0C312EF19EF2A7700984962 /* BagSpec.swift */, D0C312F019EF2A7700984962 /* DisposableSpec.swift */, D8170FC01B100EBC004192AD /* FoundationExtensionsSpec.swift */, D0A226101A72F30B00D33B74 /* ObjectiveCBridgingSpec.swift */, D0A2260D1A72F16D00D33B74 /* PropertySpec.swift */, D0C312F219EF2A7700984962 /* SchedulerSpec.swift */, 02D260291C1D6DAF003ACC61 /* SignalLifetimeSpec.swift */, D0A2260A1A72E6C500D33B74 /* SignalProducerSpec.swift */, D8024DB11B2E1BB0005E6B9A /* SignalProducerLiftingSpec.swift */, D0A226071A72E0E900D33B74 /* SignalSpec.swift */, CA6F284F1C52626B001879D2 /* FlattenSpec.swift */, B696FB801A7640C00075236D /* TestError.swift */, ); path = Swift; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 57A4D2091BA13D7A00F7D4B1 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 57A4D20A1BA13D7A00F7D4B1 /* ReactiveCocoa.h in Headers */, 57A4D20B1BA13D7A00F7D4B1 /* EXTKeyPathCoding.h in Headers */, A1046B7D1BFF5664004D8045 /* EXTRuntimeExtensions.h in Headers */, 57A4D20C1BA13D7A00F7D4B1 /* EXTScope.h in Headers */, 57A4D20D1BA13D7A00F7D4B1 /* metamacros.h in Headers */, 57A4D20E1BA13D7A00F7D4B1 /* NSArray+RACSequenceAdditions.h in Headers */, 57A4D20F1BA13D7A00F7D4B1 /* NSData+RACSupport.h in Headers */, 57A4D2101BA13D7A00F7D4B1 /* NSDictionary+RACSequenceAdditions.h in Headers */, 57A4D2111BA13D7A00F7D4B1 /* NSEnumerator+RACSequenceAdditions.h in Headers */, 57A4D2121BA13D7A00F7D4B1 /* NSFileHandle+RACSupport.h in Headers */, 57A4D2131BA13D7A00F7D4B1 /* NSIndexSet+RACSequenceAdditions.h in Headers */, 57A4D2141BA13D7A00F7D4B1 /* NSNotificationCenter+RACSupport.h in Headers */, 57A4D2151BA13D7A00F7D4B1 /* NSObject+RACDeallocating.h in Headers */, 57A4D2161BA13D7A00F7D4B1 /* NSObject+RACLifting.h in Headers */, 57A4D2171BA13D7A00F7D4B1 /* NSObject+RACPropertySubscribing.h in Headers */, 57DC89A01C5066D400E367B7 /* UIGestureRecognizer+RACSignalSupport.h in Headers */, 57A4D2181BA13D7A00F7D4B1 /* NSObject+RACSelectorSignal.h in Headers */, 57A4D2191BA13D7A00F7D4B1 /* NSOrderedSet+RACSequenceAdditions.h in Headers */, 57A4D21A1BA13D7A00F7D4B1 /* NSSet+RACSequenceAdditions.h in Headers */, 57A4D21B1BA13D7A00F7D4B1 /* NSString+RACSequenceAdditions.h in Headers */, 57A4D21C1BA13D7A00F7D4B1 /* NSString+RACSupport.h in Headers */, 57A4D21E1BA13D7A00F7D4B1 /* NSUserDefaults+RACSupport.h in Headers */, 57A4D21F1BA13D7A00F7D4B1 /* RACBehaviorSubject.h in Headers */, 57A4D2201BA13D7A00F7D4B1 /* RACChannel.h in Headers */, 57A4D2211BA13D7A00F7D4B1 /* RACCommand.h in Headers */, 57A4D2221BA13D7A00F7D4B1 /* RACCompoundDisposable.h in Headers */, 57A4D2231BA13D7A00F7D4B1 /* RACDisposable.h in Headers */, 57A4D2241BA13D7A00F7D4B1 /* RACEvent.h in Headers */, 57A4D2251BA13D7A00F7D4B1 /* RACGroupedSignal.h in Headers */, 57A4D2261BA13D7A00F7D4B1 /* RACKVOChannel.h in Headers */, 57A4D2271BA13D7A00F7D4B1 /* RACMulticastConnection.h in Headers */, 57A4D2281BA13D7A00F7D4B1 /* RACQueueScheduler.h in Headers */, 57DC89A51C50675700E367B7 /* UITextField+RACSignalSupport.h in Headers */, 57A4D2291BA13D7A00F7D4B1 /* RACQueueScheduler+Subclass.h in Headers */, 57A4D22A1BA13D7A00F7D4B1 /* RACReplaySubject.h in Headers */, 57DC89A21C50673C00E367B7 /* UISegmentedControl+RACSignalSupport.h in Headers */, 57A4D22B1BA13D7A00F7D4B1 /* RACScheduler.h in Headers */, 57DC89A41C50674D00E367B7 /* UITableViewHeaderFooterView+RACSignalSupport.h in Headers */, 57A4D22C1BA13D7A00F7D4B1 /* RACScheduler+Subclass.h in Headers */, 57DC89A11C50672B00E367B7 /* UIControl+RACSignalSupport.h in Headers */, 57A4D22D1BA13D7A00F7D4B1 /* RACScopedDisposable.h in Headers */, 57DC89A31C50674300E367B7 /* UITableViewCell+RACSignalSupport.h in Headers */, 57A4D22E1BA13D7A00F7D4B1 /* RACSequence.h in Headers */, 57A4D22F1BA13D7A00F7D4B1 /* RACSerialDisposable.h in Headers */, 57A4D2301BA13D7A00F7D4B1 /* RACSignal.h in Headers */, 57DC89A81C50679E00E367B7 /* UICollectionReusableView+RACSignalSupport.h in Headers */, 57DC89A71C50679700E367B7 /* UIButton+RACCommandSupport.h in Headers */, 57A4D2311BA13D7A00F7D4B1 /* RACSignal+Operations.h in Headers */, 57A4D2321BA13D7A00F7D4B1 /* RACStream.h in Headers */, 57A4D2331BA13D7A00F7D4B1 /* RACSubject.h in Headers */, 57A4D2341BA13D7A00F7D4B1 /* RACSubscriber.h in Headers */, 57A4D2351BA13D7A00F7D4B1 /* RACSubscriptingAssignmentTrampoline.h in Headers */, 57A4D2361BA13D7A00F7D4B1 /* RACTargetQueueScheduler.h in Headers */, 57A4D2371BA13D7A00F7D4B1 /* RACTestScheduler.h in Headers */, 57A4D2381BA13D7A00F7D4B1 /* RACTuple.h in Headers */, 57DC89A61C50675F00E367B7 /* UITextView+RACSignalSupport.h in Headers */, 57A4D2391BA13D7A00F7D4B1 /* RACUnit.h in Headers */, 57A4D23A1BA13D7A00F7D4B1 /* RACDynamicPropertySuperclass.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; A9B315511B3940610001CB9C /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( A9B315CA1B3940AB0001CB9C /* ReactiveCocoa.h in Headers */, A9B315CB1B3940AB0001CB9C /* EXTKeyPathCoding.h in Headers */, A1046B7C1BFF5662004D8045 /* EXTRuntimeExtensions.h in Headers */, A9B315CD1B3940AB0001CB9C /* EXTScope.h in Headers */, A9B315CE1B3940AB0001CB9C /* metamacros.h in Headers */, A9B315D01B3940AB0001CB9C /* NSArray+RACSequenceAdditions.h in Headers */, A9B315D31B3940AB0001CB9C /* NSData+RACSupport.h in Headers */, A9B315D41B3940AB0001CB9C /* NSDictionary+RACSequenceAdditions.h in Headers */, A9B315D51B3940AB0001CB9C /* NSEnumerator+RACSequenceAdditions.h in Headers */, A9B315D61B3940AB0001CB9C /* NSFileHandle+RACSupport.h in Headers */, A9B315D71B3940AB0001CB9C /* NSIndexSet+RACSequenceAdditions.h in Headers */, A9B315D91B3940AB0001CB9C /* NSNotificationCenter+RACSupport.h in Headers */, A9B315DB1B3940AB0001CB9C /* NSObject+RACDeallocating.h in Headers */, A9B315DE1B3940AB0001CB9C /* NSObject+RACLifting.h in Headers */, A9B315DF1B3940AB0001CB9C /* NSObject+RACPropertySubscribing.h in Headers */, A9B315E01B3940AB0001CB9C /* NSObject+RACSelectorSignal.h in Headers */, A9B315E11B3940AB0001CB9C /* NSOrderedSet+RACSequenceAdditions.h in Headers */, A9B315E21B3940AB0001CB9C /* NSSet+RACSequenceAdditions.h in Headers */, A9B315E41B3940AB0001CB9C /* NSString+RACSequenceAdditions.h in Headers */, A9B315E51B3940AB0001CB9C /* NSString+RACSupport.h in Headers */, A9B315E81B3940AB0001CB9C /* NSUserDefaults+RACSupport.h in Headers */, A9B315EA1B3940AB0001CB9C /* RACBehaviorSubject.h in Headers */, A9B315EC1B3940AB0001CB9C /* RACChannel.h in Headers */, A9B315ED1B3940AC0001CB9C /* RACCommand.h in Headers */, A9B315EE1B3940AC0001CB9C /* RACCompoundDisposable.h in Headers */, A9B315F01B3940AC0001CB9C /* RACDisposable.h in Headers */, A9B315F71B3940AC0001CB9C /* RACEvent.h in Headers */, A9B315F81B3940AC0001CB9C /* RACGroupedSignal.h in Headers */, A9B315FB1B3940AC0001CB9C /* RACKVOChannel.h in Headers */, A9B315FE1B3940AC0001CB9C /* RACMulticastConnection.h in Headers */, A9B316021B3940AD0001CB9C /* RACQueueScheduler.h in Headers */, A9B316031B3940AD0001CB9C /* RACQueueScheduler+Subclass.h in Headers */, A9B316041B3940AD0001CB9C /* RACReplaySubject.h in Headers */, A9B316061B3940AD0001CB9C /* RACScheduler.h in Headers */, A9B316081B3940AD0001CB9C /* RACScheduler+Subclass.h in Headers */, A9B316091B3940AD0001CB9C /* RACScopedDisposable.h in Headers */, A9B3160A1B3940AD0001CB9C /* RACSequence.h in Headers */, A9B3160B1B3940AD0001CB9C /* RACSerialDisposable.h in Headers */, A9B3160C1B3940AE0001CB9C /* RACSignal.h in Headers */, A9B3160D1B3940AE0001CB9C /* RACSignal+Operations.h in Headers */, A9B3160F1B3940AE0001CB9C /* RACStream.h in Headers */, A9B316121B3940AE0001CB9C /* RACSubject.h in Headers */, A9B316131B3940AE0001CB9C /* RACSubscriber.h in Headers */, A9B316151B3940AE0001CB9C /* RACSubscriptingAssignmentTrampoline.h in Headers */, A9B316171B3940AF0001CB9C /* RACTargetQueueScheduler.h in Headers */, A9B316181B3940AF0001CB9C /* RACTestScheduler.h in Headers */, A9B316191B3940AF0001CB9C /* RACTuple.h in Headers */, A9B3161C1B3940AF0001CB9C /* RACUnit.h in Headers */, A9B316311B3940B20001CB9C /* RACDynamicPropertySuperclass.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; D04725E719E49ED7006002AA /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( D04725F019E49ED7006002AA /* ReactiveCocoa.h in Headers */, D037652019EDA41200A782A9 /* NSObject+RACLifting.h in Headers */, D03764EC19EDA41200A782A9 /* NSControl+RACCommandSupport.h in Headers */, D037655C19EDA41200A782A9 /* RACChannel.h in Headers */, D03765EE19EDA41200A782A9 /* RACSubscriber.h in Headers */, D03765D219EDA41200A782A9 /* RACSignal.h in Headers */, D037650419EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.h in Headers */, D43F27A01A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.h in Headers */, D037659A19EDA41200A782A9 /* RACKVOChannel.h in Headers */, D037651419EDA41200A782A9 /* NSObject+RACDeallocating.h in Headers */, D037650C19EDA41200A782A9 /* NSNotificationCenter+RACSupport.h in Headers */, D037667319EDA57100A782A9 /* metamacros.h in Headers */, D037666B19EDA57100A782A9 /* EXTKeyPathCoding.h in Headers */, D03765F419EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.h in Headers */, D03765C419EDA41200A782A9 /* RACScheduler+Subclass.h in Headers */, D037656E19EDA41200A782A9 /* RACDisposable.h in Headers */, D03765B019EDA41200A782A9 /* RACQueueScheduler.h in Headers */, D037652419EDA41200A782A9 /* NSObject+RACPropertySubscribing.h in Headers */, D037650019EDA41200A782A9 /* NSFileHandle+RACSupport.h in Headers */, D037653019EDA41200A782A9 /* NSSet+RACSequenceAdditions.h in Headers */, D037654019EDA41200A782A9 /* NSText+RACSignalSupport.h in Headers */, D03765E019EDA41200A782A9 /* RACStream.h in Headers */, D03765FC19EDA41200A782A9 /* RACTargetQueueScheduler.h in Headers */, D03765B419EDA41200A782A9 /* RACQueueScheduler+Subclass.h in Headers */, D037661019EDA41200A782A9 /* RACUnit.h in Headers */, D037656419EDA41200A782A9 /* RACCompoundDisposable.h in Headers */, D03764F419EDA41200A782A9 /* NSData+RACSupport.h in Headers */, D03764FC19EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.h in Headers */, D03765CA19EDA41200A782A9 /* RACSequence.h in Headers */, D037672719EDA63400A782A9 /* RACBehaviorSubject.h in Headers */, D037653C19EDA41200A782A9 /* NSString+RACSupport.h in Headers */, D03765CE19EDA41200A782A9 /* RACSerialDisposable.h in Headers */, D03765D619EDA41200A782A9 /* RACSignal+Operations.h in Headers */, D03765B619EDA41200A782A9 /* RACReplaySubject.h in Headers */, D03765A219EDA41200A782A9 /* RACMulticastConnection.h in Headers */, D037658E19EDA41200A782A9 /* RACGroupedSignal.h in Headers */, D037654819EDA41200A782A9 /* NSUserDefaults+RACSupport.h in Headers */, D03765BE19EDA41200A782A9 /* RACScheduler.h in Headers */, D037656019EDA41200A782A9 /* RACCommand.h in Headers */, D037660419EDA41200A782A9 /* RACTuple.h in Headers */, D03765C619EDA41200A782A9 /* RACScopedDisposable.h in Headers */, D037660019EDA41200A782A9 /* RACTestScheduler.h in Headers */, D037652C19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.h in Headers */, D03764F019EDA41200A782A9 /* NSControl+RACTextSignalSupport.h in Headers */, D03765EA19EDA41200A782A9 /* RACSubject.h in Headers */, A1046B7A1BFF5661004D8045 /* EXTRuntimeExtensions.h in Headers */, D037652819EDA41200A782A9 /* NSObject+RACSelectorSignal.h in Headers */, D037654419EDA41200A782A9 /* NSURLConnection+RACSupport.h in Headers */, D03764E819EDA41200A782A9 /* NSArray+RACSequenceAdditions.h in Headers */, D037651019EDA41200A782A9 /* NSObject+RACAppKitBindings.h in Headers */, D037658A19EDA41200A782A9 /* RACEvent.h in Headers */, D037667119EDA57100A782A9 /* EXTScope.h in Headers */, D037653819EDA41200A782A9 /* NSString+RACSequenceAdditions.h in Headers */, D03764F819EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; D047260919E49F82006002AA /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( D037664519EDA41200A782A9 /* UISegmentedControl+RACSignalSupport.h in Headers */, D037666419EDA43C00A782A9 /* ReactiveCocoa.h in Headers */, D037652519EDA41200A782A9 /* NSObject+RACPropertySubscribing.h in Headers */, D03765B119EDA41200A782A9 /* RACQueueScheduler.h in Headers */, D037662519EDA41200A782A9 /* UIButton+RACCommandSupport.h in Headers */, D037672819EDA63500A782A9 /* RACBehaviorSubject.h in Headers */, D037660119EDA41200A782A9 /* RACTestScheduler.h in Headers */, D03765A319EDA41200A782A9 /* RACMulticastConnection.h in Headers */, D03765B719EDA41200A782A9 /* RACReplaySubject.h in Headers */, D037663D19EDA41200A782A9 /* UIImagePickerController+RACSignalSupport.h in Headers */, D037656F19EDA41200A782A9 /* RACDisposable.h in Headers */, 314304171ACA8B1E00595017 /* MKAnnotationView+RACSignalSupport.h in Headers */, D037654519EDA41200A782A9 /* NSURLConnection+RACSupport.h in Headers */, D037661D19EDA41200A782A9 /* UIAlertView+RACSignalSupport.h in Headers */, D037650D19EDA41200A782A9 /* NSNotificationCenter+RACSupport.h in Headers */, D037650119EDA41200A782A9 /* NSFileHandle+RACSupport.h in Headers */, D037666119EDA41200A782A9 /* UITextView+RACSignalSupport.h in Headers */, D037659B19EDA41200A782A9 /* RACKVOChannel.h in Headers */, D037652D19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.h in Headers */, D03764F919EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.h in Headers */, D037667219EDA57100A782A9 /* EXTScope.h in Headers */, D037663519EDA41200A782A9 /* UIDatePicker+RACSignalSupport.h in Headers */, D037667419EDA57100A782A9 /* metamacros.h in Headers */, D03764FD19EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.h in Headers */, D037652119EDA41200A782A9 /* NSObject+RACLifting.h in Headers */, D037665919EDA41200A782A9 /* UITableViewHeaderFooterView+RACSignalSupport.h in Headers */, D037656519EDA41200A782A9 /* RACCompoundDisposable.h in Headers */, D037653D19EDA41200A782A9 /* NSString+RACSupport.h in Headers */, D037662919EDA41200A782A9 /* UICollectionReusableView+RACSignalSupport.h in Headers */, D037660519EDA41200A782A9 /* RACTuple.h in Headers */, D037665519EDA41200A782A9 /* UITableViewCell+RACSignalSupport.h in Headers */, D03764F519EDA41200A782A9 /* NSData+RACSupport.h in Headers */, D037653919EDA41200A782A9 /* NSString+RACSequenceAdditions.h in Headers */, D037651519EDA41200A782A9 /* NSObject+RACDeallocating.h in Headers */, D037658F19EDA41200A782A9 /* RACGroupedSignal.h in Headers */, D03765C519EDA41200A782A9 /* RACScheduler+Subclass.h in Headers */, D03765E119EDA41200A782A9 /* RACStream.h in Headers */, D03765D719EDA41200A782A9 /* RACSignal+Operations.h in Headers */, D037665D19EDA41200A782A9 /* UITextField+RACSignalSupport.h in Headers */, D037664919EDA41200A782A9 /* UISlider+RACSignalSupport.h in Headers */, D03765BF19EDA41200A782A9 /* RACScheduler.h in Headers */, D43F27A11A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.h in Headers */, D03764E919EDA41200A782A9 /* NSArray+RACSequenceAdditions.h in Headers */, D037654919EDA41200A782A9 /* NSUserDefaults+RACSupport.h in Headers */, D037663919EDA41200A782A9 /* UIGestureRecognizer+RACSignalSupport.h in Headers */, D037653119EDA41200A782A9 /* NSSet+RACSequenceAdditions.h in Headers */, D03765CB19EDA41200A782A9 /* RACSequence.h in Headers */, D037662D19EDA41200A782A9 /* UIControl+RACSignalSupport.h in Headers */, D037666C19EDA57100A782A9 /* EXTKeyPathCoding.h in Headers */, D037658B19EDA41200A782A9 /* RACEvent.h in Headers */, D03765CF19EDA41200A782A9 /* RACSerialDisposable.h in Headers */, D037650519EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.h in Headers */, D037655D19EDA41200A782A9 /* RACChannel.h in Headers */, D03765B519EDA41200A782A9 /* RACQueueScheduler+Subclass.h in Headers */, D037665119EDA41200A782A9 /* UISwitch+RACSignalSupport.h in Headers */, D037664119EDA41200A782A9 /* UIRefreshControl+RACCommandSupport.h in Headers */, D037652919EDA41200A782A9 /* NSObject+RACSelectorSignal.h in Headers */, D03765D319EDA41200A782A9 /* RACSignal.h in Headers */, D03765F519EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.h in Headers */, D03765C719EDA41200A782A9 /* RACScopedDisposable.h in Headers */, A1046B7B1BFF5662004D8045 /* EXTRuntimeExtensions.h in Headers */, D037661119EDA41200A782A9 /* RACUnit.h in Headers */, D03765FD19EDA41200A782A9 /* RACTargetQueueScheduler.h in Headers */, D037661919EDA41200A782A9 /* UIActionSheet+RACSignalSupport.h in Headers */, D037664D19EDA41200A782A9 /* UIStepper+RACSignalSupport.h in Headers */, D037662119EDA41200A782A9 /* UIBarButtonItem+RACCommandSupport.h in Headers */, D03765EB19EDA41200A782A9 /* RACSubject.h in Headers */, D037656119EDA41200A782A9 /* RACCommand.h in Headers */, D03765EF19EDA41200A782A9 /* RACSubscriber.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 57A4D1AF1BA13D7A00F7D4B1 /* ReactiveCocoa-tvOS */ = { isa = PBXNativeTarget; buildConfigurationList = 57A4D23C1BA13D7A00F7D4B1 /* Build configuration list for PBXNativeTarget "ReactiveCocoa-tvOS" */; buildPhases = ( 57A4D1B01BA13D7A00F7D4B1 /* Sources */, 57A4D2071BA13D7A00F7D4B1 /* Frameworks */, 57A4D2091BA13D7A00F7D4B1 /* Headers */, 57A4D23B1BA13D7A00F7D4B1 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "ReactiveCocoa-tvOS"; productName = ReactiveCocoa; productReference = 57A4D2411BA13D7A00F7D4B1 /* ReactiveCocoa.framework */; productType = "com.apple.product-type.framework"; }; A9B315531B3940610001CB9C /* ReactiveCocoa-watchOS */ = { isa = PBXNativeTarget; buildConfigurationList = A9B3155D1B3940610001CB9C /* Build configuration list for PBXNativeTarget "ReactiveCocoa-watchOS" */; buildPhases = ( A9B3154F1B3940610001CB9C /* Sources */, A9B315501B3940610001CB9C /* Frameworks */, A9B315511B3940610001CB9C /* Headers */, A9B315521B3940610001CB9C /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "ReactiveCocoa-watchOS"; productName = ReactiveCocoa; productReference = A9B315541B3940610001CB9C /* ReactiveCocoa.framework */; productType = "com.apple.product-type.framework"; }; D04725E919E49ED7006002AA /* ReactiveCocoa-Mac */ = { isa = PBXNativeTarget; buildConfigurationList = D047260019E49ED7006002AA /* Build configuration list for PBXNativeTarget "ReactiveCocoa-Mac" */; buildPhases = ( D04725E519E49ED7006002AA /* Sources */, D04725E619E49ED7006002AA /* Frameworks */, D04725E719E49ED7006002AA /* Headers */, D04725E819E49ED7006002AA /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "ReactiveCocoa-Mac"; productName = ReactiveCocoa; productReference = D04725EA19E49ED7006002AA /* ReactiveCocoa.framework */; productType = "com.apple.product-type.framework"; }; D04725F419E49ED7006002AA /* ReactiveCocoa-MacTests */ = { isa = PBXNativeTarget; buildConfigurationList = D047260319E49ED7006002AA /* Build configuration list for PBXNativeTarget "ReactiveCocoa-MacTests" */; buildPhases = ( D04725F119E49ED7006002AA /* Sources */, D04725F219E49ED7006002AA /* Frameworks */, D04725F319E49ED7006002AA /* Resources */, ); buildRules = ( ); dependencies = ( D04725F819E49ED7006002AA /* PBXTargetDependency */, ); name = "ReactiveCocoa-MacTests"; productName = ReactiveCocoaTests; productReference = D04725F519E49ED7006002AA /* ReactiveCocoaTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; D047260B19E49F82006002AA /* ReactiveCocoa-iOS */ = { isa = PBXNativeTarget; buildConfigurationList = D047261F19E49F82006002AA /* Build configuration list for PBXNativeTarget "ReactiveCocoa-iOS" */; buildPhases = ( D047260719E49F82006002AA /* Sources */, D047260819E49F82006002AA /* Frameworks */, D047260919E49F82006002AA /* Headers */, D047260A19E49F82006002AA /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "ReactiveCocoa-iOS"; productName = ReactiveCocoa; productReference = D047260C19E49F82006002AA /* ReactiveCocoa.framework */; productType = "com.apple.product-type.framework"; }; D047261519E49F82006002AA /* ReactiveCocoa-iOSTests */ = { isa = PBXNativeTarget; buildConfigurationList = D047262219E49F82006002AA /* Build configuration list for PBXNativeTarget "ReactiveCocoa-iOSTests" */; buildPhases = ( D047261219E49F82006002AA /* Sources */, D047261319E49F82006002AA /* Frameworks */, D047261419E49F82006002AA /* Resources */, D01B7B6119EDD8F600D26E01 /* Copy Frameworks */, ); buildRules = ( ); dependencies = ( D047261919E49F82006002AA /* PBXTargetDependency */, ); name = "ReactiveCocoa-iOSTests"; productName = ReactiveCocoaTests; productReference = D047261619E49F82006002AA /* ReactiveCocoaTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ D04725E119E49ED7006002AA /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0700; LastUpgradeCheck = 0710; ORGANIZATIONNAME = GitHub; TargetAttributes = { A9B315531B3940610001CB9C = { CreatedOnToolsVersion = 7.0; }; D04725E919E49ED7006002AA = { CreatedOnToolsVersion = 6.1; }; D04725F419E49ED7006002AA = { CreatedOnToolsVersion = 6.1; }; D047260B19E49F82006002AA = { CreatedOnToolsVersion = 6.1; }; D047261519E49F82006002AA = { CreatedOnToolsVersion = 6.1; }; }; }; buildConfigurationList = D04725E419E49ED7006002AA /* Build configuration list for PBXProject "ReactiveCocoa" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = D04725E019E49ED7006002AA; productRefGroup = D04725EB19E49ED7006002AA /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( D04725E919E49ED7006002AA /* ReactiveCocoa-Mac */, D04725F419E49ED7006002AA /* ReactiveCocoa-MacTests */, D047260B19E49F82006002AA /* ReactiveCocoa-iOS */, D047261519E49F82006002AA /* ReactiveCocoa-iOSTests */, A9B315531B3940610001CB9C /* ReactiveCocoa-watchOS */, 57A4D1AF1BA13D7A00F7D4B1 /* ReactiveCocoa-tvOS */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 57A4D23B1BA13D7A00F7D4B1 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; A9B315521B3940610001CB9C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D04725E819E49ED7006002AA /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D04725F319E49ED7006002AA /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( D037671719EDA60000A782A9 /* test-data.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; D047260A19E49F82006002AA /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D047261419E49F82006002AA /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( D037671819EDA60000A782A9 /* test-data.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 57A4D1B01BA13D7A00F7D4B1 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 57A4D1B11BA13D7A00F7D4B1 /* Optional.swift in Sources */, 57D476951C4206EC00EFE697 /* UITableViewCell+RACSignalSupport.m in Sources */, 57A4D1B21BA13D7A00F7D4B1 /* RACCompoundDisposableProvider.d in Sources */, 57D476901C4206D400EFE697 /* UIControl+RACSignalSupportPrivate.m in Sources */, 57A4D1B31BA13D7A00F7D4B1 /* RACSignalProvider.d in Sources */, 57A4D1B41BA13D7A00F7D4B1 /* Disposable.swift in Sources */, 57A4D1B61BA13D7A00F7D4B1 /* Event.swift in Sources */, 57A4D1B71BA13D7A00F7D4B1 /* ObjectiveCBridging.swift in Sources */, 57A4D1B81BA13D7A00F7D4B1 /* Scheduler.swift in Sources */, 57A4D1B91BA13D7A00F7D4B1 /* Action.swift in Sources */, 57A4D1BA1BA13D7A00F7D4B1 /* Property.swift in Sources */, 57A4D1BB1BA13D7A00F7D4B1 /* Signal.swift in Sources */, 57A4D1BC1BA13D7A00F7D4B1 /* SignalProducer.swift in Sources */, 57A4D1BD1BA13D7A00F7D4B1 /* Atomic.swift in Sources */, 57A4D1BE1BA13D7A00F7D4B1 /* Bag.swift in Sources */, 57A4D1BF1BA13D7A00F7D4B1 /* TupleExtensions.swift in Sources */, 57A4D1C01BA13D7A00F7D4B1 /* FoundationExtensions.swift in Sources */, 57A4D1C11BA13D7A00F7D4B1 /* EXTRuntimeExtensions.m in Sources */, 57A4D1C21BA13D7A00F7D4B1 /* NSArray+RACSequenceAdditions.m in Sources */, 57A4D1C31BA13D7A00F7D4B1 /* NSData+RACSupport.m in Sources */, 57A4D1C41BA13D7A00F7D4B1 /* NSDictionary+RACSequenceAdditions.m in Sources */, 57A4D1C51BA13D7A00F7D4B1 /* NSEnumerator+RACSequenceAdditions.m in Sources */, D85C652D1C0E70E5005A77AD /* Flatten.swift in Sources */, 57D476961C4206EC00EFE697 /* UITableViewHeaderFooterView+RACSignalSupport.m in Sources */, 57A4D1C61BA13D7A00F7D4B1 /* NSFileHandle+RACSupport.m in Sources */, 57A4D1C71BA13D7A00F7D4B1 /* NSIndexSet+RACSequenceAdditions.m in Sources */, 57A4D1C81BA13D7A00F7D4B1 /* NSInvocation+RACTypeParsing.m in Sources */, 57D4769B1C4206F200EFE697 /* UICollectionReusableView+RACSignalSupport.m in Sources */, 57A4D1C91BA13D7A00F7D4B1 /* NSNotificationCenter+RACSupport.m in Sources */, 57A4D1CA1BA13D7A00F7D4B1 /* NSObject+RACDeallocating.m in Sources */, 57A4D1CB1BA13D7A00F7D4B1 /* NSObject+RACDescription.m in Sources */, 57A4D1CC1BA13D7A00F7D4B1 /* NSObject+RACKVOWrapper.m in Sources */, 57A4D1CD1BA13D7A00F7D4B1 /* NSObject+RACLifting.m in Sources */, 57A4D1CE1BA13D7A00F7D4B1 /* NSObject+RACPropertySubscribing.m in Sources */, 57A4D1CF1BA13D7A00F7D4B1 /* NSObject+RACSelectorSignal.m in Sources */, 57D476981C4206EC00EFE697 /* UITextView+RACSignalSupport.m in Sources */, 57A4D1D01BA13D7A00F7D4B1 /* NSOrderedSet+RACSequenceAdditions.m in Sources */, 57A4D1D11BA13D7A00F7D4B1 /* NSSet+RACSequenceAdditions.m in Sources */, 57D476911C4206DA00EFE697 /* UIGestureRecognizer+RACSignalSupport.m in Sources */, 57A4D1D21BA13D7A00F7D4B1 /* NSString+RACKeyPathUtilities.m in Sources */, 57D4769A1C4206F200EFE697 /* UIButton+RACCommandSupport.m in Sources */, 57A4D1D31BA13D7A00F7D4B1 /* NSString+RACSequenceAdditions.m in Sources */, 57A4D1D41BA13D7A00F7D4B1 /* NSString+RACSupport.m in Sources */, 57A4D1D61BA13D7A00F7D4B1 /* NSUserDefaults+RACSupport.m in Sources */, 57A4D1D71BA13D7A00F7D4B1 /* RACArraySequence.m in Sources */, 57A4D1D81BA13D7A00F7D4B1 /* RACBehaviorSubject.m in Sources */, 57A4D1D91BA13D7A00F7D4B1 /* RACBlockTrampoline.m in Sources */, 57A4D1DA1BA13D7A00F7D4B1 /* RACChannel.m in Sources */, 57A4D1DB1BA13D7A00F7D4B1 /* RACCommand.m in Sources */, 57A4D1DC1BA13D7A00F7D4B1 /* RACCompoundDisposable.m in Sources */, 57A4D1DD1BA13D7A00F7D4B1 /* RACDelegateProxy.m in Sources */, 57A4D1DE1BA13D7A00F7D4B1 /* RACDisposable.m in Sources */, EBCC7DBF1BBF01E200A2AE92 /* Observer.swift in Sources */, 57A4D1DF1BA13D7A00F7D4B1 /* RACDynamicSequence.m in Sources */, 57A4D1E01BA13D7A00F7D4B1 /* RACDynamicSignal.m in Sources */, 57A4D1E11BA13D7A00F7D4B1 /* RACEagerSequence.m in Sources */, 57D4768D1C42063C00EFE697 /* UIControl+RACSignalSupport.m in Sources */, 57A4D1E21BA13D7A00F7D4B1 /* RACEmptySequence.m in Sources */, 57A4D1E31BA13D7A00F7D4B1 /* RACEmptySignal.m in Sources */, 57A4D1E41BA13D7A00F7D4B1 /* RACErrorSignal.m in Sources */, 57A4D1E51BA13D7A00F7D4B1 /* RACEvent.m in Sources */, 57A4D1E61BA13D7A00F7D4B1 /* RACGroupedSignal.m in Sources */, 57A4D1E71BA13D7A00F7D4B1 /* RACImmediateScheduler.m in Sources */, 57D476971C4206EC00EFE697 /* UITextField+RACSignalSupport.m in Sources */, 57A4D1E81BA13D7A00F7D4B1 /* RACIndexSetSequence.m in Sources */, 57A4D1E91BA13D7A00F7D4B1 /* RACKVOChannel.m in Sources */, 57A4D1EA1BA13D7A00F7D4B1 /* RACKVOProxy.m in Sources */, 57A4D1EB1BA13D7A00F7D4B1 /* RACKVOTrampoline.m in Sources */, 57A4D1EC1BA13D7A00F7D4B1 /* RACMulticastConnection.m in Sources */, 57A4D1ED1BA13D7A00F7D4B1 /* RACObjCRuntime.m in Sources */, 57A4D1EE1BA13D7A00F7D4B1 /* RACPassthroughSubscriber.m in Sources */, 57A4D1EF1BA13D7A00F7D4B1 /* RACQueueScheduler.m in Sources */, 57A4D1F01BA13D7A00F7D4B1 /* RACReplaySubject.m in Sources */, 57A4D1F11BA13D7A00F7D4B1 /* RACReturnSignal.m in Sources */, 57A4D1F21BA13D7A00F7D4B1 /* RACScheduler.m in Sources */, 57A4D1F31BA13D7A00F7D4B1 /* RACScopedDisposable.m in Sources */, 57A4D1F41BA13D7A00F7D4B1 /* RACSequence.m in Sources */, 57A4D1F51BA13D7A00F7D4B1 /* RACSerialDisposable.m in Sources */, 57A4D1F61BA13D7A00F7D4B1 /* RACSignal.m in Sources */, 57D476921C4206DF00EFE697 /* UISegmentedControl+RACSignalSupport.m in Sources */, 57A4D1F71BA13D7A00F7D4B1 /* RACSignal+Operations.m in Sources */, 57A4D1F81BA13D7A00F7D4B1 /* RACSignalSequence.m in Sources */, 57A4D1F91BA13D7A00F7D4B1 /* RACStream.m in Sources */, 57A4D1FA1BA13D7A00F7D4B1 /* RACStringSequence.m in Sources */, 57A4D1FB1BA13D7A00F7D4B1 /* RACSubject.m in Sources */, 57A4D1FC1BA13D7A00F7D4B1 /* RACSubscriber.m in Sources */, 57A4D1FD1BA13D7A00F7D4B1 /* RACSubscriptingAssignmentTrampoline.m in Sources */, 57A4D1FE1BA13D7A00F7D4B1 /* RACSubscriptionScheduler.m in Sources */, 57A4D1FF1BA13D7A00F7D4B1 /* RACTargetQueueScheduler.m in Sources */, 57A4D2001BA13D7A00F7D4B1 /* RACTestScheduler.m in Sources */, 57A4D2011BA13D7A00F7D4B1 /* RACTuple.m in Sources */, 57A4D2021BA13D7A00F7D4B1 /* RACTupleSequence.m in Sources */, 57A4D2031BA13D7A00F7D4B1 /* RACUnarySequence.m in Sources */, 57A4D2041BA13D7A00F7D4B1 /* RACUnit.m in Sources */, 57A4D2051BA13D7A00F7D4B1 /* RACValueTransformer.m in Sources */, 57A4D2061BA13D7A00F7D4B1 /* RACDynamicPropertySuperclass.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; A9B3154F1B3940610001CB9C /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( A9F793341B60D0140026BCBA /* Optional.swift in Sources */, A9B316341B394C7F0001CB9C /* RACCompoundDisposableProvider.d in Sources */, A9B316351B394C7F0001CB9C /* RACSignalProvider.d in Sources */, A9B315BC1B3940810001CB9C /* Disposable.swift in Sources */, A9B315BE1B3940810001CB9C /* Event.swift in Sources */, A9B315BF1B3940810001CB9C /* ObjectiveCBridging.swift in Sources */, A9B315C01B3940810001CB9C /* Scheduler.swift in Sources */, A9B315C11B3940810001CB9C /* Action.swift in Sources */, A9B315C21B3940810001CB9C /* Property.swift in Sources */, A9B315C31B3940810001CB9C /* Signal.swift in Sources */, A9B315C41B3940810001CB9C /* SignalProducer.swift in Sources */, A9B315C51B3940810001CB9C /* Atomic.swift in Sources */, A9B315C61B3940810001CB9C /* Bag.swift in Sources */, A9B315C71B3940810001CB9C /* TupleExtensions.swift in Sources */, A9B315C81B3940810001CB9C /* FoundationExtensions.swift in Sources */, A9B3155E1B3940750001CB9C /* EXTRuntimeExtensions.m in Sources */, A9B315601B3940750001CB9C /* NSArray+RACSequenceAdditions.m in Sources */, A9B315631B3940750001CB9C /* NSData+RACSupport.m in Sources */, A9B315641B3940750001CB9C /* NSDictionary+RACSequenceAdditions.m in Sources */, A9B315651B3940750001CB9C /* NSEnumerator+RACSequenceAdditions.m in Sources */, D85C652C1C0E70E4005A77AD /* Flatten.swift in Sources */, A9B315661B3940750001CB9C /* NSFileHandle+RACSupport.m in Sources */, A9B315671B3940750001CB9C /* NSIndexSet+RACSequenceAdditions.m in Sources */, A9B315681B3940750001CB9C /* NSInvocation+RACTypeParsing.m in Sources */, A9B315691B3940750001CB9C /* NSNotificationCenter+RACSupport.m in Sources */, A9B3156B1B3940750001CB9C /* NSObject+RACDeallocating.m in Sources */, A9B3156C1B3940750001CB9C /* NSObject+RACDescription.m in Sources */, A9B3156D1B3940750001CB9C /* NSObject+RACKVOWrapper.m in Sources */, A9B3156E1B3940750001CB9C /* NSObject+RACLifting.m in Sources */, A9B3156F1B3940750001CB9C /* NSObject+RACPropertySubscribing.m in Sources */, A9B315701B3940750001CB9C /* NSObject+RACSelectorSignal.m in Sources */, A9B315711B3940750001CB9C /* NSOrderedSet+RACSequenceAdditions.m in Sources */, A9B315721B3940750001CB9C /* NSSet+RACSequenceAdditions.m in Sources */, A9B315731B3940750001CB9C /* NSString+RACKeyPathUtilities.m in Sources */, A9B315741B3940750001CB9C /* NSString+RACSequenceAdditions.m in Sources */, A9B315751B3940750001CB9C /* NSString+RACSupport.m in Sources */, A9B315781B3940750001CB9C /* NSUserDefaults+RACSupport.m in Sources */, A9B315791B3940750001CB9C /* RACArraySequence.m in Sources */, A9B3157A1B3940750001CB9C /* RACBehaviorSubject.m in Sources */, A9B3157B1B3940750001CB9C /* RACBlockTrampoline.m in Sources */, A9B3157C1B3940750001CB9C /* RACChannel.m in Sources */, A9B3157D1B3940750001CB9C /* RACCommand.m in Sources */, A9B3157E1B3940750001CB9C /* RACCompoundDisposable.m in Sources */, A9B3157F1B3940750001CB9C /* RACDelegateProxy.m in Sources */, A9B315801B3940750001CB9C /* RACDisposable.m in Sources */, EBCC7DBE1BBF01E200A2AE92 /* Observer.swift in Sources */, A9B315811B3940750001CB9C /* RACDynamicSequence.m in Sources */, A9B315821B3940750001CB9C /* RACDynamicSignal.m in Sources */, A9B315831B3940750001CB9C /* RACEagerSequence.m in Sources */, A9B315841B3940750001CB9C /* RACEmptySequence.m in Sources */, A9B315851B3940750001CB9C /* RACEmptySignal.m in Sources */, A9B315861B3940750001CB9C /* RACErrorSignal.m in Sources */, A9B315871B3940750001CB9C /* RACEvent.m in Sources */, A9B315881B3940750001CB9C /* RACGroupedSignal.m in Sources */, A9B315891B3940750001CB9C /* RACImmediateScheduler.m in Sources */, A9B3158A1B3940750001CB9C /* RACIndexSetSequence.m in Sources */, A9B3158B1B3940750001CB9C /* RACKVOChannel.m in Sources */, A9B3158C1B3940750001CB9C /* RACKVOProxy.m in Sources */, A9B3158D1B3940750001CB9C /* RACKVOTrampoline.m in Sources */, A9B3158E1B3940750001CB9C /* RACMulticastConnection.m in Sources */, A9B3158F1B3940750001CB9C /* RACObjCRuntime.m in Sources */, A9B315901B3940750001CB9C /* RACPassthroughSubscriber.m in Sources */, A9B315911B3940750001CB9C /* RACQueueScheduler.m in Sources */, A9B315921B3940750001CB9C /* RACReplaySubject.m in Sources */, A9B315931B3940750001CB9C /* RACReturnSignal.m in Sources */, A9B315941B3940750001CB9C /* RACScheduler.m in Sources */, A9B315951B3940750001CB9C /* RACScopedDisposable.m in Sources */, A9B315961B3940750001CB9C /* RACSequence.m in Sources */, A9B315971B3940750001CB9C /* RACSerialDisposable.m in Sources */, A9B315981B3940750001CB9C /* RACSignal.m in Sources */, A9B315991B3940750001CB9C /* RACSignal+Operations.m in Sources */, A9B3159A1B3940750001CB9C /* RACSignalSequence.m in Sources */, A9B3159B1B3940750001CB9C /* RACStream.m in Sources */, A9B3159C1B3940750001CB9C /* RACStringSequence.m in Sources */, A9B3159D1B3940750001CB9C /* RACSubject.m in Sources */, A9B3159E1B3940750001CB9C /* RACSubscriber.m in Sources */, A9B3159F1B3940750001CB9C /* RACSubscriptingAssignmentTrampoline.m in Sources */, A9B315A01B3940750001CB9C /* RACSubscriptionScheduler.m in Sources */, A9B315A11B3940750001CB9C /* RACTargetQueueScheduler.m in Sources */, A9B315A21B3940750001CB9C /* RACTestScheduler.m in Sources */, A9B315A31B3940750001CB9C /* RACTuple.m in Sources */, A9B315A41B3940750001CB9C /* RACTupleSequence.m in Sources */, A9B315A51B3940750001CB9C /* RACUnarySequence.m in Sources */, A9B315A61B3940750001CB9C /* RACUnit.m in Sources */, A9B315A71B3940750001CB9C /* RACValueTransformer.m in Sources */, A9B315BB1B3940750001CB9C /* RACDynamicPropertySuperclass.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D04725E519E49ED7006002AA /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D037654219EDA41200A782A9 /* NSText+RACSignalSupport.m in Sources */, D037659C19EDA41200A782A9 /* RACKVOChannel.m in Sources */, D03765C819EDA41200A782A9 /* RACScopedDisposable.m in Sources */, D03764FE19EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.m in Sources */, D03764EA19EDA41200A782A9 /* NSArray+RACSequenceAdditions.m in Sources */, D00004091A46864E000E7D41 /* TupleExtensions.swift in Sources */, D03765C019EDA41200A782A9 /* RACScheduler.m in Sources */, D43F27A21A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.m in Sources */, D037659819EDA41200A782A9 /* RACIndexSetSequence.m in Sources */, D03765D819EDA41200A782A9 /* RACSignal+Operations.m in Sources */, D871D69F1B3B29A40070F16C /* Optional.swift in Sources */, D08C54B61A69A3DB00AD8286 /* Event.swift in Sources */, D03764F219EDA41200A782A9 /* NSControl+RACTextSignalSupport.m in Sources */, D037650219EDA41200A782A9 /* NSFileHandle+RACSupport.m in Sources */, D03765E219EDA41200A782A9 /* RACStream.m in Sources */, D037655619EDA41200A782A9 /* RACBehaviorSubject.m in Sources */, D037660219EDA41200A782A9 /* RACTestScheduler.m in Sources */, D03765B819EDA41200A782A9 /* RACReplaySubject.m in Sources */, D03765EC19EDA41200A782A9 /* RACSubject.m in Sources */, D03765D019EDA41200A782A9 /* RACSerialDisposable.m in Sources */, D0C312D319EF2A5800984962 /* Disposable.swift in Sources */, D037666F19EDA57100A782A9 /* EXTRuntimeExtensions.m in Sources */, D037653E19EDA41200A782A9 /* NSString+RACSupport.m in Sources */, D037653619EDA41200A782A9 /* NSString+RACKeyPathUtilities.m in Sources */, D03764FA19EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.m in Sources */, EBCC7DBC1BBF010C00A2AE92 /* Observer.swift in Sources */, D037656819EDA41200A782A9 /* RACCompoundDisposableProvider.d in Sources */, D03B4A3D19F4C39A009E02AC /* FoundationExtensions.swift in Sources */, D037653A19EDA41200A782A9 /* NSString+RACSequenceAdditions.m in Sources */, D03765E819EDA41200A782A9 /* RACStringSequence.m in Sources */, D03764EE19EDA41200A782A9 /* NSControl+RACCommandSupport.m in Sources */, D08C54B31A69A2AE00AD8286 /* Signal.swift in Sources */, D037660A19EDA41200A782A9 /* RACTupleSequence.m in Sources */, D03765D419EDA41200A782A9 /* RACSignal.m in Sources */, D037651A19EDA41200A782A9 /* NSObject+RACDescription.m in Sources */, D03765A419EDA41200A782A9 /* RACMulticastConnection.m in Sources */, D037654E19EDA41200A782A9 /* RACArraySequence.m in Sources */, D037652219EDA41200A782A9 /* NSObject+RACLifting.m in Sources */, D037650619EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.m in Sources */, D037650E19EDA41200A782A9 /* NSNotificationCenter+RACSupport.m in Sources */, D03765FA19EDA41200A782A9 /* RACSubscriptionScheduler.m in Sources */, D85C652A1C0D84C7005A77AD /* Flatten.swift in Sources */, D0C312CF19EF2A5800984962 /* Bag.swift in Sources */, D037658019EDA41200A782A9 /* RACEmptySequence.m in Sources */, D03765AA19EDA41200A782A9 /* RACObjCRuntime.m in Sources */, D037654A19EDA41200A782A9 /* NSUserDefaults+RACSupport.m in Sources */, D037660E19EDA41200A782A9 /* RACUnarySequence.m in Sources */, D03765FE19EDA41200A782A9 /* RACTargetQueueScheduler.m in Sources */, D03765DE19EDA41200A782A9 /* RACSignalSequence.m in Sources */, D037656C19EDA41200A782A9 /* RACDelegateProxy.m in Sources */, D037657419EDA41200A782A9 /* RACDynamicSequence.m in Sources */, D037657019EDA41200A782A9 /* RACDisposable.m in Sources */, D03765DA19EDA41200A782A9 /* RACSignalProvider.d in Sources */, D037653219EDA41200A782A9 /* NSSet+RACSequenceAdditions.m in Sources */, D037651219EDA41200A782A9 /* NSObject+RACAppKitBindings.m in Sources */, D037656619EDA41200A782A9 /* RACCompoundDisposable.m in Sources */, D037655A19EDA41200A782A9 /* RACBlockTrampoline.m in Sources */, D0C312DF19EF2A5800984962 /* ObjectiveCBridging.swift in Sources */, D037659019EDA41200A782A9 /* RACGroupedSignal.m in Sources */, D037655E19EDA41200A782A9 /* RACChannel.m in Sources */, D037657C19EDA41200A782A9 /* RACEagerSequence.m in Sources */, D037657819EDA41200A782A9 /* RACDynamicSignal.m in Sources */, D037659419EDA41200A782A9 /* RACImmediateScheduler.m in Sources */, 7A7065811A3F88B8001E8354 /* RACKVOProxy.m in Sources */, D037651619EDA41200A782A9 /* NSObject+RACDeallocating.m in Sources */, D0C312E719EF2A5800984962 /* Scheduler.swift in Sources */, D0C312CD19EF2A5800984962 /* Atomic.swift in Sources */, D037658419EDA41200A782A9 /* RACEmptySignal.m in Sources */, D037654619EDA41200A782A9 /* NSURLConnection+RACSupport.m in Sources */, D03765F019EDA41200A782A9 /* RACSubscriber.m in Sources */, D03764F619EDA41200A782A9 /* NSData+RACSupport.m in Sources */, D037656219EDA41200A782A9 /* RACCommand.m in Sources */, D037658819EDA41200A782A9 /* RACErrorSignal.m in Sources */, D03765F619EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.m in Sources */, D08C54BA1A69C54300AD8286 /* Property.swift in Sources */, D0D11AB91A6AE87700C1F8B1 /* Action.swift in Sources */, D037661219EDA41200A782A9 /* RACUnit.m in Sources */, D03765A019EDA41200A782A9 /* RACKVOTrampoline.m in Sources */, D037650A19EDA41200A782A9 /* NSInvocation+RACTypeParsing.m in Sources */, D037660619EDA41200A782A9 /* RACTuple.m in Sources */, D037651E19EDA41200A782A9 /* NSObject+RACKVOWrapper.m in Sources */, D037661619EDA41200A782A9 /* RACValueTransformer.m in Sources */, D03765CC19EDA41200A782A9 /* RACSequence.m in Sources */, D037652E19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.m in Sources */, D037652619EDA41200A782A9 /* NSObject+RACPropertySubscribing.m in Sources */, D037658C19EDA41200A782A9 /* RACEvent.m in Sources */, D08C54B81A69A9D000AD8286 /* SignalProducer.swift in Sources */, D03765B219EDA41200A782A9 /* RACQueueScheduler.m in Sources */, D037652A19EDA41200A782A9 /* NSObject+RACSelectorSignal.m in Sources */, D03765AE19EDA41200A782A9 /* RACPassthroughSubscriber.m in Sources */, D03765BC19EDA41200A782A9 /* RACReturnSignal.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D04725F119E49ED7006002AA /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D0A2260E1A72F16D00D33B74 /* PropertySpec.swift in Sources */, D03766C719EDA60000A782A9 /* NSObjectRACPropertySubscribingExamples.m in Sources */, D03766E319EDA60000A782A9 /* RACDelegateProxySpec.m in Sources */, B696FB811A7640C00075236D /* TestError.swift in Sources */, D021671D1A6CD50500987861 /* ActionSpec.swift in Sources */, D03766F919EDA60000A782A9 /* RACSerialDisposableSpec.m in Sources */, D0C3131E19EF2D9700984962 /* RACTestExampleScheduler.m in Sources */, D037670B19EDA60000A782A9 /* RACTargetQueueSchedulerSpec.m in Sources */, D03766DD19EDA60000A782A9 /* RACCommandSpec.m in Sources */, D0C3130E19EF2B1F00984962 /* SchedulerSpec.swift in Sources */, D037670919EDA60000A782A9 /* RACSubscriptingAssignmentTrampolineSpec.m in Sources */, BFA6B94D1A7604D400C846D1 /* SignalProducerNimbleMatchers.swift in Sources */, D03766EB19EDA60000A782A9 /* RACKVOWrapperSpec.m in Sources */, D03766E719EDA60000A782A9 /* RACEventSpec.m in Sources */, D03766F719EDA60000A782A9 /* RACSequenceSpec.m in Sources */, D8170FC11B100EBC004192AD /* FoundationExtensionsSpec.swift in Sources */, D03766C919EDA60000A782A9 /* NSObjectRACPropertySubscribingSpec.m in Sources */, D03766C319EDA60000A782A9 /* NSObjectRACDeallocatingSpec.m in Sources */, D03766BD19EDA60000A782A9 /* NSEnumeratorRACSequenceAdditionsSpec.m in Sources */, CA6F28501C52626B001879D2 /* FlattenSpec.swift in Sources */, D037670119EDA60000A782A9 /* RACSubclassObject.m in Sources */, D03766CD19EDA60000A782A9 /* NSStringRACKeyPathUtilitiesSpec.m in Sources */, D037671519EDA60000A782A9 /* RACTupleSpec.m in Sources */, D03766C519EDA60000A782A9 /* NSObjectRACLiftingSpec.m in Sources */, D03766D119EDA60000A782A9 /* NSURLConnectionRACSupportSpec.m in Sources */, D03766F319EDA60000A782A9 /* RACSequenceAdditionsSpec.m in Sources */, D03766ED19EDA60000A782A9 /* RACMulticastConnectionSpec.m in Sources */, CDCD247A1C277EEC00710AEE /* AtomicSpec.swift in Sources */, D03766E919EDA60000A782A9 /* RACKVOChannelSpec.m in Sources */, D03766FB19EDA60000A782A9 /* RACSignalSpec.m in Sources */, 7A7065841A3F8967001E8354 /* RACKVOProxySpec.m in Sources */, 579504331BB8A34200A5E482 /* BagSpec.swift in Sources */, D037670719EDA60000A782A9 /* RACSubscriberSpec.m in Sources */, D03766EF19EDA60000A782A9 /* RACPropertySignalExamples.m in Sources */, D037670519EDA60000A782A9 /* RACSubscriberExamples.m in Sources */, D0A226081A72E0E900D33B74 /* SignalSpec.swift in Sources */, D0C3132219EF2D9700984962 /* RACTestSchedulerSpec.m in Sources */, 02D2602B1C1D6DB8003ACC61 /* SignalLifetimeSpec.swift in Sources */, D0C3130C19EF2B1F00984962 /* DisposableSpec.swift in Sources */, D03766D719EDA60000A782A9 /* RACBlockTrampolineSpec.m in Sources */, D0A2260B1A72E6C500D33B74 /* SignalProducerSpec.swift in Sources */, D03766FF19EDA60000A782A9 /* RACStreamExamples.m in Sources */, D03766CB19EDA60000A782A9 /* NSObjectRACSelectorSignalSpec.m in Sources */, D03766E119EDA60000A782A9 /* RACControlCommandExamples.m in Sources */, D03766BF19EDA60000A782A9 /* NSNotificationCenterRACSupportSpec.m in Sources */, D037670319EDA60000A782A9 /* RACSubjectSpec.m in Sources */, D03766F119EDA60000A782A9 /* RACSchedulerSpec.m in Sources */, D03766DF19EDA60000A782A9 /* RACCompoundDisposableSpec.m in Sources */, D03766E519EDA60000A782A9 /* RACDisposableSpec.m in Sources */, D0C3132019EF2D9700984962 /* RACTestObject.m in Sources */, D03766D319EDA60000A782A9 /* NSUserDefaultsRACSupportSpec.m in Sources */, D03766C119EDA60000A782A9 /* NSObjectRACAppKitBindingsSpec.m in Sources */, D03766DB19EDA60000A782A9 /* RACChannelSpec.m in Sources */, D0A226111A72F30B00D33B74 /* ObjectiveCBridgingSpec.swift in Sources */, D03766D919EDA60000A782A9 /* RACChannelExamples.m in Sources */, D03766F519EDA60000A782A9 /* RACSequenceExamples.m in Sources */, D8024DB21B2E1BB0005E6B9A /* SignalProducerLiftingSpec.swift in Sources */, D03766B919EDA60000A782A9 /* NSControllerRACSupportSpec.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D047260719E49F82006002AA /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D037659D19EDA41200A782A9 /* RACKVOChannel.m in Sources */, D08C54B41A69A2AF00AD8286 /* Signal.swift in Sources */, D037666319EDA41200A782A9 /* UITextView+RACSignalSupport.m in Sources */, D037662F19EDA41200A782A9 /* UIControl+RACSignalSupport.m in Sources */, D03765C919EDA41200A782A9 /* RACScopedDisposable.m in Sources */, D03764FF19EDA41200A782A9 /* NSEnumerator+RACSequenceAdditions.m in Sources */, D037664719EDA41200A782A9 /* UISegmentedControl+RACSignalSupport.m in Sources */, D43F27A31A9F7E8A00C1AD76 /* RACDynamicPropertySuperclass.m in Sources */, D8E84A671B3B32FB00C3E831 /* Optional.swift in Sources */, D03764EB19EDA41200A782A9 /* NSArray+RACSequenceAdditions.m in Sources */, D0C312D419EF2A5800984962 /* Disposable.swift in Sources */, D03765C119EDA41200A782A9 /* RACScheduler.m in Sources */, D037662B19EDA41200A782A9 /* UICollectionReusableView+RACSignalSupport.m in Sources */, D037659919EDA41200A782A9 /* RACIndexSetSequence.m in Sources */, D03765D919EDA41200A782A9 /* RACSignal+Operations.m in Sources */, D037661B19EDA41200A782A9 /* UIActionSheet+RACSignalSupport.m in Sources */, D037650319EDA41200A782A9 /* NSFileHandle+RACSupport.m in Sources */, D08C54B91A69A9D100AD8286 /* SignalProducer.swift in Sources */, D03765E319EDA41200A782A9 /* RACStream.m in Sources */, D037655719EDA41200A782A9 /* RACBehaviorSubject.m in Sources */, D037663B19EDA41200A782A9 /* UIGestureRecognizer+RACSignalSupport.m in Sources */, D037660319EDA41200A782A9 /* RACTestScheduler.m in Sources */, D03765B919EDA41200A782A9 /* RACReplaySubject.m in Sources */, D03765ED19EDA41200A782A9 /* RACSubject.m in Sources */, D037664F19EDA41200A782A9 /* UIStepper+RACSignalSupport.m in Sources */, D03765D119EDA41200A782A9 /* RACSerialDisposable.m in Sources */, EBCC7DBD1BBF01E100A2AE92 /* Observer.swift in Sources */, D037663F19EDA41200A782A9 /* UIImagePickerController+RACSignalSupport.m in Sources */, D037653F19EDA41200A782A9 /* NSString+RACSupport.m in Sources */, D037653719EDA41200A782A9 /* NSString+RACKeyPathUtilities.m in Sources */, D03764FB19EDA41200A782A9 /* NSDictionary+RACSequenceAdditions.m in Sources */, D037656919EDA41200A782A9 /* RACCompoundDisposableProvider.d in Sources */, D037653B19EDA41200A782A9 /* NSString+RACSequenceAdditions.m in Sources */, D037661F19EDA41200A782A9 /* UIAlertView+RACSignalSupport.m in Sources */, D03765E919EDA41200A782A9 /* RACStringSequence.m in Sources */, D037660B19EDA41200A782A9 /* RACTupleSequence.m in Sources */, D03765D519EDA41200A782A9 /* RACSignal.m in Sources */, D037663319EDA41200A782A9 /* UIControl+RACSignalSupportPrivate.m in Sources */, D037664319EDA41200A782A9 /* UIRefreshControl+RACCommandSupport.m in Sources */, D037651B19EDA41200A782A9 /* NSObject+RACDescription.m in Sources */, D03765A519EDA41200A782A9 /* RACMulticastConnection.m in Sources */, D85C652B1C0E70E3005A77AD /* Flatten.swift in Sources */, D037654F19EDA41200A782A9 /* RACArraySequence.m in Sources */, D037652319EDA41200A782A9 /* NSObject+RACLifting.m in Sources */, D037650719EDA41200A782A9 /* NSIndexSet+RACSequenceAdditions.m in Sources */, D037665F19EDA41200A782A9 /* UITextField+RACSignalSupport.m in Sources */, D037650F19EDA41200A782A9 /* NSNotificationCenter+RACSupport.m in Sources */, D03765FB19EDA41200A782A9 /* RACSubscriptionScheduler.m in Sources */, D037658119EDA41200A782A9 /* RACEmptySequence.m in Sources */, D03765AB19EDA41200A782A9 /* RACObjCRuntime.m in Sources */, D0C312E019EF2A5800984962 /* ObjectiveCBridging.swift in Sources */, D037654B19EDA41200A782A9 /* NSUserDefaults+RACSupport.m in Sources */, D037660F19EDA41200A782A9 /* RACUnarySequence.m in Sources */, D08C54BB1A69C54400AD8286 /* Property.swift in Sources */, D03765FF19EDA41200A782A9 /* RACTargetQueueScheduler.m in Sources */, D03765DF19EDA41200A782A9 /* RACSignalSequence.m in Sources */, D037656D19EDA41200A782A9 /* RACDelegateProxy.m in Sources */, D03B4A3E19F4C39A009E02AC /* FoundationExtensions.swift in Sources */, D037657519EDA41200A782A9 /* RACDynamicSequence.m in Sources */, D037657119EDA41200A782A9 /* RACDisposable.m in Sources */, D000040A1A46864E000E7D41 /* TupleExtensions.swift in Sources */, D03765DB19EDA41200A782A9 /* RACSignalProvider.d in Sources */, D037653319EDA41200A782A9 /* NSSet+RACSequenceAdditions.m in Sources */, D037665319EDA41200A782A9 /* UISwitch+RACSignalSupport.m in Sources */, D037664B19EDA41200A782A9 /* UISlider+RACSignalSupport.m in Sources */, D037656719EDA41200A782A9 /* RACCompoundDisposable.m in Sources */, D037655B19EDA41200A782A9 /* RACBlockTrampoline.m in Sources */, D037659119EDA41200A782A9 /* RACGroupedSignal.m in Sources */, D037655F19EDA41200A782A9 /* RACChannel.m in Sources */, D037657D19EDA41200A782A9 /* RACEagerSequence.m in Sources */, D037657919EDA41200A782A9 /* RACDynamicSignal.m in Sources */, D037659519EDA41200A782A9 /* RACImmediateScheduler.m in Sources */, D037651719EDA41200A782A9 /* NSObject+RACDeallocating.m in Sources */, D037658519EDA41200A782A9 /* RACEmptySignal.m in Sources */, D037663719EDA41200A782A9 /* UIDatePicker+RACSignalSupport.m in Sources */, D08C54B71A69A3DB00AD8286 /* Event.swift in Sources */, D037654719EDA41200A782A9 /* NSURLConnection+RACSupport.m in Sources */, D03765F119EDA41200A782A9 /* RACSubscriber.m in Sources */, D03764F719EDA41200A782A9 /* NSData+RACSupport.m in Sources */, D0C312CE19EF2A5800984962 /* Atomic.swift in Sources */, D0C312E819EF2A5800984962 /* Scheduler.swift in Sources */, D037656319EDA41200A782A9 /* RACCommand.m in Sources */, D037658919EDA41200A782A9 /* RACErrorSignal.m in Sources */, D03765F719EDA41200A782A9 /* RACSubscriptingAssignmentTrampoline.m in Sources */, D037661319EDA41200A782A9 /* RACUnit.m in Sources */, D037662319EDA41200A782A9 /* UIBarButtonItem+RACCommandSupport.m in Sources */, D03765A119EDA41200A782A9 /* RACKVOTrampoline.m in Sources */, D037665B19EDA41200A782A9 /* UITableViewHeaderFooterView+RACSignalSupport.m in Sources */, D0C312D019EF2A5800984962 /* Bag.swift in Sources */, D0D11ABA1A6AE87700C1F8B1 /* Action.swift in Sources */, D037650B19EDA41200A782A9 /* NSInvocation+RACTypeParsing.m in Sources */, D037660719EDA41200A782A9 /* RACTuple.m in Sources */, D037667019EDA57100A782A9 /* EXTRuntimeExtensions.m in Sources */, D037651F19EDA41200A782A9 /* NSObject+RACKVOWrapper.m in Sources */, D037661719EDA41200A782A9 /* RACValueTransformer.m in Sources */, D03765CD19EDA41200A782A9 /* RACSequence.m in Sources */, 314304181ACA8B1E00595017 /* MKAnnotationView+RACSignalSupport.m in Sources */, D037652F19EDA41200A782A9 /* NSOrderedSet+RACSequenceAdditions.m in Sources */, D037662719EDA41200A782A9 /* UIButton+RACCommandSupport.m in Sources */, D037652719EDA41200A782A9 /* NSObject+RACPropertySubscribing.m in Sources */, 7A7065821A3F88B8001E8354 /* RACKVOProxy.m in Sources */, D037658D19EDA41200A782A9 /* RACEvent.m in Sources */, D03765B319EDA41200A782A9 /* RACQueueScheduler.m in Sources */, D037665719EDA41200A782A9 /* UITableViewCell+RACSignalSupport.m in Sources */, D037652B19EDA41200A782A9 /* NSObject+RACSelectorSignal.m in Sources */, D03765AF19EDA41200A782A9 /* RACPassthroughSubscriber.m in Sources */, D03765BD19EDA41200A782A9 /* RACReturnSignal.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D047261219E49F82006002AA /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D0A2260C1A72E6C500D33B74 /* SignalProducerSpec.swift in Sources */, D03766C819EDA60000A782A9 /* NSObjectRACPropertySubscribingExamples.m in Sources */, D037672419EDA60000A782A9 /* UIImagePickerControllerRACSupportSpec.m in Sources */, D03766E419EDA60000A782A9 /* RACDelegateProxySpec.m in Sources */, D0A2260F1A72F16D00D33B74 /* PropertySpec.swift in Sources */, D03766FA19EDA60000A782A9 /* RACSerialDisposableSpec.m in Sources */, D0A226091A72E0E900D33B74 /* SignalSpec.swift in Sources */, CDCD247B1C277EED00710AEE /* AtomicSpec.swift in Sources */, D037670C19EDA60000A782A9 /* RACTargetQueueSchedulerSpec.m in Sources */, D03766DE19EDA60000A782A9 /* RACCommandSpec.m in Sources */, D037670A19EDA60000A782A9 /* RACSubscriptingAssignmentTrampolineSpec.m in Sources */, D03766EC19EDA60000A782A9 /* RACKVOWrapperSpec.m in Sources */, D021671E1A6CD50500987861 /* ActionSpec.swift in Sources */, D03766E819EDA60000A782A9 /* RACEventSpec.m in Sources */, D03766F819EDA60000A782A9 /* RACSequenceSpec.m in Sources */, D0A226121A72F30B00D33B74 /* ObjectiveCBridgingSpec.swift in Sources */, D037671E19EDA60000A782A9 /* UIBarButtonItemRACSupportSpec.m in Sources */, D8024DB31B2E1BB0005E6B9A /* SignalProducerLiftingSpec.swift in Sources */, BFA6B94E1A7604D500C846D1 /* SignalProducerNimbleMatchers.swift in Sources */, D03766CA19EDA60000A782A9 /* NSObjectRACPropertySubscribingSpec.m in Sources */, D0C3132319EF2D9700984962 /* RACTestSchedulerSpec.m in Sources */, D03766C419EDA60000A782A9 /* NSObjectRACDeallocatingSpec.m in Sources */, D03766BE19EDA60000A782A9 /* NSEnumeratorRACSequenceAdditionsSpec.m in Sources */, D037672019EDA60000A782A9 /* UIButtonRACSupportSpec.m in Sources */, D0C3132519EF2D9700984962 /* RACTestUIButton.m in Sources */, D037670219EDA60000A782A9 /* RACSubclassObject.m in Sources */, D03766CE19EDA60000A782A9 /* NSStringRACKeyPathUtilitiesSpec.m in Sources */, D037671619EDA60000A782A9 /* RACTupleSpec.m in Sources */, 7A7065851A3F8967001E8354 /* RACKVOProxySpec.m in Sources */, D03766C619EDA60000A782A9 /* NSObjectRACLiftingSpec.m in Sources */, B696FB821A7640C00075236D /* TestError.swift in Sources */, D0C3131F19EF2D9700984962 /* RACTestExampleScheduler.m in Sources */, D8170FC21B100EBC004192AD /* FoundationExtensionsSpec.swift in Sources */, D03766D219EDA60000A782A9 /* NSURLConnectionRACSupportSpec.m in Sources */, D03766F419EDA60000A782A9 /* RACSequenceAdditionsSpec.m in Sources */, D0C3131419EF2B2000984962 /* SchedulerSpec.swift in Sources */, D0C3131219EF2B2000984962 /* DisposableSpec.swift in Sources */, D03766EE19EDA60000A782A9 /* RACMulticastConnectionSpec.m in Sources */, D03766EA19EDA60000A782A9 /* RACKVOChannelSpec.m in Sources */, CA6F28511C52626B001879D2 /* FlattenSpec.swift in Sources */, D0C3132119EF2D9700984962 /* RACTestObject.m in Sources */, D03766FC19EDA60000A782A9 /* RACSignalSpec.m in Sources */, D037670819EDA60000A782A9 /* RACSubscriberSpec.m in Sources */, D037671C19EDA60000A782A9 /* UIAlertViewRACSupportSpec.m in Sources */, D03766F019EDA60000A782A9 /* RACPropertySignalExamples.m in Sources */, D037670619EDA60000A782A9 /* RACSubscriberExamples.m in Sources */, D03766D819EDA60000A782A9 /* RACBlockTrampolineSpec.m in Sources */, D037670019EDA60000A782A9 /* RACStreamExamples.m in Sources */, D03766CC19EDA60000A782A9 /* NSObjectRACSelectorSignalSpec.m in Sources */, D03766E219EDA60000A782A9 /* RACControlCommandExamples.m in Sources */, D03766C019EDA60000A782A9 /* NSNotificationCenterRACSupportSpec.m in Sources */, D037670419EDA60000A782A9 /* RACSubjectSpec.m in Sources */, D03766F219EDA60000A782A9 /* RACSchedulerSpec.m in Sources */, D03766E019EDA60000A782A9 /* RACCompoundDisposableSpec.m in Sources */, D03766E619EDA60000A782A9 /* RACDisposableSpec.m in Sources */, D03766D419EDA60000A782A9 /* NSUserDefaultsRACSupportSpec.m in Sources */, D03766DC19EDA60000A782A9 /* RACChannelSpec.m in Sources */, 579504341BB8A34300A5E482 /* BagSpec.swift in Sources */, D037671A19EDA60000A782A9 /* UIActionSheetRACSupportSpec.m in Sources */, D03766DA19EDA60000A782A9 /* RACChannelExamples.m in Sources */, D03766F619EDA60000A782A9 /* RACSequenceExamples.m in Sources */, 02D2602A1C1D6DAF003ACC61 /* SignalLifetimeSpec.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ D04725F819E49ED7006002AA /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D04725E919E49ED7006002AA /* ReactiveCocoa-Mac */; targetProxy = D04725F719E49ED7006002AA /* PBXContainerItemProxy */; }; D047261919E49F82006002AA /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D047260B19E49F82006002AA /* ReactiveCocoa-iOS */; targetProxy = D047261819E49F82006002AA /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 57A4D23D1BA13D7A00F7D4B1 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 57A4D2461BA13F9700F7D4B1 /* tvOS-Framework.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvsimulator*]" = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", "DTRACE_PROBES_DISABLED=1", ); INFOPLIST_FILE = ReactiveCocoa/Info.plist; TARGETED_DEVICE_FAMILY = 3; }; name = Debug; }; 57A4D23E1BA13D7A00F7D4B1 /* Test */ = { isa = XCBuildConfiguration; baseConfigurationReference = 57A4D2461BA13F9700F7D4B1 /* tvOS-Framework.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvsimulator*]" = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", "DTRACE_PROBES_DISABLED=1", ); INFOPLIST_FILE = ReactiveCocoa/Info.plist; TARGETED_DEVICE_FAMILY = 3; }; name = Test; }; 57A4D23F1BA13D7A00F7D4B1 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 57A4D2461BA13F9700F7D4B1 /* tvOS-Framework.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvsimulator*]" = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", "DTRACE_PROBES_DISABLED=1", ); INFOPLIST_FILE = ReactiveCocoa/Info.plist; TARGETED_DEVICE_FAMILY = 3; }; name = Release; }; 57A4D2401BA13D7A00F7D4B1 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 57A4D2461BA13F9700F7D4B1 /* tvOS-Framework.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvsimulator*]" = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", "DTRACE_PROBES_DISABLED=1", ); INFOPLIST_FILE = ReactiveCocoa/Info.plist; TARGETED_DEVICE_FAMILY = 3; }; name = Profile; }; A9B315591B3940610001CB9C /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = A97451351B3A935E00F48E55 /* watchOS-Framework.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=watchsimulator*]" = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", "DTRACE_PROBES_DISABLED=1", ); INFOPLIST_FILE = ReactiveCocoa/Info.plist; TARGETED_DEVICE_FAMILY = 4; }; name = Debug; }; A9B3155A1B3940610001CB9C /* Test */ = { isa = XCBuildConfiguration; baseConfigurationReference = A97451351B3A935E00F48E55 /* watchOS-Framework.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=watchsimulator*]" = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", "DTRACE_PROBES_DISABLED=1", ); INFOPLIST_FILE = ReactiveCocoa/Info.plist; TARGETED_DEVICE_FAMILY = 4; }; name = Test; }; A9B3155B1B3940610001CB9C /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = A97451351B3A935E00F48E55 /* watchOS-Framework.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=watchsimulator*]" = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", "DTRACE_PROBES_DISABLED=1", ); INFOPLIST_FILE = ReactiveCocoa/Info.plist; TARGETED_DEVICE_FAMILY = 4; }; name = Release; }; A9B3155C1B3940610001CB9C /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = A97451351B3A935E00F48E55 /* watchOS-Framework.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=watchsimulator*]" = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", "DTRACE_PROBES_DISABLED=1", ); INFOPLIST_FILE = ReactiveCocoa/Info.plist; TARGETED_DEVICE_FAMILY = 4; }; name = Profile; }; D04725FE19E49ED7006002AA /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047262919E49FE8006002AA /* Debug.xcconfig */; buildSettings = { BITCODE_GENERATION_MODE = bitcode; CURRENT_PROJECT_VERSION = 1; ENABLE_BITCODE = YES; ENABLE_TESTABILITY = YES; GCC_NO_COMMON_BLOCKS = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACOSX_DEPLOYMENT_TARGET = 10.9; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = "org.reactivecocoa.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(PROJECT_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; TVOS_DEPLOYMENT_TARGET = 9.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Debug; }; D04725FF19E49ED7006002AA /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047262B19E49FE8006002AA /* Release.xcconfig */; buildSettings = { BITCODE_GENERATION_MODE = bitcode; CURRENT_PROJECT_VERSION = 1; ENABLE_BITCODE = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACOSX_DEPLOYMENT_TARGET = 10.9; PRODUCT_BUNDLE_IDENTIFIER = "org.reactivecocoa.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(PROJECT_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; TVOS_DEPLOYMENT_TARGET = 9.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Release; }; D047260119E49ED7006002AA /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047263A19E49FE8006002AA /* Mac-Framework.xcconfig */; buildSettings = { DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; ENABLE_BITCODE = NO; FRAMEWORK_VERSION = A; INFOPLIST_FILE = ReactiveCocoa/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; USER_HEADER_SEARCH_PATHS = ReactiveCocoa/extobjc; }; name = Debug; }; D047260219E49ED7006002AA /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047263A19E49FE8006002AA /* Mac-Framework.xcconfig */; buildSettings = { DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; ENABLE_BITCODE = NO; FRAMEWORK_VERSION = A; INFOPLIST_FILE = ReactiveCocoa/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; USER_HEADER_SEARCH_PATHS = ReactiveCocoa/extobjc; }; name = Release; }; D047260419E49ED7006002AA /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047263719E49FE8006002AA /* Mac-Application.xcconfig */; buildSettings = { ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); INFOPLIST_FILE = ReactiveCocoaTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_NAME = "$(PROJECT_NAME)Tests"; }; name = Debug; }; D047260519E49ED7006002AA /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047263719E49FE8006002AA /* Mac-Application.xcconfig */; buildSettings = { ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); INFOPLIST_FILE = ReactiveCocoaTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_NAME = "$(PROJECT_NAME)Tests"; }; name = Release; }; D047262019E49F82006002AA /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047263419E49FE8006002AA /* iOS-Framework.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphonesimulator*]" = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; INFOPLIST_FILE = ReactiveCocoa/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; USER_HEADER_SEARCH_PATHS = ReactiveCocoa/extobjc; }; name = Debug; }; D047262119E49F82006002AA /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047263419E49FE8006002AA /* iOS-Framework.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphonesimulator*]" = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; INFOPLIST_FILE = ReactiveCocoa/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; USER_HEADER_SEARCH_PATHS = ReactiveCocoa/extobjc; }; name = Release; }; D047262319E49F82006002AA /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047263219E49FE8006002AA /* iOS-Application.xcconfig */; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); INFOPLIST_FILE = ReactiveCocoaTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(PROJECT_NAME)Tests"; }; name = Debug; }; D047262419E49F82006002AA /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047263219E49FE8006002AA /* iOS-Application.xcconfig */; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); INFOPLIST_FILE = ReactiveCocoaTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(PROJECT_NAME)Tests"; }; name = Release; }; D047263D19E4A008006002AA /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047262A19E49FE8006002AA /* Profile.xcconfig */; buildSettings = { BITCODE_GENERATION_MODE = bitcode; CURRENT_PROJECT_VERSION = 1; ENABLE_BITCODE = YES; GCC_NO_COMMON_BLOCKS = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACOSX_DEPLOYMENT_TARGET = 10.9; PRODUCT_BUNDLE_IDENTIFIER = "org.reactivecocoa.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(PROJECT_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; TVOS_DEPLOYMENT_TARGET = 9.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Profile; }; D047263E19E4A008006002AA /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047263A19E49FE8006002AA /* Mac-Framework.xcconfig */; buildSettings = { DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; ENABLE_BITCODE = NO; FRAMEWORK_VERSION = A; INFOPLIST_FILE = ReactiveCocoa/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; USER_HEADER_SEARCH_PATHS = ReactiveCocoa/extobjc; }; name = Profile; }; D047263F19E4A008006002AA /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047263719E49FE8006002AA /* Mac-Application.xcconfig */; buildSettings = { ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); INFOPLIST_FILE = ReactiveCocoaTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_NAME = "$(PROJECT_NAME)Tests"; }; name = Profile; }; D047264019E4A008006002AA /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047263419E49FE8006002AA /* iOS-Framework.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphonesimulator*]" = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; INFOPLIST_FILE = ReactiveCocoa/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; USER_HEADER_SEARCH_PATHS = ReactiveCocoa/extobjc; }; name = Profile; }; D047264119E4A008006002AA /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047263219E49FE8006002AA /* iOS-Application.xcconfig */; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); INFOPLIST_FILE = ReactiveCocoaTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(PROJECT_NAME)Tests"; }; name = Profile; }; D047264219E4A00B006002AA /* Test */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047262C19E49FE8006002AA /* Test.xcconfig */; buildSettings = { BITCODE_GENERATION_MODE = bitcode; CURRENT_PROJECT_VERSION = 1; ENABLE_BITCODE = YES; GCC_NO_COMMON_BLOCKS = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACOSX_DEPLOYMENT_TARGET = 10.9; PRODUCT_BUNDLE_IDENTIFIER = "org.reactivecocoa.$(PRODUCT_NAME:rfc1034identifier)-Tests"; PRODUCT_NAME = "$(PROJECT_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; TVOS_DEPLOYMENT_TARGET = 9.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Test; }; D047264319E4A00B006002AA /* Test */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047263A19E49FE8006002AA /* Mac-Framework.xcconfig */; buildSettings = { DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; ENABLE_BITCODE = NO; FRAMEWORK_VERSION = A; INFOPLIST_FILE = ReactiveCocoa/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; USER_HEADER_SEARCH_PATHS = ReactiveCocoa/extobjc; }; name = Test; }; D047264419E4A00B006002AA /* Test */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047263719E49FE8006002AA /* Mac-Application.xcconfig */; buildSettings = { ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); INFOPLIST_FILE = ReactiveCocoaTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_NAME = "$(PROJECT_NAME)Tests"; }; name = Test; }; D047264519E4A00B006002AA /* Test */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047263419E49FE8006002AA /* iOS-Framework.xcconfig */; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphonesimulator*]" = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; INFOPLIST_FILE = ReactiveCocoa/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; USER_HEADER_SEARCH_PATHS = ReactiveCocoa/extobjc; }; name = Test; }; D047264619E4A00B006002AA /* Test */ = { isa = XCBuildConfiguration; baseConfigurationReference = D047263219E49FE8006002AA /* iOS-Application.xcconfig */; buildSettings = { FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); INFOPLIST_FILE = ReactiveCocoaTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(PROJECT_NAME)Tests"; }; name = Test; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 57A4D23C1BA13D7A00F7D4B1 /* Build configuration list for PBXNativeTarget "ReactiveCocoa-tvOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 57A4D23D1BA13D7A00F7D4B1 /* Debug */, 57A4D23E1BA13D7A00F7D4B1 /* Test */, 57A4D23F1BA13D7A00F7D4B1 /* Release */, 57A4D2401BA13D7A00F7D4B1 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; A9B3155D1B3940610001CB9C /* Build configuration list for PBXNativeTarget "ReactiveCocoa-watchOS" */ = { isa = XCConfigurationList; buildConfigurations = ( A9B315591B3940610001CB9C /* Debug */, A9B3155A1B3940610001CB9C /* Test */, A9B3155B1B3940610001CB9C /* Release */, A9B3155C1B3940610001CB9C /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D04725E419E49ED7006002AA /* Build configuration list for PBXProject "ReactiveCocoa" */ = { isa = XCConfigurationList; buildConfigurations = ( D04725FE19E49ED7006002AA /* Debug */, D047264219E4A00B006002AA /* Test */, D04725FF19E49ED7006002AA /* Release */, D047263D19E4A008006002AA /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D047260019E49ED7006002AA /* Build configuration list for PBXNativeTarget "ReactiveCocoa-Mac" */ = { isa = XCConfigurationList; buildConfigurations = ( D047260119E49ED7006002AA /* Debug */, D047264319E4A00B006002AA /* Test */, D047260219E49ED7006002AA /* Release */, D047263E19E4A008006002AA /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D047260319E49ED7006002AA /* Build configuration list for PBXNativeTarget "ReactiveCocoa-MacTests" */ = { isa = XCConfigurationList; buildConfigurations = ( D047260419E49ED7006002AA /* Debug */, D047264419E4A00B006002AA /* Test */, D047260519E49ED7006002AA /* Release */, D047263F19E4A008006002AA /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D047261F19E49F82006002AA /* Build configuration list for PBXNativeTarget "ReactiveCocoa-iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( D047262019E49F82006002AA /* Debug */, D047264519E4A00B006002AA /* Test */, D047262119E49F82006002AA /* Release */, D047264019E4A008006002AA /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D047262219E49F82006002AA /* Build configuration list for PBXNativeTarget "ReactiveCocoa-iOSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( D047262319E49F82006002AA /* Debug */, D047264619E4A00B006002AA /* Test */, D047262419E49F82006002AA /* Release */, D047264119E4A008006002AA /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = D04725E119E49ED7006002AA /* Project object */; } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa.xcodeproj/xcshareddata/xcschemes/ReactiveCocoa-Mac.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa.xcodeproj/xcshareddata/xcschemes/ReactiveCocoa-iOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa.xcodeproj/xcshareddata/xcschemes/ReactiveCocoa-tvOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoa.xcodeproj/xcshareddata/xcschemes/ReactiveCocoa-watchOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/NSControllerRACSupportSpec.m ================================================ // // NSControllerRACSupportSpec.m // ReactiveCocoa // // Created by Uri Baghin on 26/10/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import #import "RACKVOChannel.h" @interface RACTestController : NSController @property (nonatomic, strong) id object; @end @implementation RACTestController @end QuickSpecBegin(NSControllerRACSupportSpec) qck_it(@"RACKVOChannel should support NSController", ^{ RACTestController *a = [[RACTestController alloc] init]; RACTestController *b = [[RACTestController alloc] init]; RACChannelTo(a, object) = RACChannelTo(b, object); expect(a.object).to(beNil()); expect(b.object).to(beNil()); a.object = a; expect(a.object).to(equal(a)); expect(b.object).to(equal(a)); b.object = b; expect(a.object).to(equal(b)); expect(b.object).to(equal(b)); a.object = nil; expect(a.object).to(beNil()); expect(b.object).to(beNil()); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/NSEnumeratorRACSequenceAdditionsSpec.m ================================================ // // NSEnumeratorRACSequenceAdditionsSpec.m // ReactiveCocoa // // Created by Uri Baghin on 07/01/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "RACSequenceExamples.h" #import "NSEnumerator+RACSequenceAdditions.h" QuickSpecBegin(NSEnumeratorRACSequenceAdditionsSpec) qck_describe(@"-rac_sequence", ^{ NSArray *values = @[ @0, @1, @2, @3, @4 ]; qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: values.objectEnumerator.rac_sequence, RACSequenceExampleExpectedValues: values }; }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/NSNotificationCenterRACSupportSpec.m ================================================ // // NSNotificationCenterRACSupportSpec.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-12-07. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "NSNotificationCenter+RACSupport.h" #import "RACSignal.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "NSObject+RACDeallocating.h" static NSString * const TestNotification = @"TestNotification"; QuickSpecBegin(NSNotificationCenterRACSupportSpec) __block NSNotificationCenter *notificationCenter; qck_beforeEach(^{ // The compiler gets confused and thinks you might be messaging // NSDistributedNotificationCenter otherwise. Wtf? notificationCenter = NSNotificationCenter.defaultCenter; }); qck_it(@"should send the notification when posted by any object", ^{ RACSignal *signal = [notificationCenter rac_addObserverForName:TestNotification object:nil]; __block NSUInteger count = 0; [signal subscribeNext:^(NSNotification *notification) { ++count; expect(notification).to(beAKindOf(NSNotification.class)); expect(notification.name).to(equal(TestNotification)); }]; expect(@(count)).to(equal(@0)); [notificationCenter postNotificationName:TestNotification object:nil]; expect(@(count)).to(equal(@1)); [notificationCenter postNotificationName:TestNotification object:self]; expect(@(count)).to(equal(@2)); }); qck_it(@"should send the notification when posted by a specific object", ^{ RACSignal *signal = [notificationCenter rac_addObserverForName:TestNotification object:self]; __block NSUInteger count = 0; [signal subscribeNext:^(NSNotification *notification) { ++count; expect(notification).to(beAKindOf(NSNotification.class)); expect(notification.name).to(equal(TestNotification)); expect(notification.object).to(beIdenticalTo(self)); }]; expect(@(count)).to(equal(@0)); [notificationCenter postNotificationName:TestNotification object:nil]; expect(@(count)).to(equal(@0)); [notificationCenter postNotificationName:TestNotification object:self]; expect(@(count)).to(equal(@1)); }); qck_it(@"shouldn't strongly capture the notification object", ^{ RACSignal *signal __attribute__((objc_precise_lifetime, unused)); __block BOOL dealloced = NO; @autoreleasepool { NSObject *notificationObject = [[NSObject alloc] init]; [notificationObject.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ dealloced = YES; }]]; signal = [notificationCenter rac_addObserverForName:TestNotification object:notificationObject]; } expect(@(dealloced)).to(beTruthy()); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/NSObjectRACAppKitBindingsSpec.m ================================================ // // NSObjectRACAppKitBindingsSpec.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-07-01. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "RACChannelExamples.h" #import #import "NSObject+RACAppKitBindings.h" QuickSpecBegin(NSObjectRACAppKitBindingsSpec) qck_itBehavesLike(RACViewChannelExamples, ^{ return @{ RACViewChannelExampleCreateViewBlock: ^{ return [[NSSlider alloc] initWithFrame:NSZeroRect]; }, RACViewChannelExampleCreateTerminalBlock: ^(NSSlider *view) { return [view rac_channelToBinding:NSValueBinding]; }, RACViewChannelExampleKeyPath: @keypath(NSSlider.new, objectValue), RACViewChannelExampleSetViewValueBlock: ^(NSSlider *view, NSNumber *value) { view.objectValue = value; // Bindings don't actually trigger from programmatic modification. Do it // manually. NSDictionary *bindingInfo = [view infoForBinding:NSValueBinding]; [bindingInfo[NSObservedObjectKey] setValue:value forKeyPath:bindingInfo[NSObservedKeyPathKey]]; } }; }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/NSObjectRACDeallocatingSpec.m ================================================ // // NSObject+RACDeallocating.m // ReactiveCocoa // // Created by Kazuo Koga on 2013/03/15. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "RACTestObject.h" #import "NSObject+RACDeallocating.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACSignal+Operations.h" #import @interface RACDeallocSwizzlingTestClass : NSObject @end @implementation RACDeallocSwizzlingTestClass - (void)dealloc { // Provide an empty implementation just so we can swizzle it. } @end @interface RACDeallocSwizzlingTestSubclass : RACDeallocSwizzlingTestClass @end @implementation RACDeallocSwizzlingTestSubclass @end QuickSpecBegin(NSObjectRACDeallocatingSpec) qck_describe(@"-dealloc swizzling", ^{ SEL selector = NSSelectorFromString(@"dealloc"); qck_it(@"should not invoke superclass -dealloc method twice", ^{ __block NSUInteger superclassDeallocatedCount = 0; __block BOOL subclassDeallocated = NO; @autoreleasepool { RACDeallocSwizzlingTestSubclass *object __attribute__((objc_precise_lifetime)) = [[RACDeallocSwizzlingTestSubclass alloc] init]; Method oldDeallocMethod = class_getInstanceMethod(RACDeallocSwizzlingTestClass.class, selector); void (*oldDealloc)(id, SEL) = (__typeof__(oldDealloc))method_getImplementation(oldDeallocMethod); id newDealloc = ^(__unsafe_unretained id self) { superclassDeallocatedCount++; oldDealloc(self, selector); }; class_replaceMethod(RACDeallocSwizzlingTestClass.class, selector, imp_implementationWithBlock(newDealloc), method_getTypeEncoding(oldDeallocMethod)); [object.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ subclassDeallocated = YES; }]]; expect(@(subclassDeallocated)).to(beFalsy()); expect(@(superclassDeallocatedCount)).to(equal(@0)); } expect(@(subclassDeallocated)).to(beTruthy()); expect(@(superclassDeallocatedCount)).to(equal(@1)); }); qck_it(@"should invoke superclass -dealloc method swizzled in after the subclass", ^{ __block BOOL superclassDeallocated = NO; __block BOOL subclassDeallocated = NO; @autoreleasepool { RACDeallocSwizzlingTestSubclass *object __attribute__((objc_precise_lifetime)) = [[RACDeallocSwizzlingTestSubclass alloc] init]; [object.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ subclassDeallocated = YES; }]]; Method oldDeallocMethod = class_getInstanceMethod(RACDeallocSwizzlingTestClass.class, selector); void (*oldDealloc)(id, SEL) = (__typeof__(oldDealloc))method_getImplementation(oldDeallocMethod); id newDealloc = ^(__unsafe_unretained id self) { superclassDeallocated = YES; oldDealloc(self, selector); }; class_replaceMethod(RACDeallocSwizzlingTestClass.class, selector, imp_implementationWithBlock(newDealloc), method_getTypeEncoding(oldDeallocMethod)); expect(@(subclassDeallocated)).to(beFalsy()); expect(@(superclassDeallocated)).to(beFalsy()); } expect(@(subclassDeallocated)).to(beTruthy()); expect(@(superclassDeallocated)).to(beTruthy()); }); }); qck_describe(@"-rac_deallocDisposable", ^{ qck_it(@"should dispose of the disposable when it is dealloc'd", ^{ __block BOOL wasDisposed = NO; @autoreleasepool { NSObject *object __attribute__((objc_precise_lifetime)) = [[NSObject alloc] init]; [object.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ wasDisposed = YES; }]]; expect(@(wasDisposed)).to(beFalsy()); } expect(@(wasDisposed)).to(beTruthy()); }); qck_it(@"should be able to use the object during disposal", ^{ @autoreleasepool { RACTestObject *object __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init]; @autoreleasepool { object.objectValue = [@"foo" mutableCopy]; } __unsafe_unretained RACTestObject *weakObject = object; [object.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ expect(weakObject.objectValue).to(equal(@"foo")); }]]; } }); }); qck_describe(@"-rac_willDeallocSignal", ^{ qck_it(@"should complete on dealloc", ^{ __block BOOL completed = NO; @autoreleasepool { [[[[RACTestObject alloc] init] rac_willDeallocSignal] subscribeCompleted:^{ completed = YES; }]; } expect(@(completed)).to(beTruthy()); }); qck_it(@"should not send anything", ^{ __block BOOL valueReceived = NO; __block BOOL completed = NO; @autoreleasepool { [[[[RACTestObject alloc] init] rac_willDeallocSignal] subscribeNext:^(id x) { valueReceived = YES; } completed:^{ completed = YES; }]; } expect(@(valueReceived)).to(beFalsy()); expect(@(completed)).to(beTruthy()); }); qck_it(@"should complete upon subscription if already deallocated", ^{ __block BOOL deallocated = NO; RACSignal *signal; @autoreleasepool { RACTestObject *object = [[RACTestObject alloc] init]; signal = [object rac_willDeallocSignal]; [signal subscribeCompleted:^{ deallocated = YES; }]; } expect(@(deallocated)).to(beTruthy()); expect(@([signal waitUntilCompleted:NULL])).to(beTruthy()); }); qck_it(@"should complete before the object is invalid", ^{ __block NSString *objectValue; @autoreleasepool { RACTestObject *object __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init]; @autoreleasepool { object.objectValue = [@"foo" mutableCopy]; } __unsafe_unretained RACTestObject *weakObject = object; [[object rac_willDeallocSignal] subscribeCompleted:^{ objectValue = [weakObject.objectValue copy]; }]; } expect(objectValue).to(equal(@"foo")); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/NSObjectRACLiftingSpec.m ================================================ // // NSObjectRACLifting.m // ReactiveCocoa // // Created by Josh Abernathy on 10/2/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACTestObject.h" #import "NSObject+RACLifting.h" #import "NSObject+RACDeallocating.h" #import "NSObject+RACPropertySubscribing.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACSubject.h" #import "RACTuple.h" #import "RACUnit.h" QuickSpecBegin(NSObjectRACLiftingSpec) qck_describe(@"-rac_liftSelector:withSignals:", ^{ __block RACTestObject *object; qck_beforeEach(^{ object = [[RACTestObject alloc] init]; }); qck_it(@"should call the selector with the value of the signal", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(setObjectValue:) withSignals:subject, nil]; expect(object.objectValue).to(beNil()); [subject sendNext:@1]; expect(object.objectValue).to(equal(@1)); [subject sendNext:@42]; expect(object.objectValue).to(equal(@42)); }); }); qck_describe(@"-rac_liftSelector:withSignalsFromArray:", ^{ __block RACTestObject *object; qck_beforeEach(^{ object = [[RACTestObject alloc] init]; }); qck_it(@"should call the selector with the value of the signal", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(setObjectValue:) withSignalsFromArray:@[ subject ]]; expect(object.objectValue).to(beNil()); [subject sendNext:@1]; expect(object.objectValue).to(equal(@1)); [subject sendNext:@42]; expect(object.objectValue).to(equal(@42)); }); qck_it(@"should call the selector with the value of the signal unboxed", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(setIntegerValue:) withSignalsFromArray:@[ subject ]]; expect(@(object.integerValue)).to(equal(@0)); [subject sendNext:@1]; expect(@(object.integerValue)).to(equal(@1)); [subject sendNext:@42]; expect(@(object.integerValue)).to(equal(@42)); }); qck_it(@"should work with multiple arguments", ^{ RACSubject *objectValueSubject = [RACSubject subject]; RACSubject *integerValueSubject = [RACSubject subject]; [object rac_liftSelector:@selector(setObjectValue:andIntegerValue:) withSignalsFromArray:@[ objectValueSubject, integerValueSubject ]]; expect(@(object.hasInvokedSetObjectValueAndIntegerValue)).to(beFalsy()); expect(object.objectValue).to(beNil()); expect(@(object.integerValue)).to(equal(@0)); [objectValueSubject sendNext:@1]; expect(@(object.hasInvokedSetObjectValueAndIntegerValue)).to(beFalsy()); expect(object.objectValue).to(beNil()); expect(@(object.integerValue)).to(equal(@0)); [integerValueSubject sendNext:@42]; expect(@(object.hasInvokedSetObjectValueAndIntegerValue)).to(beTruthy()); expect(object.objectValue).to(equal(@1)); expect(@(object.integerValue)).to(equal(@42)); }); qck_it(@"should work with signals that immediately start with a value", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(setObjectValue:) withSignalsFromArray:@[ [subject startWith:@42] ]]; expect(object.objectValue).to(equal(@42)); [subject sendNext:@1]; expect(object.objectValue).to(equal(@1)); }); qck_it(@"should work with signals that send nil", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(setObjectValue:) withSignalsFromArray:@[ subject ]]; [subject sendNext:nil]; expect(object.objectValue).to(beNil()); [subject sendNext:RACTupleNil.tupleNil]; expect(object.objectValue).to(beNil()); }); qck_it(@"should work with integers", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(setIntegerValue:) withSignalsFromArray:@[ subject ]]; expect(@(object.integerValue)).to(equal(@0)); [subject sendNext:@1]; expect(@(object.integerValue)).to(equal(@1)); }); qck_it(@"should convert between numeric types", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(setIntegerValue:) withSignalsFromArray:@[ subject ]]; expect(@(object.integerValue)).to(equal(@0)); [subject sendNext:@1.0]; expect(@(object.integerValue)).to(equal(@1)); }); qck_it(@"should work with class objects", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(setObjectValue:) withSignalsFromArray:@[ subject ]]; expect(object.objectValue).to(beNil()); [subject sendNext:self.class]; expect(object.objectValue).to(equal(self.class)); }); qck_it(@"should work for char pointer", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(setCharPointerValue:) withSignalsFromArray:@[ subject ]]; expect(@((size_t)object.charPointerValue)).to(equal(@0)); NSString *string = @"blah blah blah"; [subject sendNext:string]; expect(@(object.charPointerValue)).to(equal(string)); }); qck_it(@"should work for const char pointer", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(setConstCharPointerValue:) withSignalsFromArray:@[ subject ]]; expect(@((size_t)object.constCharPointerValue)).to(equal(@0)); NSString *string = @"blah blah blah"; [subject sendNext:string]; expect(@(object.constCharPointerValue)).to(equal(string)); }); qck_it(@"should work for CGRect", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(setRectValue:) withSignalsFromArray:@[ subject ]]; expect(@(CGRectEqualToRect(object.rectValue, CGRectZero))).to(beTruthy()); CGRect value = CGRectMake(10, 20, 30, 40); [subject sendNext:[NSValue valueWithBytes:&value objCType:@encode(CGRect)]]; expect(@(CGRectEqualToRect(object.rectValue, value))).to(beTruthy()); }); qck_it(@"should work for CGSize", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(setSizeValue:) withSignalsFromArray:@[ subject ]]; expect(@(CGSizeEqualToSize(object.sizeValue, CGSizeZero))).to(beTruthy()); CGSize value = CGSizeMake(10, 20); [subject sendNext:[NSValue valueWithBytes:&value objCType:@encode(CGSize)]]; expect(@(CGSizeEqualToSize(object.sizeValue, value))).to(beTruthy()); }); qck_it(@"should work for CGPoint", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(setPointValue:) withSignalsFromArray:@[ subject ]]; expect(@(CGPointEqualToPoint(object.pointValue, CGPointZero))).to(beTruthy()); CGPoint value = CGPointMake(10, 20); [subject sendNext:[NSValue valueWithBytes:&value objCType:@encode(CGPoint)]]; expect(@(CGPointEqualToPoint(object.pointValue, value))).to(beTruthy()); }); qck_it(@"should work for NSRange", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(setRangeValue:) withSignalsFromArray:@[ subject ]]; expect(@(NSEqualRanges(object.rangeValue, NSMakeRange(0, 0)))).to(beTruthy()); NSRange value = NSMakeRange(10, 20); [subject sendNext:[NSValue valueWithRange:value]]; expect(@(NSEqualRanges(object.rangeValue, value))).to(beTruthy()); }); qck_it(@"should work for _Bool", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(setC99BoolValue:) withSignalsFromArray:@[ subject ]]; expect(@(object.c99BoolValue)).to(beFalsy()); _Bool value = true; [subject sendNext:@(value)]; expect(@(object.c99BoolValue)).to(beTruthy()); }); qck_it(@"should work for primitive pointers", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(write5ToIntPointer:) withSignalsFromArray:@[ subject ]]; int value = 0; int *valuePointer = &value; expect(@(value)).to(equal(@0)); [subject sendNext:[NSValue valueWithPointer:valuePointer]]; expect(@(value)).to(equal(@5)); }); qck_it(@"should work for custom structs", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(setStructValue:) withSignalsFromArray:@[ subject ]]; expect(@(object.structValue.integerField)).to(equal(@0)); expect(@(object.structValue.doubleField)).to(equal(@0.0)); RACTestStruct value = (RACTestStruct){7, 1.23}; [subject sendNext:[NSValue valueWithBytes:&value objCType:@encode(typeof(value))]]; expect(@(object.structValue.integerField)).to(equal(@(value.integerField))); expect(@(object.structValue.doubleField)).to(equal(@(value.doubleField))); }); qck_it(@"should send the latest value of the signal as the right argument", ^{ RACSubject *subject = [RACSubject subject]; [object rac_liftSelector:@selector(setObjectValue:andIntegerValue:) withSignalsFromArray:@[ [RACSignal return:@"object"], subject ]]; [subject sendNext:@1]; expect(object.objectValue).to(equal(@"object")); expect(@(object.integerValue)).to(equal(@1)); }); qck_describe(@"the returned signal", ^{ qck_it(@"should send the return value of the method invocation", ^{ RACSubject *objectSubject = [RACSubject subject]; RACSubject *integerSubject = [RACSubject subject]; RACSignal *signal = [object rac_liftSelector:@selector(combineObjectValue:andIntegerValue:) withSignalsFromArray:@[ objectSubject, integerSubject ]]; __block NSString *result; [signal subscribeNext:^(id x) { result = x; }]; [objectSubject sendNext:@"Magic number"]; expect(result).to(beNil()); [integerSubject sendNext:@42]; expect(result).to(equal(@"Magic number: 42")); }); qck_it(@"should send RACUnit.defaultUnit for void-returning methods", ^{ RACSubject *subject = [RACSubject subject]; RACSignal *signal = [object rac_liftSelector:@selector(setObjectValue:) withSignalsFromArray:@[ subject ]]; __block id result; [signal subscribeNext:^(id x) { result = x; }]; [subject sendNext:@1]; expect(result).to(equal(RACUnit.defaultUnit)); }); qck_it(@"should support integer returning methods", ^{ RACSubject *subject = [RACSubject subject]; RACSignal *signal = [object rac_liftSelector:@selector(doubleInteger:) withSignalsFromArray:@[ subject ]]; __block id result; [signal subscribeNext:^(id x) { result = x; }]; [subject sendNext:@1]; expect(result).to(equal(@2)); }); qck_it(@"should support char * returning methods", ^{ RACSubject *subject = [RACSubject subject]; RACSignal *signal = [object rac_liftSelector:@selector(doubleString:) withSignalsFromArray:@[ subject ]]; __block id result; [signal subscribeNext:^(id x) { result = x; }]; [subject sendNext:@"test"]; expect(result).to(equal(@"testtest")); }); qck_it(@"should support const char * returning methods", ^{ RACSubject *subject = [RACSubject subject]; RACSignal *signal = [object rac_liftSelector:@selector(doubleConstString:) withSignalsFromArray:@[ subject ]]; __block id result; [signal subscribeNext:^(id x) { result = x; }]; [subject sendNext:@"test"]; expect(result).to(equal(@"testtest")); }); qck_it(@"should support struct returning methods", ^{ RACSubject *subject = [RACSubject subject]; RACSignal *signal = [object rac_liftSelector:@selector(doubleStruct:) withSignalsFromArray:@[ subject ]]; __block NSValue *boxedResult; [signal subscribeNext:^(id x) { boxedResult = x; }]; RACTestStruct value = {4, 12.3}; NSValue *boxedValue = [NSValue valueWithBytes:&value objCType:@encode(typeof(value))]; [subject sendNext:boxedValue]; RACTestStruct result = {0, 0.0}; [boxedResult getValue:&result]; expect(@(result.integerField)).to(equal(@8)); expect(@(result.doubleField)).to(equal(@24.6)); }); qck_it(@"should support block arguments and returns", ^{ RACSubject *subject = [RACSubject subject]; RACSignal *signal = [object rac_liftSelector:@selector(wrapBlock:) withSignalsFromArray:@[ subject ]]; __block BOOL blockInvoked = NO; dispatch_block_t testBlock = ^{ blockInvoked = YES; }; __block dispatch_block_t result; [signal subscribeNext:^(id x) { result = x; }]; [subject sendNext:testBlock]; expect(result).notTo(beNil()); result(); expect(@(blockInvoked)).to(beTruthy()); }); qck_it(@"should replay the last value", ^{ RACSubject *objectSubject = [RACSubject subject]; RACSubject *integerSubject = [RACSubject subject]; RACSignal *signal = [object rac_liftSelector:@selector(combineObjectValue:andIntegerValue:) withSignalsFromArray:@[ objectSubject, integerSubject ]]; [objectSubject sendNext:@"Magic number"]; [integerSubject sendNext:@42]; [integerSubject sendNext:@43]; __block NSString *result; [signal subscribeNext:^(id x) { result = x; }]; expect(result).to(equal(@"Magic number: 43")); }); }); qck_it(@"shouldn't strongly capture the receiver", ^{ __block BOOL dealloced = NO; @autoreleasepool { RACTestObject *testObject __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init]; [testObject.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ dealloced = YES; }]]; RACSubject *subject = [RACSubject subject]; [testObject rac_liftSelector:@selector(setObjectValue:) withSignalsFromArray:@[ subject ]]; [subject sendNext:@1]; } expect(@(dealloced)).to(beTruthy()); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/NSObjectRACPropertySubscribingExamples.h ================================================ // // NSObjectRACPropertySubscribingExamples.h // ReactiveCocoa // // Created by Josh Vera on 4/10/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // // The name of the shared examples for a signal-driven observation. extern NSString * const RACPropertySubscribingExamples; // The block should have the signature: // RACSignal * (^)(RACTestObject *testObject, NSString *keyPath, id observer) // and should observe the value of the key path on testObject with observer. The value // for this key should not be nil. extern NSString * const RACPropertySubscribingExamplesSetupBlock; ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/NSObjectRACPropertySubscribingExamples.m ================================================ // // NSObjectRACPropertySubscribingExamples.m // ReactiveCocoa // // Created by Josh Vera on 4/10/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "RACTestObject.h" #import "NSObjectRACPropertySubscribingExamples.h" #import #import "NSObject+RACDeallocating.h" #import "NSObject+RACPropertySubscribing.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACSignal.h" NSString * const RACPropertySubscribingExamples = @"RACPropertySubscribingExamples"; NSString * const RACPropertySubscribingExamplesSetupBlock = @"RACPropertySubscribingExamplesSetupBlock"; QuickConfigurationBegin(NSObjectRACPropertySubscribingExamples) + (void)configure:(Configuration *)configuration { sharedExamples(RACPropertySubscribingExamples, ^(QCKDSLSharedExampleContext exampleContext) { __block RACSignal *(^signalBlock)(RACTestObject *object, NSString *keyPath, id observer); qck_beforeEach(^{ signalBlock = exampleContext()[RACPropertySubscribingExamplesSetupBlock]; }); qck_it(@"should send the current value once on subscription", ^{ RACTestObject *object = [[RACTestObject alloc] init]; RACSignal *signal = signalBlock(object, @keypath(object, objectValue), self); NSMutableArray *values = [NSMutableArray array]; object.objectValue = @0; [signal subscribeNext:^(id x) { [values addObject:x]; }]; expect(values).to(equal((@[ @0 ]))); }); qck_it(@"should send the new value when it changes", ^{ RACTestObject *object = [[RACTestObject alloc] init]; RACSignal *signal = signalBlock(object, @keypath(object, objectValue), self); NSMutableArray *values = [NSMutableArray array]; object.objectValue = @0; [signal subscribeNext:^(id x) { [values addObject:x]; }]; expect(values).to(equal((@[ @0 ]))); object.objectValue = @1; expect(values).to(equal((@[ @0, @1 ]))); }); qck_it(@"should stop observing when disposed", ^{ RACTestObject *object = [[RACTestObject alloc] init]; RACSignal *signal = signalBlock(object, @keypath(object, objectValue), self); NSMutableArray *values = [NSMutableArray array]; object.objectValue = @0; RACDisposable *disposable = [signal subscribeNext:^(id x) { [values addObject:x]; }]; object.objectValue = @1; NSArray *expected = @[ @0, @1 ]; expect(values).to(equal(expected)); [disposable dispose]; object.objectValue = @2; expect(values).to(equal(expected)); }); qck_it(@"shouldn't send any more values after the observer is gone", ^{ __block BOOL observerDealloced = NO; RACTestObject *object = [[RACTestObject alloc] init]; NSMutableArray *values = [NSMutableArray array]; @autoreleasepool { RACTestObject *observer __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init]; [observer.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ observerDealloced = YES; }]]; RACSignal *signal = signalBlock(object, @keypath(object, objectValue), observer); object.objectValue = @1; [signal subscribeNext:^(id x) { [values addObject:x]; }]; } expect(@(observerDealloced)).to(beTruthy()); NSArray *expected = @[ @1 ]; expect(values).to(equal(expected)); object.objectValue = @2; expect(values).to(equal(expected)); }); qck_it(@"shouldn't keep either object alive unnaturally long", ^{ __block BOOL objectDealloced = NO; __block BOOL scopeObjectDealloced = NO; @autoreleasepool { RACTestObject *object __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init]; [object.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ objectDealloced = YES; }]]; RACTestObject *scopeObject __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init]; [scopeObject.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ scopeObjectDealloced = YES; }]]; RACSignal *signal = signalBlock(object, @keypath(object, objectValue), scopeObject); [signal subscribeNext:^(id _) { }]; } expect(@(objectDealloced)).to(beTruthy()); expect(@(scopeObjectDealloced)).to(beTruthy()); }); qck_it(@"shouldn't keep the signal alive past the lifetime of the object", ^{ __block BOOL objectDealloced = NO; __block BOOL signalDealloced = NO; @autoreleasepool { RACTestObject *object __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init]; [object.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ objectDealloced = YES; }]]; RACSignal *signal = [signalBlock(object, @keypath(object, objectValue), self) map:^(id value) { return value; }]; [signal.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ signalDealloced = YES; }]]; [signal subscribeNext:^(id _) { }]; } expect(@(signalDealloced)).toEventually(beTruthy()); expect(@(objectDealloced)).to(beTruthy()); }); qck_it(@"shouldn't crash when the value is changed on a different queue", ^{ __block id value; @autoreleasepool { RACTestObject *object __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init]; RACSignal *signal = signalBlock(object, @keypath(object, objectValue), self); [signal subscribeNext:^(id x) { value = x; }]; NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperationWithBlock:^{ object.objectValue = @1; }]; [queue waitUntilAllOperationsAreFinished]; } expect(value).toEventually(equal(@1)); }); qck_describe(@"mutating collections", ^{ __block RACTestObject *object; __block NSMutableOrderedSet *lastValue; __block NSMutableOrderedSet *proxySet; qck_beforeEach(^{ object = [[RACTestObject alloc] init]; object.objectValue = [NSMutableOrderedSet orderedSetWithObject:@1]; NSString *keyPath = @keypath(object, objectValue); [signalBlock(object, keyPath, self) subscribeNext:^(NSMutableOrderedSet *x) { lastValue = x; }]; proxySet = [object mutableOrderedSetValueForKey:keyPath]; }); qck_it(@"sends the newest object when inserting values into an observed object", ^{ NSMutableOrderedSet *expected = [NSMutableOrderedSet orderedSetWithObjects: @1, @2, nil]; [proxySet addObject:@2]; expect(lastValue).to(equal(expected)); }); qck_it(@"sends the newest object when removing values in an observed object", ^{ NSMutableOrderedSet *expected = [NSMutableOrderedSet orderedSet]; [proxySet removeAllObjects]; expect(lastValue).to(equal(expected)); }); qck_it(@"sends the newest object when replacing values in an observed object", ^{ NSMutableOrderedSet *expected = [NSMutableOrderedSet orderedSetWithObjects: @2, nil]; [proxySet replaceObjectAtIndex:0 withObject:@2]; expect(lastValue).to(equal(expected)); }); }); }); } QuickConfigurationEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/NSObjectRACPropertySubscribingSpec.m ================================================ // // NSObjectRACPropertySubscribingSpec.m // ReactiveCocoa // // Created by Josh Abernathy on 9/28/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "NSObjectRACPropertySubscribingExamples.h" #import "RACTestObject.h" #import "NSObject+RACPropertySubscribing.h" #import "RACDisposable.h" #import "RACSignal.h" QuickSpecBegin(NSObjectRACPropertySubscribingSpec) qck_describe(@"-rac_valuesForKeyPath:observer:", ^{ id (^setupBlock)(id, id, id) = ^(RACTestObject *object, NSString *keyPath, id observer) { return [object rac_valuesForKeyPath:keyPath observer:observer]; }; qck_itBehavesLike(RACPropertySubscribingExamples, ^{ return @{ RACPropertySubscribingExamplesSetupBlock: setupBlock }; }); }); qck_describe(@"+rac_signalWithChangesFor:keyPath:options:observer:", ^{ qck_describe(@"KVO options argument", ^{ __block RACTestObject *object; __block id actual; __block RACSignal *(^objectValueSignal)(NSKeyValueObservingOptions); qck_beforeEach(^{ object = [[RACTestObject alloc] init]; objectValueSignal = ^(NSKeyValueObservingOptions options) { return [[object rac_valuesAndChangesForKeyPath:@keypath(object, objectValue) options:options observer:self] reduceEach:^(id value, NSDictionary *change) { return change; }]; }; }); qck_it(@"sends a KVO dictionary", ^{ [objectValueSignal(0) subscribeNext:^(NSDictionary *x) { actual = x; }]; object.objectValue = @1; expect(actual).to(beAKindOf(NSDictionary.class)); }); qck_it(@"sends a kind key by default", ^{ [objectValueSignal(0) subscribeNext:^(NSDictionary *x) { actual = x[NSKeyValueChangeKindKey]; }]; object.objectValue = @1; expect(actual).notTo(beNil()); }); qck_it(@"sends the newest changes with NSKeyValueObservingOptionNew", ^{ [objectValueSignal(NSKeyValueObservingOptionNew) subscribeNext:^(NSDictionary *x) { actual = x[NSKeyValueChangeNewKey]; }]; object.objectValue = @1; expect(actual).to(equal(@1)); object.objectValue = @2; expect(actual).to(equal(@2)); }); qck_it(@"sends an additional change value with NSKeyValueObservingOptionPrior", ^{ NSMutableArray *values = [NSMutableArray new]; NSArray *expected = @[ @(YES), @(NO) ]; [objectValueSignal(NSKeyValueObservingOptionPrior) subscribeNext:^(NSDictionary *x) { BOOL isPrior = [x[NSKeyValueChangeNotificationIsPriorKey] boolValue]; [values addObject:@(isPrior)]; }]; object.objectValue = @[ @1 ]; expect(values).to(equal(expected)); }); qck_it(@"sends index changes when adding, inserting or removing a value from an observed object", ^{ __block NSUInteger hasIndexesCount = 0; [objectValueSignal(0) subscribeNext:^(NSDictionary *x) { if (x[NSKeyValueChangeIndexesKey] != nil) { hasIndexesCount += 1; } }]; object.objectValue = [NSMutableOrderedSet orderedSet]; expect(@(hasIndexesCount)).to(equal(@0)); NSMutableOrderedSet *objectValue = [object mutableOrderedSetValueForKey:@"objectValue"]; [objectValue addObject:@1]; expect(@(hasIndexesCount)).to(equal(@1)); [objectValue replaceObjectAtIndex:0 withObject:@2]; expect(@(hasIndexesCount)).to(equal(@2)); [objectValue removeObject:@2]; expect(@(hasIndexesCount)).to(equal(@3)); }); qck_it(@"sends the previous value with NSKeyValueObservingOptionOld", ^{ [objectValueSignal(NSKeyValueObservingOptionOld) subscribeNext:^(NSDictionary *x) { actual = x[NSKeyValueChangeOldKey]; }]; object.objectValue = @1; expect(actual).to(equal(NSNull.null)); object.objectValue = @2; expect(actual).to(equal(@1)); }); qck_it(@"sends the initial value with NSKeyValueObservingOptionInitial", ^{ [objectValueSignal(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) subscribeNext:^(NSDictionary *x) { actual = x[NSKeyValueChangeNewKey]; }]; expect(actual).to(equal(NSNull.null)); }); }); }); qck_describe(@"-rac_valuesAndChangesForKeyPath:options:observer:", ^{ qck_it(@"should complete immediately if the receiver or observer have deallocated", ^{ RACSignal *signal; @autoreleasepool { RACTestObject *object __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init]; RACTestObject *observer __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init]; signal = [object rac_valuesAndChangesForKeyPath:@keypath(object, stringValue) options:0 observer:observer]; } __block BOOL completed = NO; [signal subscribeCompleted:^{ completed = YES; }]; expect(@(completed)).to(beTruthy()); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/NSObjectRACSelectorSignalSpec.m ================================================ // // NSObjectRACSelectorSignalSpec.m // ReactiveCocoa // // Created by Josh Abernathy on 3/18/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "RACTestObject.h" #import "RACSubclassObject.h" #import "NSObject+RACDeallocating.h" #import "NSObject+RACPropertySubscribing.h" #import "NSObject+RACSelectorSignal.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACMulticastConnection.h" #import "RACSignal+Operations.h" #import "RACSignal.h" #import "RACTuple.h" @protocol TestProtocol @required - (BOOL)requiredMethod:(NSUInteger)number; - (void)lifeIsGood:(id)sender; @optional - (NSUInteger)optionalMethodWithObject:(id)object flag:(BOOL)flag; - (id)objectValue; @end QuickSpecBegin(NSObjectRACSelectorSignalSpec) qck_describe(@"RACTestObject", ^{ qck_it(@"should send the argument for each invocation", ^{ RACTestObject *object = [[RACTestObject alloc] init]; __block id value; [[object rac_signalForSelector:@selector(lifeIsGood:)] subscribeNext:^(RACTuple *x) { value = x.first; }]; [object lifeIsGood:@42]; expect(value).to(equal(@42)); }); qck_it(@"should send completed on deallocation", ^{ __block BOOL completed = NO; __block BOOL deallocated = NO; @autoreleasepool { RACTestObject *object __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init]; [object.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ deallocated = YES; }]]; [[object rac_signalForSelector:@selector(lifeIsGood:)] subscribeCompleted:^{ completed = YES; }]; expect(@(deallocated)).to(beFalsy()); expect(@(completed)).to(beFalsy()); } expect(@(deallocated)).to(beTruthy()); expect(@(completed)).to(beTruthy()); }); qck_it(@"should send for a zero-argument method", ^{ RACTestObject *object = [[RACTestObject alloc] init]; __block RACTuple *value; [[object rac_signalForSelector:@selector(objectValue)] subscribeNext:^(RACTuple *x) { value = x; }]; (void)[object objectValue]; expect(value).to(equal([RACTuple tupleWithObjectsFromArray:@[]])); }); qck_it(@"should send the argument for each invocation to the instance's own signal", ^{ RACTestObject *object1 = [[RACTestObject alloc] init]; __block id value1; [[object1 rac_signalForSelector:@selector(lifeIsGood:)] subscribeNext:^(RACTuple *x) { value1 = x.first; }]; RACTestObject *object2 = [[RACTestObject alloc] init]; __block id value2; [[object2 rac_signalForSelector:@selector(lifeIsGood:)] subscribeNext:^(RACTuple *x) { value2 = x.first; }]; [object1 lifeIsGood:@42]; [object2 lifeIsGood:@"Carpe diem"]; expect(value1).to(equal(@42)); expect(value2).to(equal(@"Carpe diem")); }); qck_it(@"should send multiple arguments for each invocation", ^{ RACTestObject *object = [[RACTestObject alloc] init]; __block id value1; __block id value2; [[object rac_signalForSelector:@selector(combineObjectValue:andSecondObjectValue:)] subscribeNext:^(RACTuple *x) { value1 = x.first; value2 = x.second; }]; expect([object combineObjectValue:@42 andSecondObjectValue:@"foo"]).to(equal(@"42: foo")); expect(value1).to(equal(@42)); expect(value2).to(equal(@"foo")); }); qck_it(@"should send arguments for invocation of non-existant methods", ^{ RACTestObject *object = [[RACTestObject alloc] init]; __block id key; __block id value; [[object rac_signalForSelector:@selector(setObject:forKey:)] subscribeNext:^(RACTuple *x) { value = x.first; key = x.second; }]; [object performSelector:@selector(setObject:forKey:) withObject:@YES withObject:@"Winner"]; expect(value).to(equal(@YES)); expect(key).to(equal(@"Winner")); }); qck_it(@"should send arguments for invocation and invoke the original method on previously KVO'd receiver", ^{ RACTestObject *object = [[RACTestObject alloc] init]; [[RACObserve(object, objectValue) publish] connect]; __block id key; __block id value; [[object rac_signalForSelector:@selector(setObjectValue:andSecondObjectValue:)] subscribeNext:^(RACTuple *x) { value = x.first; key = x.second; }]; [object setObjectValue:@YES andSecondObjectValue:@"Winner"]; expect(@(object.hasInvokedSetObjectValueAndSecondObjectValue)).to(beTruthy()); expect(object.objectValue).to(equal(@YES)); expect(object.secondObjectValue).to(equal(@"Winner")); expect(value).to(equal(@YES)); expect(key).to(equal(@"Winner")); }); qck_it(@"should send arguments for invocation and invoke the original method when receiver is subsequently KVO'd", ^{ RACTestObject *object = [[RACTestObject alloc] init]; __block id key; __block id value; [[object rac_signalForSelector:@selector(setObjectValue:andSecondObjectValue:)] subscribeNext:^(RACTuple *x) { value = x.first; key = x.second; }]; [[RACObserve(object, objectValue) publish] connect]; [object setObjectValue:@YES andSecondObjectValue:@"Winner"]; expect(@(object.hasInvokedSetObjectValueAndSecondObjectValue)).to(beTruthy()); expect(object.objectValue).to(equal(@YES)); expect(object.secondObjectValue).to(equal(@"Winner")); expect(value).to(equal(@YES)); expect(key).to(equal(@"Winner")); }); qck_it(@"should properly implement -respondsToSelector: when called on KVO'd receiver", ^{ RACTestObject *object = [[RACTestObject alloc] init]; // First, setup KVO on `object`, which gives us the desired side-effect // of `object` taking on a KVO-custom subclass. [[RACObserve(object, objectValue) publish] connect]; SEL selector = NSSelectorFromString(@"anyOldSelector:"); // With the KVO subclass in place, call -rac_signalForSelector: to // implement -anyOldSelector: directly on the KVO subclass. [object rac_signalForSelector:selector]; expect(@([object respondsToSelector:selector])).to(beTruthy()); }); qck_it(@"should properly implement -respondsToSelector: when called on signalForSelector'd receiver that has subsequently been KVO'd", ^{ RACTestObject *object = [[RACTestObject alloc] init]; SEL selector = NSSelectorFromString(@"anyOldSelector:"); // Implement -anyOldSelector: on the object first [object rac_signalForSelector:selector]; expect(@([object respondsToSelector:selector])).to(beTruthy()); // Then KVO the object [[RACObserve(object, objectValue) publish] connect]; expect(@([object respondsToSelector:selector])).to(beTruthy()); }); qck_it(@"should properly implement -respondsToSelector: when called on signalForSelector'd receiver that has subsequently been KVO'd, then signalForSelector'd again", ^{ RACTestObject *object = [[RACTestObject alloc] init]; SEL selector = NSSelectorFromString(@"anyOldSelector:"); // Implement -anyOldSelector: on the object first [object rac_signalForSelector:selector]; expect(@([object respondsToSelector:selector])).to(beTruthy()); // Then KVO the object [[RACObserve(object, objectValue) publish] connect]; expect(@([object respondsToSelector:selector])).to(beTruthy()); SEL selector2 = NSSelectorFromString(@"anotherSelector:"); // Then implement -anotherSelector: on the object [object rac_signalForSelector:selector2]; expect(@([object respondsToSelector:selector2])).to(beTruthy()); }); qck_it(@"should call the right signal for two instances of the same class, adding signals for the same selector", ^{ RACTestObject *object1 = [[RACTestObject alloc] init]; RACTestObject *object2 = [[RACTestObject alloc] init]; SEL selector = NSSelectorFromString(@"lifeIsGood:"); __block id value1 = nil; [[object1 rac_signalForSelector:selector] subscribeNext:^(RACTuple *x) { value1 = x.first; }]; __block id value2 = nil; [[object2 rac_signalForSelector:selector] subscribeNext:^(RACTuple *x) { value2 = x.first; }]; [object1 lifeIsGood:@42]; expect(value1).to(equal(@42)); expect(value2).to(beNil()); [object2 lifeIsGood:@420]; expect(value1).to(equal(@42)); expect(value2).to(equal(@420)); }); qck_it(@"should properly implement -respondsToSelector: for optional method from a protocol", ^{ // Selector for the targeted optional method from a protocol. SEL selector = @selector(optionalProtocolMethodWithObjectValue:); RACTestObject *object1 = [[RACTestObject alloc] init]; // Method implementation of the selector is added to its swizzled class. [object1 rac_signalForSelector:selector fromProtocol:@protocol(RACTestProtocol)]; expect(@([object1 respondsToSelector:selector])).to(beTruthy()); RACTestObject *object2 = [[RACTestObject alloc] init]; // Call -rac_signalForSelector: to swizzle this instance's class, // method implementations of -respondsToSelector: and // -forwardInvocation:. [object2 rac_signalForSelector:@selector(lifeIsGood:)]; // This instance should not respond to the selector because of not // calling -rac_signalForSelector: with the selector. expect(@([object2 respondsToSelector:selector])).to(beFalsy()); }); qck_it(@"should send non-object arguments", ^{ RACTestObject *object = [[RACTestObject alloc] init]; __block id value; [[object rac_signalForSelector:@selector(setIntegerValue:)] subscribeNext:^(RACTuple *x) { value = x.first; }]; object.integerValue = 42; expect(value).to(equal(@42)); }); qck_it(@"should send on signal after the original method is invoked", ^{ RACTestObject *object = [[RACTestObject alloc] init]; __block BOOL invokedMethodBefore = NO; [[object rac_signalForSelector:@selector(setObjectValue:andSecondObjectValue:)] subscribeNext:^(RACTuple *x) { invokedMethodBefore = object.hasInvokedSetObjectValueAndSecondObjectValue; }]; [object setObjectValue:@YES andSecondObjectValue:@"Winner"]; expect(@(invokedMethodBefore)).to(beTruthy()); }); }); qck_it(@"should swizzle an NSObject method", ^{ NSObject *object = [[NSObject alloc] init]; __block RACTuple *value; [[object rac_signalForSelector:@selector(description)] subscribeNext:^(RACTuple *x) { value = x; }]; expect([object description]).notTo(beNil()); expect(value).to(equal([RACTuple tupleWithObjectsFromArray:@[]])); }); qck_describe(@"a class that already overrides -forwardInvocation:", ^{ qck_it(@"should invoke the superclass' implementation", ^{ RACSubclassObject *object = [[RACSubclassObject alloc] init]; __block id value; [[object rac_signalForSelector:@selector(lifeIsGood:)] subscribeNext:^(RACTuple *x) { value = x.first; }]; [object lifeIsGood:@42]; expect(value).to(equal(@42)); expect(@((size_t)(void*)object.forwardedSelector)).to(equal(@0)); [object performSelector:@selector(allObjects)]; expect(value).to(equal(@42)); expect(NSStringFromSelector(object.forwardedSelector)).to(equal(@"allObjects")); }); qck_it(@"should not infinite recurse when KVO'd after RAC swizzled", ^{ RACSubclassObject *object = [[RACSubclassObject alloc] init]; __block id value; [[object rac_signalForSelector:@selector(lifeIsGood:)] subscribeNext:^(RACTuple *x) { value = x.first; }]; [[RACObserve(object, objectValue) publish] connect]; [object lifeIsGood:@42]; expect(value).to(equal(@42)); expect(@((size_t)(void*)object.forwardedSelector)).to(equal(@0)); [object performSelector:@selector(allObjects)]; expect(NSStringFromSelector(object.forwardedSelector)).to(equal(@"allObjects")); }); }); qck_describe(@"two classes in the same hierarchy", ^{ __block RACTestObject *superclassObj; __block RACTuple *superclassTuple; __block RACSubclassObject *subclassObj; __block RACTuple *subclassTuple; qck_beforeEach(^{ superclassObj = [[RACTestObject alloc] init]; expect(superclassObj).notTo(beNil()); subclassObj = [[RACSubclassObject alloc] init]; expect(subclassObj).notTo(beNil()); }); qck_it(@"should not collide", ^{ [[superclassObj rac_signalForSelector:@selector(combineObjectValue:andIntegerValue:)] subscribeNext:^(RACTuple *t) { superclassTuple = t; }]; [[subclassObj rac_signalForSelector:@selector(combineObjectValue:andIntegerValue:)] subscribeNext:^(RACTuple *t) { subclassTuple = t; }]; expect([superclassObj combineObjectValue:@"foo" andIntegerValue:42]).to(equal(@"foo: 42")); NSArray *expectedValues = @[ @"foo", @42 ]; expect(superclassTuple.allObjects).to(equal(expectedValues)); expect([subclassObj combineObjectValue:@"foo" andIntegerValue:42]).to(equal(@"fooSUBCLASS: 42")); expectedValues = @[ @"foo", @42 ]; expect(subclassTuple.allObjects).to(equal(expectedValues)); }); qck_it(@"should not collide when the superclass is invoked asynchronously", ^{ [[superclassObj rac_signalForSelector:@selector(setObjectValue:andSecondObjectValue:)] subscribeNext:^(RACTuple *t) { superclassTuple = t; }]; [[subclassObj rac_signalForSelector:@selector(setObjectValue:andSecondObjectValue:)] subscribeNext:^(RACTuple *t) { subclassTuple = t; }]; [superclassObj setObjectValue:@"foo" andSecondObjectValue:@"42"]; expect(@(superclassObj.hasInvokedSetObjectValueAndSecondObjectValue)).to(beTruthy()); NSArray *expectedValues = @[ @"foo", @"42" ]; expect(superclassTuple.allObjects).to(equal(expectedValues)); [subclassObj setObjectValue:@"foo" andSecondObjectValue:@"42"]; expect(@(subclassObj.hasInvokedSetObjectValueAndSecondObjectValue)).to(beFalsy()); expect(@(subclassObj.hasInvokedSetObjectValueAndSecondObjectValue)).toEventually(beTruthy()); expectedValues = @[ @"foo", @"42" ]; expect(subclassTuple.allObjects).to(equal(expectedValues)); }); }); qck_describe(@"-rac_signalForSelector:fromProtocol", ^{ __block RACTestObject *object; __block Protocol *protocol; qck_beforeEach(^{ object = (id)[[RACTestObject alloc] init]; expect(object).notTo(beNil()); protocol = @protocol(TestProtocol); expect(protocol).notTo(beNil()); }); qck_it(@"should not clobber a required method already implemented", ^{ __block id value; [[object rac_signalForSelector:@selector(lifeIsGood:) fromProtocol:protocol] subscribeNext:^(RACTuple *x) { value = x.first; }]; [object lifeIsGood:@42]; expect(value).to(equal(@42)); }); qck_it(@"should not clobber an optional method already implemented", ^{ object.objectValue = @"foo"; __block id value; [[object rac_signalForSelector:@selector(objectValue) fromProtocol:protocol] subscribeNext:^(RACTuple *x) { value = x; }]; expect([object objectValue]).to(equal(@"foo")); expect(value).to(equal([RACTuple tupleWithObjectsFromArray:@[]])); }); qck_it(@"should inject a required method", ^{ __block id value; [[object rac_signalForSelector:@selector(requiredMethod:) fromProtocol:protocol] subscribeNext:^(RACTuple *x) { value = x.first; }]; expect(@([object requiredMethod:42])).to(beFalsy()); expect(value).to(equal(@42)); }); qck_it(@"should inject an optional method", ^{ __block id value; [[object rac_signalForSelector:@selector(optionalMethodWithObject:flag:) fromProtocol:protocol] subscribeNext:^(RACTuple *x) { value = x; }]; expect(@([object optionalMethodWithObject:@"foo" flag:YES])).to(equal(@0)); expect(value).to(equal(RACTuplePack(@"foo", @YES))); }); }); qck_describe(@"class reporting", ^{ __block RACTestObject *object; __block Class originalClass; qck_beforeEach(^{ object = [[RACTestObject alloc] init]; originalClass = object.class; }); qck_it(@"should report the original class", ^{ [object rac_signalForSelector:@selector(lifeIsGood:)]; expect(object.class).to(beIdenticalTo(originalClass)); }); qck_it(@"should report the original class when it's KVO'd after dynamically subclassing", ^{ [object rac_signalForSelector:@selector(lifeIsGood:)]; [[RACObserve(object, objectValue) publish] connect]; expect(object.class).to(beIdenticalTo(originalClass)); }); qck_it(@"should report the original class when it's KVO'd before dynamically subclassing", ^{ [[RACObserve(object, objectValue) publish] connect]; [object rac_signalForSelector:@selector(lifeIsGood:)]; expect(object.class).to(beIdenticalTo(originalClass)); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/NSStringRACKeyPathUtilitiesSpec.m ================================================ // // NSStringRACKeyPathUtilitiesSpec.m // ReactiveCocoa // // Created by Uri Baghin on 05/05/2013. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "NSString+RACKeyPathUtilities.h" QuickSpecBegin(NSStringRACKeyPathUtilitiesSpec) qck_describe(@"-keyPathComponents", ^{ qck_it(@"should return components in the key path", ^{ expect(@"self.test.key.path".rac_keyPathComponents).to(equal((@[@"self", @"test", @"key", @"path"]))); }); qck_it(@"should return nil if given an empty string", ^{ expect(@"".rac_keyPathComponents).to(beNil()); }); }); qck_describe(@"-keyPathByDeletingLastKeyPathComponent", ^{ qck_it(@"should return the parent key path", ^{ expect(@"grandparent.parent.child".rac_keyPathByDeletingLastKeyPathComponent).to(equal(@"grandparent.parent")); }); qck_it(@"should return nil if given an empty string", ^{ expect(@"".rac_keyPathByDeletingLastKeyPathComponent).to(beNil()); }); qck_it(@"should return nil if given a key path with only one component", ^{ expect(@"self".rac_keyPathByDeletingLastKeyPathComponent).to(beNil()); }); }); qck_describe(@"-keyPathByDeletingFirstKeyPathComponent", ^{ qck_it(@"should return the remaining key path", ^{ expect(@"first.second.third".rac_keyPathByDeletingFirstKeyPathComponent).to(equal(@"second.third")); }); qck_it(@"should return nil if given an empty string", ^{ expect(@"".rac_keyPathByDeletingFirstKeyPathComponent).to(beNil()); }); qck_it(@"should return nil if given a key path with only one component", ^{ expect(@"self".rac_keyPathByDeletingFirstKeyPathComponent).to(beNil()); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/NSURLConnectionRACSupportSpec.m ================================================ // // NSURLConnectionRACSupportSpec.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-10-01. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "NSURLConnection+RACSupport.h" #import "RACSignal+Operations.h" #import "RACTuple.h" QuickSpecBegin(NSURLConnectionRACSupportSpec) qck_it(@"should fetch a JSON file", ^{ NSURL *fileURL = [[NSBundle bundleForClass:self.class] URLForResource:@"test-data" withExtension:@"json"]; expect(fileURL).notTo(beNil()); NSURLRequest *request = [NSURLRequest requestWithURL:fileURL]; BOOL success = NO; NSError *error = nil; RACTuple *result = [[NSURLConnection rac_sendAsynchronousRequest:request] firstOrDefault:nil success:&success error:&error]; expect(@(success)).to(beTruthy()); expect(error).to(beNil()); expect(result).to(beAKindOf(RACTuple.class)); NSURLResponse *response = result.first; expect(response).to(beAKindOf(NSURLResponse.class)); NSData *data = result.second; expect(data).to(beAKindOf(NSData.class)); expect(data).to(equal([NSData dataWithContentsOfURL:fileURL])); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/NSUserDefaultsRACSupportSpec.m ================================================ // // NSUserDefaultsRACSupportSpec.m // ReactiveCocoa // // Created by Matt Diephouse on 12/19/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "NSUserDefaults+RACSupport.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACKVOChannel.h" #import "NSObject+RACDeallocating.h" #import "RACSignal+Operations.h" static NSString * const NSUserDefaultsRACSupportSpecStringDefault = @"NSUserDefaultsRACSupportSpecStringDefault"; static NSString * const NSUserDefaultsRACSupportSpecBoolDefault = @"NSUserDefaultsRACSupportSpecBoolDefault"; @interface TestObserver : NSObject @property (copy, atomic) NSString *string1; @property (copy, atomic) NSString *string2; @property (assign, atomic) BOOL bool1; @end @implementation TestObserver @end QuickSpecBegin(NSUserDefaultsRACSupportSpec) __block NSUserDefaults *defaults = nil; __block TestObserver *observer = nil; qck_beforeEach(^{ defaults = NSUserDefaults.standardUserDefaults; observer = [TestObserver new]; }); qck_afterEach(^{ [defaults removeObjectForKey:NSUserDefaultsRACSupportSpecStringDefault]; [defaults removeObjectForKey:NSUserDefaultsRACSupportSpecBoolDefault]; observer = nil; }); qck_it(@"should set defaults", ^{ RACChannelTo(observer, string1) = [defaults rac_channelTerminalForKey:NSUserDefaultsRACSupportSpecStringDefault]; RACChannelTo(observer, bool1, @NO) = [defaults rac_channelTerminalForKey:NSUserDefaultsRACSupportSpecBoolDefault]; observer.string1 = @"A string"; observer.bool1 = YES; expect([defaults objectForKey:NSUserDefaultsRACSupportSpecStringDefault]).toEventually(equal(@"A string")); expect([defaults objectForKey:NSUserDefaultsRACSupportSpecBoolDefault]).toEventually(equal(@YES)); }); qck_it(@"should read defaults", ^{ RACChannelTo(observer, string1) = [defaults rac_channelTerminalForKey:NSUserDefaultsRACSupportSpecStringDefault]; RACChannelTo(observer, bool1, @NO) = [defaults rac_channelTerminalForKey:NSUserDefaultsRACSupportSpecBoolDefault]; expect(observer.string1).to(beNil()); expect(@(observer.bool1)).to(equal(@NO)); [defaults setObject:@"Another string" forKey:NSUserDefaultsRACSupportSpecStringDefault]; [defaults setBool:YES forKey:NSUserDefaultsRACSupportSpecBoolDefault]; expect(observer.string1).to(equal(@"Another string")); expect(@(observer.bool1)).to(equal(@YES)); }); qck_it(@"should be okay to create 2 terminals", ^{ RACChannelTo(observer, string1) = [defaults rac_channelTerminalForKey:NSUserDefaultsRACSupportSpecStringDefault]; RACChannelTo(observer, string2) = [defaults rac_channelTerminalForKey:NSUserDefaultsRACSupportSpecStringDefault]; [defaults setObject:@"String 3" forKey:NSUserDefaultsRACSupportSpecStringDefault]; expect(observer.string1).to(equal(@"String 3")); expect(observer.string2).to(equal(@"String 3")); }); qck_it(@"should handle removed defaults", ^{ observer.string1 = @"Some string"; observer.bool1 = YES; RACChannelTo(observer, string1) = [defaults rac_channelTerminalForKey:NSUserDefaultsRACSupportSpecStringDefault]; RACChannelTo(observer, bool1, @NO) = [defaults rac_channelTerminalForKey:NSUserDefaultsRACSupportSpecBoolDefault]; [defaults removeObjectForKey:NSUserDefaultsRACSupportSpecStringDefault]; [defaults removeObjectForKey:NSUserDefaultsRACSupportSpecBoolDefault]; expect(observer.string1).to(beNil()); expect(@(observer.bool1)).to(equal(@NO)); }); qck_it(@"shouldn't resend values", ^{ RACChannelTerminal *terminal = [defaults rac_channelTerminalForKey:NSUserDefaultsRACSupportSpecStringDefault]; RACChannelTo(observer, string1) = terminal; RACSignal *sentValue = [terminal replayLast]; observer.string1 = @"Test value"; id value = [sentValue asynchronousFirstOrDefault:nil success:NULL error:NULL]; expect(value).to(beNil()); }); qck_it(@"should complete when the NSUserDefaults deallocates", ^{ __block RACChannelTerminal *terminal; __block BOOL deallocated = NO; @autoreleasepool { NSUserDefaults *customDefaults __attribute__((objc_precise_lifetime)) = [NSUserDefaults new]; [customDefaults.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ deallocated = YES; }]]; terminal = [customDefaults rac_channelTerminalForKey:NSUserDefaultsRACSupportSpecStringDefault]; } expect(@(deallocated)).to(beTruthy()); expect(@([terminal asynchronouslyWaitUntilCompleted:NULL])).to(beTruthy()); }); qck_it(@"should send an initial value", ^{ [defaults setObject:@"Initial" forKey:NSUserDefaultsRACSupportSpecStringDefault]; RACChannelTerminal *terminal = [defaults rac_channelTerminalForKey:NSUserDefaultsRACSupportSpecStringDefault]; expect([terminal asynchronousFirstOrDefault:nil success:NULL error:NULL]).to(equal(@"Initial")); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACBlockTrampolineSpec.m ================================================ // // RACBlockTrampolineSpec.m // ReactiveCocoa // // Created by Josh Abernathy on 10/28/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACBlockTrampoline.h" #import "RACTuple.h" QuickSpecBegin(RACBlockTrampolineSpec) qck_it(@"should invoke the block with the given arguments", ^{ __block NSString *stringArg; __block NSNumber *numberArg; id (^block)(NSString *, NSNumber *) = ^ id (NSString *string, NSNumber *number) { stringArg = string; numberArg = number; return nil; }; [RACBlockTrampoline invokeBlock:block withArguments:RACTuplePack(@"hi", @1)]; expect(stringArg).to(equal(@"hi")); expect(numberArg).to(equal(@1)); }); qck_it(@"should return the result of the block invocation", ^{ NSString * (^block)(NSString *) = ^(NSString *string) { return string.uppercaseString; }; NSString *result = [RACBlockTrampoline invokeBlock:block withArguments:RACTuplePack(@"hi")]; expect(result).to(equal(@"HI")); }); qck_it(@"should pass RACTupleNils as nil", ^{ __block id arg; id (^block)(id) = ^ id (id obj) { arg = obj; return nil; }; [RACBlockTrampoline invokeBlock:block withArguments:RACTuplePack(nil)]; expect(arg).to(beNil()); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACChannelExamples.h ================================================ // // RACChannelExamples.h // ReactiveCocoa // // Created by Uri Baghin on 30/12/2012. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // // The name of the shared examples for RACChannel and its subclasses. extern NSString * const RACChannelExamples; // A block of type `RACChannel * (^)(void)`, which should return a new // RACChannel. extern NSString * const RACChannelExampleCreateBlock; // The name of the shared examples for any RACChannel class that gets and sets // a property. extern NSString * const RACViewChannelExamples; // A block of type `NSObject * (^)(void)`, which should create a new test view // and return it. extern NSString * const RACViewChannelExampleCreateViewBlock; // A block of type `RACChannelTerminal * (^)(NSObject *view)`, which should // create a new RACChannel to the given test view and return an terminal. extern NSString * const RACViewChannelExampleCreateTerminalBlock; // The key path that will be read/written in RACViewChannelExamples. This // must lead to an NSNumber or numeric primitive property. extern NSString * const RACViewChannelExampleKeyPath; // A block of type `void (^)(NSObject *view, NSNumber *value)`, which should // change the given test view's value to the given one. extern NSString * const RACViewChannelExampleSetViewValueBlock; ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACChannelExamples.m ================================================ // // RACChannelExamples.m // ReactiveCocoa // // Created by Uri Baghin on 30/12/2012. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACChannelExamples.h" #import "NSObject+RACDeallocating.h" #import "NSObject+RACPropertySubscribing.h" #import "RACChannel.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACSignal+Operations.h" NSString * const RACChannelExamples = @"RACChannelExamples"; NSString * const RACChannelExampleCreateBlock = @"RACChannelExampleCreateBlock"; NSString * const RACViewChannelExamples = @"RACViewChannelExamples"; NSString * const RACViewChannelExampleCreateViewBlock = @"RACViewChannelExampleCreateViewBlock"; NSString * const RACViewChannelExampleCreateTerminalBlock = @"RACViewChannelExampleCreateTerminalBlock"; NSString * const RACViewChannelExampleKeyPath = @"RACViewChannelExampleKeyPath"; NSString * const RACViewChannelExampleSetViewValueBlock = @"RACViewChannelExampleSetViewValueBlock"; QuickConfigurationBegin(RACChannelExampleGroups) + (void)configure:(Configuration *)configuration { sharedExamples(RACChannelExamples, ^(QCKDSLSharedExampleContext exampleContext) { __block RACChannel * (^getChannel)(void); __block RACChannel *channel; id value1 = @"test value 1"; id value2 = @"test value 2"; id value3 = @"test value 3"; NSArray *values = @[ value1, value2, value3 ]; qck_beforeEach(^{ getChannel = exampleContext()[RACChannelExampleCreateBlock]; channel = getChannel(); }); qck_it(@"should not send any leadingTerminal value on subscription", ^{ __block id receivedValue = nil; [channel.followingTerminal sendNext:value1]; [channel.leadingTerminal subscribeNext:^(id x) { receivedValue = x; }]; expect(receivedValue).to(beNil()); [channel.followingTerminal sendNext:value2]; expect(receivedValue).to(equal(value2)); }); qck_it(@"should send the latest followingTerminal value on subscription", ^{ __block id receivedValue = nil; [channel.leadingTerminal sendNext:value1]; [[channel.followingTerminal take:1] subscribeNext:^(id x) { receivedValue = x; }]; expect(receivedValue).to(equal(value1)); [channel.leadingTerminal sendNext:value2]; [[channel.followingTerminal take:1] subscribeNext:^(id x) { receivedValue = x; }]; expect(receivedValue).to(equal(value2)); }); qck_it(@"should send leadingTerminal values as they change", ^{ NSMutableArray *receivedValues = [NSMutableArray array]; [channel.leadingTerminal subscribeNext:^(id x) { [receivedValues addObject:x]; }]; [channel.followingTerminal sendNext:value1]; [channel.followingTerminal sendNext:value2]; [channel.followingTerminal sendNext:value3]; expect(receivedValues).to(equal(values)); }); qck_it(@"should send followingTerminal values as they change", ^{ [channel.leadingTerminal sendNext:value1]; NSMutableArray *receivedValues = [NSMutableArray array]; [channel.followingTerminal subscribeNext:^(id x) { [receivedValues addObject:x]; }]; [channel.leadingTerminal sendNext:value2]; [channel.leadingTerminal sendNext:value3]; expect(receivedValues).to(equal(values)); }); qck_it(@"should complete both signals when the leadingTerminal is completed", ^{ __block BOOL completedLeft = NO; [channel.leadingTerminal subscribeCompleted:^{ completedLeft = YES; }]; __block BOOL completedRight = NO; [channel.followingTerminal subscribeCompleted:^{ completedRight = YES; }]; [channel.leadingTerminal sendCompleted]; expect(@(completedLeft)).to(beTruthy()); expect(@(completedRight)).to(beTruthy()); }); qck_it(@"should complete both signals when the followingTerminal is completed", ^{ __block BOOL completedLeft = NO; [channel.leadingTerminal subscribeCompleted:^{ completedLeft = YES; }]; __block BOOL completedRight = NO; [channel.followingTerminal subscribeCompleted:^{ completedRight = YES; }]; [channel.followingTerminal sendCompleted]; expect(@(completedLeft)).to(beTruthy()); expect(@(completedRight)).to(beTruthy()); }); qck_it(@"should replay completion to new subscribers", ^{ [channel.leadingTerminal sendCompleted]; __block BOOL completedLeft = NO; [channel.leadingTerminal subscribeCompleted:^{ completedLeft = YES; }]; __block BOOL completedRight = NO; [channel.followingTerminal subscribeCompleted:^{ completedRight = YES; }]; expect(@(completedLeft)).to(beTruthy()); expect(@(completedRight)).to(beTruthy()); }); }); sharedExamples(RACViewChannelExamples, ^(QCKDSLSharedExampleContext exampleContext) { __block NSString *keyPath; __block NSObject * (^getView)(void); __block RACChannelTerminal * (^getTerminal)(NSObject *); __block void (^setViewValue)(NSObject *view, NSNumber *value); __block NSObject *testView; __block RACChannelTerminal *endpoint; qck_beforeEach(^{ keyPath = exampleContext()[RACViewChannelExampleKeyPath]; getTerminal = exampleContext()[RACViewChannelExampleCreateTerminalBlock]; getView = exampleContext()[RACViewChannelExampleCreateViewBlock]; setViewValue = exampleContext()[RACViewChannelExampleSetViewValueBlock]; testView = getView(); endpoint = getTerminal(testView); }); qck_it(@"should not send changes made by the channel itself", ^{ __block BOOL receivedNext = NO; [endpoint subscribeNext:^(id x) { receivedNext = YES; }]; expect(@(receivedNext)).to(beFalsy()); [endpoint sendNext:@0.1]; expect(@(receivedNext)).to(beFalsy()); [endpoint sendNext:@0.2]; expect(@(receivedNext)).to(beFalsy()); [endpoint sendCompleted]; expect(@(receivedNext)).to(beFalsy()); }); qck_it(@"should not send progammatic changes made to the view", ^{ __block BOOL receivedNext = NO; [endpoint subscribeNext:^(id x) { receivedNext = YES; }]; expect(@(receivedNext)).to(beFalsy()); [testView setValue:@0.1 forKeyPath:keyPath]; expect(@(receivedNext)).to(beFalsy()); [testView setValue:@0.2 forKeyPath:keyPath]; expect(@(receivedNext)).to(beFalsy()); }); qck_it(@"should not have a starting value", ^{ __block BOOL receivedNext = NO; [endpoint subscribeNext:^(id x) { receivedNext = YES; }]; expect(@(receivedNext)).to(beFalsy()); }); qck_it(@"should send view changes", ^{ __block NSString *received; [endpoint subscribeNext:^(id x) { received = x; }]; setViewValue(testView, @0.1); expect(received).to(equal(@0.1)); setViewValue(testView, @0.2); expect(received).to(equal(@0.2)); }); qck_it(@"should set values on the view", ^{ [endpoint sendNext:@0.1]; expect([testView valueForKeyPath:keyPath]).to(equal(@0.1)); [endpoint sendNext:@0.2]; expect([testView valueForKeyPath:keyPath]).to(equal(@0.2)); }); qck_it(@"should not echo changes back to the channel", ^{ __block NSUInteger receivedCount = 0; [endpoint subscribeNext:^(id _) { receivedCount++; }]; expect(@(receivedCount)).to(equal(@0)); [endpoint sendNext:@0.1]; expect(@(receivedCount)).to(equal(@0)); setViewValue(testView, @0.2); expect(@(receivedCount)).to(equal(@1)); }); qck_it(@"should complete when the view deallocates", ^{ __block BOOL deallocated = NO; __block BOOL completed = NO; @autoreleasepool { NSObject *view __attribute__((objc_precise_lifetime)) = getView(); [view.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ deallocated = YES; }]]; RACChannelTerminal *terminal = getTerminal(view); [terminal subscribeCompleted:^{ completed = YES; }]; expect(@(deallocated)).to(beFalsy()); expect(@(completed)).to(beFalsy()); } expect(@(deallocated)).to(beTruthy()); expect(@(completed)).to(beTruthy()); }); qck_it(@"should deallocate after the view deallocates", ^{ __block BOOL viewDeallocated = NO; __block BOOL terminalDeallocated = NO; @autoreleasepool { NSObject *view __attribute__((objc_precise_lifetime)) = getView(); [view.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ viewDeallocated = YES; }]]; RACChannelTerminal *terminal = getTerminal(view); [terminal.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ terminalDeallocated = YES; }]]; expect(@(viewDeallocated)).to(beFalsy()); expect(@(terminalDeallocated)).to(beFalsy()); } expect(@(viewDeallocated)).to(beTruthy()); expect(@(terminalDeallocated)).toEventually(beTruthy()); }); }); } QuickConfigurationEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACChannelSpec.m ================================================ // // RACChannelSpec.m // ReactiveCocoa // // Created by Uri Baghin on 30/12/2012. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACChannelExamples.h" #import "NSObject+RACDeallocating.h" #import "RACChannel.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACSignal.h" QuickSpecBegin(RACChannelSpec) qck_describe(@"RACChannel", ^{ qck_itBehavesLike(RACChannelExamples, ^{ return @{ RACChannelExampleCreateBlock: [^{ return [[RACChannel alloc] init]; } copy] }; }); qck_describe(@"memory management", ^{ qck_it(@"should dealloc when its subscribers are disposed", ^{ RACDisposable *leadingDisposable = nil; RACDisposable *followingDisposable = nil; __block BOOL deallocated = NO; @autoreleasepool { RACChannel *channel __attribute__((objc_precise_lifetime)) = [[RACChannel alloc] init]; [channel.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ deallocated = YES; }]]; leadingDisposable = [channel.leadingTerminal subscribeCompleted:^{}]; followingDisposable = [channel.followingTerminal subscribeCompleted:^{}]; } [leadingDisposable dispose]; [followingDisposable dispose]; expect(@(deallocated)).toEventually(beTruthy()); }); qck_it(@"should dealloc when its subscriptions are disposed", ^{ RACDisposable *leadingDisposable = nil; RACDisposable *followingDisposable = nil; __block BOOL deallocated = NO; @autoreleasepool { RACChannel *channel __attribute__((objc_precise_lifetime)) = [[RACChannel alloc] init]; [channel.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ deallocated = YES; }]]; leadingDisposable = [[RACSignal never] subscribe:channel.leadingTerminal]; followingDisposable = [[RACSignal never] subscribe:channel.followingTerminal]; } [leadingDisposable dispose]; [followingDisposable dispose]; expect(@(deallocated)).toEventually(beTruthy()); }); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACCommandSpec.m ================================================ // // RACCommandSpec.m // ReactiveCocoa // // Created by Josh Abernathy on 8/31/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "NSArray+RACSequenceAdditions.h" #import "NSObject+RACDeallocating.h" #import "NSObject+RACPropertySubscribing.h" #import "RACCommand.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACEvent.h" #import "RACScheduler.h" #import "RACSequence.h" #import "RACSignal+Operations.h" #import "RACSubject.h" #import "RACUnit.h" QuickSpecBegin(RACCommandSpec) RACSignal * (^emptySignalBlock)(id) = ^(id _) { return [RACSignal empty]; }; qck_describe(@"with a simple signal block", ^{ __block RACCommand *command; qck_beforeEach(^{ command = [[RACCommand alloc] initWithSignalBlock:^(id value) { return [RACSignal return:value]; }]; expect(command).notTo(beNil()); expect(@(command.allowsConcurrentExecution)).to(beFalsy()); }); qck_it(@"should be enabled by default", ^{ expect([command.enabled first]).to(equal(@YES)); }); qck_it(@"should not be executing by default", ^{ expect([command.executing first]).to(equal(@NO)); }); qck_it(@"should create an execution signal", ^{ __block NSUInteger signalsReceived = 0; __block BOOL completed = NO; id value = NSNull.null; [command.executionSignals subscribeNext:^(RACSignal *signal) { signalsReceived++; [signal subscribeNext:^(id x) { expect(x).to(equal(value)); } completed:^{ completed = YES; }]; }]; expect(@(signalsReceived)).to(equal(@0)); [command execute:value]; expect(@(signalsReceived)).toEventually(equal(@1)); expect(@(completed)).to(beTruthy()); }); qck_it(@"should return the execution signal from -execute:", ^{ __block BOOL completed = NO; id value = NSNull.null; [[command execute:value] subscribeNext:^(id x) { expect(x).to(equal(value)); } completed:^{ completed = YES; }]; expect(@(completed)).toEventually(beTruthy()); }); qck_it(@"should always send executionSignals on the main thread", ^{ __block RACScheduler *receivedScheduler = nil; [command.executionSignals subscribeNext:^(id _) { receivedScheduler = RACScheduler.currentScheduler; }]; [[RACScheduler scheduler] schedule:^{ expect(@([[command execute:nil] waitUntilCompleted:NULL])).to(beTruthy()); }]; expect(receivedScheduler).to(beNil()); expect(receivedScheduler).toEventually(equal(RACScheduler.mainThreadScheduler)); }); qck_it(@"should not send anything on 'errors' by default", ^{ __block BOOL receivedError = NO; [command.errors subscribeNext:^(id _) { receivedError = YES; }]; expect(@([[command execute:nil] asynchronouslyWaitUntilCompleted:NULL])).to(beTruthy()); expect(@(receivedError)).to(beFalsy()); }); qck_it(@"should be executing while an execution signal is running", ^{ [command.executionSignals subscribeNext:^(RACSignal *signal) { [signal subscribeNext:^(id x) { expect([command.executing first]).to(equal(@YES)); }]; }]; expect(@([[command execute:nil] asynchronouslyWaitUntilCompleted:NULL])).to(beTruthy()); expect([command.executing first]).to(equal(@NO)); }); qck_it(@"should always update executing on the main thread", ^{ __block RACScheduler *updatedScheduler = nil; [[command.executing skip:1] subscribeNext:^(NSNumber *executing) { if (!executing.boolValue) return; updatedScheduler = RACScheduler.currentScheduler; }]; [[RACScheduler scheduler] schedule:^{ expect(@([[command execute:nil] waitUntilCompleted:NULL])).to(beTruthy()); }]; expect([command.executing first]).to(equal(@NO)); expect(updatedScheduler).toEventually(equal(RACScheduler.mainThreadScheduler)); }); qck_it(@"should dealloc without subscribers", ^{ __block BOOL disposed = NO; @autoreleasepool { RACCommand *command __attribute__((objc_precise_lifetime)) = [[RACCommand alloc] initWithSignalBlock:emptySignalBlock]; [command.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ disposed = YES; }]]; } expect(@(disposed)).toEventually(beTruthy()); }); qck_it(@"should complete signals on the main thread when deallocated", ^{ __block RACScheduler *executionSignalsScheduler = nil; __block RACScheduler *executingScheduler = nil; __block RACScheduler *enabledScheduler = nil; __block RACScheduler *errorsScheduler = nil; [[RACScheduler scheduler] schedule:^{ @autoreleasepool { RACCommand *command __attribute__((objc_precise_lifetime)) = [[RACCommand alloc] initWithSignalBlock:emptySignalBlock]; [command.executionSignals subscribeCompleted:^{ executionSignalsScheduler = RACScheduler.currentScheduler; }]; [command.executing subscribeCompleted:^{ executingScheduler = RACScheduler.currentScheduler; }]; [command.enabled subscribeCompleted:^{ enabledScheduler = RACScheduler.currentScheduler; }]; [command.errors subscribeCompleted:^{ errorsScheduler = RACScheduler.currentScheduler; }]; } }]; expect(executionSignalsScheduler).toEventually(equal(RACScheduler.mainThreadScheduler)); expect(executingScheduler).toEventually(equal(RACScheduler.mainThreadScheduler)); expect(enabledScheduler).toEventually(equal(RACScheduler.mainThreadScheduler)); expect(errorsScheduler).toEventually(equal(RACScheduler.mainThreadScheduler)); }); }); qck_it(@"should invoke the signalBlock once per execution", ^{ NSMutableArray *valuesReceived = [NSMutableArray array]; RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^(id x) { [valuesReceived addObject:x]; return [RACSignal empty]; }]; expect(@([[command execute:@"foo"] asynchronouslyWaitUntilCompleted:NULL])).to(beTruthy()); expect(valuesReceived).to(equal((@[ @"foo" ]))); expect(@([[command execute:@"bar"] asynchronouslyWaitUntilCompleted:NULL])).to(beTruthy()); expect(valuesReceived).to(equal((@[ @"foo", @"bar" ]))); }); qck_it(@"should send on executionSignals in order of execution", ^{ RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^(RACSequence *seq) { return [seq signalWithScheduler:RACScheduler.immediateScheduler]; }]; NSMutableArray *valuesReceived = [NSMutableArray array]; [[command.executionSignals concat] subscribeNext:^(id x) { [valuesReceived addObject:x]; }]; RACSequence *first = @[ @"foo", @"bar" ].rac_sequence; expect(@([[command execute:first] asynchronouslyWaitUntilCompleted:NULL])).to(beTruthy()); RACSequence *second = @[ @"buzz", @"baz" ].rac_sequence; expect(@([[command execute:second] asynchronouslyWaitUntilCompleted:NULL])).to(beTruthy()); NSArray *expectedValues = @[ @"foo", @"bar", @"buzz", @"baz" ]; expect(valuesReceived).to(equal(expectedValues)); }); qck_it(@"should wait for all signals to complete or error before executing sends NO", ^{ RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^(RACSignal *signal) { return signal; }]; command.allowsConcurrentExecution = YES; RACSubject *firstSubject = [RACSubject subject]; expect([command execute:firstSubject]).notTo(beNil()); RACSubject *secondSubject = [RACSubject subject]; expect([command execute:secondSubject]).notTo(beNil()); expect([command.executing first]).toEventually(equal(@YES)); [firstSubject sendError:nil]; expect([command.executing first]).to(equal(@YES)); [secondSubject sendNext:nil]; expect([command.executing first]).to(equal(@YES)); [secondSubject sendCompleted]; expect([command.executing first]).toEventually(equal(@NO)); }); qck_it(@"should have allowsConcurrentExecution be observable", ^{ RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^(RACSignal *signal) { return signal; }]; RACSubject *completion = [RACSubject subject]; RACSignal *allowsConcurrentExecution = [[RACObserve(command, allowsConcurrentExecution) takeUntil:completion] replayLast]; command.allowsConcurrentExecution = YES; expect([allowsConcurrentExecution first]).to(beTrue()); [completion sendCompleted]; }); qck_it(@"should not deliver errors from executionSignals", ^{ RACSubject *subject = [RACSubject subject]; NSMutableArray *receivedEvents = [NSMutableArray array]; RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^(id _) { return subject; }]; [[[command.executionSignals flatten] materialize] subscribeNext:^(RACEvent *event) { [receivedEvents addObject:event]; }]; expect([command execute:nil]).notTo(beNil()); expect([command.executing first]).toEventually(equal(@YES)); [subject sendNext:RACUnit.defaultUnit]; NSArray *expectedEvents = @[ [RACEvent eventWithValue:RACUnit.defaultUnit] ]; expect(receivedEvents).toEventually(equal(expectedEvents)); expect([command.executing first]).to(equal(@YES)); [subject sendNext:@"foo"]; expectedEvents = @[ [RACEvent eventWithValue:RACUnit.defaultUnit], [RACEvent eventWithValue:@"foo"] ]; expect(receivedEvents).toEventually(equal(expectedEvents)); expect([command.executing first]).to(equal(@YES)); NSError *error = [NSError errorWithDomain:@"" code:1 userInfo:nil]; [subject sendError:error]; expect([command.executing first]).toEventually(equal(@NO)); expect(receivedEvents).to(equal(expectedEvents)); }); qck_it(@"should deliver errors from -execute:", ^{ RACSubject *subject = [RACSubject subject]; NSMutableArray *receivedEvents = [NSMutableArray array]; RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^(id _) { return subject; }]; [[[command execute:nil] materialize] subscribeNext:^(RACEvent *event) { [receivedEvents addObject:event]; }]; expect([command.executing first]).toEventually(equal(@YES)); [subject sendNext:RACUnit.defaultUnit]; NSArray *expectedEvents = @[ [RACEvent eventWithValue:RACUnit.defaultUnit] ]; expect(receivedEvents).toEventually(equal(expectedEvents)); expect([command.executing first]).to(equal(@YES)); [subject sendNext:@"foo"]; expectedEvents = @[ [RACEvent eventWithValue:RACUnit.defaultUnit], [RACEvent eventWithValue:@"foo"] ]; expect(receivedEvents).toEventually(equal(expectedEvents)); expect([command.executing first]).to(equal(@YES)); NSError *error = [NSError errorWithDomain:@"" code:1 userInfo:nil]; [subject sendError:error]; expectedEvents = @[ [RACEvent eventWithValue:RACUnit.defaultUnit], [RACEvent eventWithValue:@"foo"], [RACEvent eventWithError:error] ]; expect(receivedEvents).toEventually(equal(expectedEvents)); expect([command.executing first]).toEventually(equal(@NO)); }); qck_it(@"should deliver errors onto 'errors'", ^{ RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^(RACSignal *signal) { return signal; }]; command.allowsConcurrentExecution = YES; RACSubject *firstSubject = [RACSubject subject]; expect([command execute:firstSubject]).notTo(beNil()); RACSubject *secondSubject = [RACSubject subject]; expect([command execute:secondSubject]).notTo(beNil()); NSError *firstError = [NSError errorWithDomain:@"" code:1 userInfo:nil]; NSError *secondError = [NSError errorWithDomain:@"" code:2 userInfo:nil]; // We should receive errors from our previously-started executions. NSMutableArray *receivedErrors = [NSMutableArray array]; [command.errors subscribeNext:^(NSError *error) { [receivedErrors addObject:error]; }]; expect([command.executing first]).toEventually(equal(@YES)); [firstSubject sendError:firstError]; expect([command.executing first]).toEventually(equal(@YES)); NSArray *expected = @[ firstError ]; expect(receivedErrors).toEventually(equal(expected)); [secondSubject sendError:secondError]; expect([command.executing first]).toEventually(equal(@NO)); expected = @[ firstError, secondError ]; expect(receivedErrors).toEventually(equal(expected)); }); qck_it(@"should not deliver non-error events onto 'errors'", ^{ RACSubject *subject = [RACSubject subject]; RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^(id _) { return subject; }]; __block BOOL receivedEvent = NO; [command.errors subscribeNext:^(id _) { receivedEvent = YES; }]; expect([command execute:nil]).notTo(beNil()); expect([command.executing first]).toEventually(equal(@YES)); [subject sendNext:RACUnit.defaultUnit]; [subject sendCompleted]; expect([command.executing first]).toEventually(equal(@NO)); expect(@(receivedEvent)).to(beFalsy()); }); qck_it(@"should send errors on the main thread", ^{ RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^(RACSignal *signal) { return signal; }]; NSError *error = [NSError errorWithDomain:@"" code:1 userInfo:nil]; __block RACScheduler *receivedScheduler = nil; [command.errors subscribeNext:^(NSError *e) { expect(e).to(equal(error)); receivedScheduler = RACScheduler.currentScheduler; }]; RACSignal *errorSignal = [RACSignal error:error]; [[RACScheduler scheduler] schedule:^{ [command execute:errorSignal]; }]; expect(receivedScheduler).to(beNil()); expect(receivedScheduler).toEventually(equal(RACScheduler.mainThreadScheduler)); }); qck_describe(@"enabled signal", ^{ __block RACSubject *enabledSubject; __block RACCommand *command; qck_beforeEach(^{ enabledSubject = [RACSubject subject]; command = [[RACCommand alloc] initWithEnabled:enabledSubject signalBlock:^(id _) { return [RACSignal return:RACUnit.defaultUnit]; }]; }); qck_it(@"should send YES by default", ^{ expect([command.enabled first]).to(equal(@YES)); }); qck_it(@"should send whatever the enabledSignal has sent most recently", ^{ [enabledSubject sendNext:@NO]; expect([command.enabled first]).toEventually(equal(@NO)); [enabledSubject sendNext:@YES]; expect([command.enabled first]).toEventually(equal(@YES)); [enabledSubject sendNext:@NO]; expect([command.enabled first]).toEventually(equal(@NO)); }); qck_it(@"should sample enabledSignal synchronously at initialization time", ^{ RACCommand *command = [[RACCommand alloc] initWithEnabled:[RACSignal return:@NO] signalBlock:^(id _) { return [RACSignal empty]; }]; expect([command.enabled first]).to(equal(@NO)); }); qck_it(@"should send NO while executing is YES and allowsConcurrentExecution is NO", ^{ [[command.executionSignals flatten] subscribeNext:^(id _) { expect([command.executing first]).to(equal(@YES)); expect([command.enabled first]).to(equal(@NO)); }]; expect([command.enabled first]).to(equal(@YES)); expect(@([[command execute:nil] asynchronouslyWaitUntilCompleted:NULL])).to(beTruthy()); expect([command.enabled first]).to(equal(@YES)); }); qck_it(@"should send YES while executing is YES and allowsConcurrentExecution is YES", ^{ command.allowsConcurrentExecution = YES; __block BOOL outerExecuted = NO; __block BOOL innerExecuted = NO; // Prevent infinite recursion by only responding to the first value. [[[command.executionSignals take:1] flatten] subscribeNext:^(id _) { outerExecuted = YES; expect([command.executing first]).to(equal(@YES)); expect([command.enabled first]).to(equal(@YES)); [[command execute:nil] subscribeCompleted:^{ innerExecuted = YES; }]; }]; expect([command.enabled first]).to(equal(@YES)); expect([command execute:nil]).notTo(beNil()); expect(@(outerExecuted)).toEventually(beTruthy()); expect(@(innerExecuted)).toEventually(beTruthy()); expect([command.enabled first]).to(equal(@YES)); }); qck_it(@"should send an error from -execute: when NO", ^{ [enabledSubject sendNext:@NO]; RACSignal *signal = [command execute:nil]; expect(signal).notTo(beNil()); __block BOOL success = NO; __block NSError *error = nil; expect([signal firstOrDefault:nil success:&success error:&error]).to(beNil()); expect(@(success)).to(beFalsy()); expect(error).notTo(beNil()); expect(error.domain).to(equal(RACCommandErrorDomain)); expect(@(error.code)).to(equal(@(RACCommandErrorNotEnabled))); expect(error.userInfo[RACUnderlyingCommandErrorKey]).to(beIdenticalTo(command)); }); qck_it(@"should always update on the main thread", ^{ __block RACScheduler *updatedScheduler = nil; [[command.enabled skip:1] subscribeNext:^(id _) { updatedScheduler = RACScheduler.currentScheduler; }]; [[RACScheduler scheduler] schedule:^{ [enabledSubject sendNext:@NO]; }]; expect([command.enabled first]).to(equal(@YES)); expect([command.enabled first]).toEventually(equal(@NO)); expect(updatedScheduler).to(equal(RACScheduler.mainThreadScheduler)); }); qck_it(@"should complete when the command is deallocated even if the input signal hasn't", ^{ __block BOOL deallocated = NO; __block BOOL completed = NO; @autoreleasepool { RACCommand *command __attribute__((objc_precise_lifetime)) = [[RACCommand alloc] initWithEnabled:enabledSubject signalBlock:emptySignalBlock]; [command.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ deallocated = YES; }]]; [command.enabled subscribeCompleted:^{ completed = YES; }]; } expect(@(deallocated)).toEventually(beTruthy()); expect(@(completed)).toEventually(beTruthy()); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACCompoundDisposableSpec.m ================================================ // // RACCompoundDisposableSpec.m // ReactiveCocoa // // Created by Josh Abernathy on 11/30/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACCompoundDisposable.h" QuickSpecBegin(RACCompoundDisposableSpec) qck_it(@"should dispose of all its contained disposables", ^{ __block BOOL d1Disposed = NO; RACDisposable *d1 = [RACDisposable disposableWithBlock:^{ d1Disposed = YES; }]; __block BOOL d2Disposed = NO; RACDisposable *d2 = [RACDisposable disposableWithBlock:^{ d2Disposed = YES; }]; __block BOOL d3Disposed = NO; RACDisposable *d3 = [RACDisposable disposableWithBlock:^{ d3Disposed = YES; }]; __block BOOL d4Disposed = NO; RACDisposable *d4 = [RACDisposable disposableWithBlock:^{ d4Disposed = YES; }]; RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposableWithDisposables:@[ d1, d2, d3 ]]; [disposable addDisposable:d4]; expect(@(d1Disposed)).to(beFalsy()); expect(@(d2Disposed)).to(beFalsy()); expect(@(d3Disposed)).to(beFalsy()); expect(@(d4Disposed)).to(beFalsy()); expect(@(disposable.disposed)).to(beFalsy()); [disposable dispose]; expect(@(d1Disposed)).to(beTruthy()); expect(@(d2Disposed)).to(beTruthy()); expect(@(d3Disposed)).to(beTruthy()); expect(@(d4Disposed)).to(beTruthy()); expect(@(disposable.disposed)).to(beTruthy()); }); qck_it(@"should dispose of any added disposables immediately if it's already been disposed", ^{ RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable]; [disposable dispose]; RACDisposable *d = [[RACDisposable alloc] init]; expect(@(d.disposed)).to(beFalsy()); [disposable addDisposable:d]; expect(@(d.disposed)).to(beTruthy()); }); qck_it(@"should work when initialized with -init", ^{ RACCompoundDisposable *disposable = [[RACCompoundDisposable alloc] init]; __block BOOL disposed = NO; RACDisposable *d = [RACDisposable disposableWithBlock:^{ disposed = YES; }]; [disposable addDisposable:d]; expect(@(disposed)).to(beFalsy()); [disposable dispose]; expect(@(disposed)).to(beTruthy()); }); qck_it(@"should work when initialized with +disposableWithBlock:", ^{ __block BOOL compoundDisposed = NO; RACCompoundDisposable *disposable = [RACCompoundDisposable disposableWithBlock:^{ compoundDisposed = YES; }]; __block BOOL disposed = NO; RACDisposable *d = [RACDisposable disposableWithBlock:^{ disposed = YES; }]; [disposable addDisposable:d]; expect(@(disposed)).to(beFalsy()); expect(@(compoundDisposed)).to(beFalsy()); [disposable dispose]; expect(@(disposed)).to(beTruthy()); expect(@(compoundDisposed)).to(beTruthy()); }); qck_it(@"should allow disposables to be removed", ^{ RACCompoundDisposable *disposable = [[RACCompoundDisposable alloc] init]; RACDisposable *d = [[RACDisposable alloc] init]; [disposable addDisposable:d]; [disposable removeDisposable:d]; [disposable dispose]; expect(@(d.disposed)).to(beFalsy()); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACControlCommandExamples.h ================================================ // // RACControlCommandExamples.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-08-15. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // // The name of the shared examples for any control class that has // `rac_command` and `isEnabled` properties. extern NSString * const RACControlCommandExamples; // The control to test. extern NSString * const RACControlCommandExampleControl; // A block of type `void (^)(id control)` which should activate the // `rac_command` of the `control` by manipulating the control itself. extern NSString * const RACControlCommandExampleActivateBlock; ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACControlCommandExamples.m ================================================ // // RACControlCommandExamples.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-08-15. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "RACControlCommandExamples.h" #import "RACCommand.h" #import "RACSubject.h" #import "RACUnit.h" NSString * const RACControlCommandExamples = @"RACControlCommandExamples"; NSString * const RACControlCommandExampleControl = @"RACControlCommandExampleControl"; NSString * const RACControlCommandExampleActivateBlock = @"RACControlCommandExampleActivateBlock"; // Methods used by the unit test that would otherwise require platform-specific // imports. @interface NSObject (RACControlCommandExamples) @property (nonatomic, strong) RACCommand *rac_command; - (BOOL)isEnabled; @end QuickConfigurationBegin(RACControlCommandExampleGroups) + (void)configure:(Configuration *)configuration { sharedExamples(RACControlCommandExamples, ^(QCKDSLSharedExampleContext exampleContext) { __block id control; __block void (^activate)(id); __block RACSubject *enabledSubject; __block RACCommand *command; qck_beforeEach(^{ control = exampleContext()[RACControlCommandExampleControl]; activate = [exampleContext()[RACControlCommandExampleActivateBlock] copy]; enabledSubject = [RACSubject subject]; command = [[RACCommand alloc] initWithEnabled:enabledSubject signalBlock:^(id sender) { return [RACSignal return:sender]; }]; [control setRac_command:command]; }); qck_it(@"should bind the control's enabledness to the command", ^{ expect(@([control isEnabled])).toEventually(beTruthy()); [enabledSubject sendNext:@NO]; expect(@([control isEnabled])).toEventually(beFalsy()); [enabledSubject sendNext:@YES]; expect(@([control isEnabled])).toEventually(beTruthy()); }); qck_it(@"should execute the control's command when activated", ^{ __block BOOL executed = NO; [[command.executionSignals flatten] subscribeNext:^(id sender) { expect(sender).to(equal(control)); executed = YES; }]; activate(control); expect(@(executed)).toEventually(beTruthy()); }); qck_it(@"should overwrite an existing command when setting a new one", ^{ RACCommand *secondCommand = [[RACCommand alloc] initWithSignalBlock:^(id _) { return [RACSignal return:RACUnit.defaultUnit]; }]; [control setRac_command:secondCommand]; expect([control rac_command]).to(beIdenticalTo(secondCommand)); }); }); } QuickConfigurationEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACDelegateProxySpec.m ================================================ // // RACDelegateProxySpec.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-06-22. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "NSObject+RACSelectorSignal.h" #import "RACDelegateProxy.h" #import "RACSignal.h" #import "RACTuple.h" #import "RACCompoundDisposable.h" #import "NSObject+RACDeallocating.h" @protocol TestDelegateProtocol - (NSUInteger)lengthOfString:(NSString *)str; @end @interface TestDelegate : NSObject @property (nonatomic, assign) BOOL lengthOfStringInvoked; @end QuickSpecBegin(RACDelegateProxySpec) __block id proxy; __block TestDelegate *delegate; __block Protocol *protocol; qck_beforeEach(^{ protocol = @protocol(TestDelegateProtocol); expect(protocol).notTo(beNil()); proxy = [[RACDelegateProxy alloc] initWithProtocol:protocol]; expect(proxy).notTo(beNil()); expect([proxy rac_proxiedDelegate]).to(beNil()); delegate = [[TestDelegate alloc] init]; expect(delegate).notTo(beNil()); }); qck_it(@"should not respond to selectors at first", ^{ expect(@([proxy respondsToSelector:@selector(lengthOfString:)])).to(beFalsy()); }); qck_it(@"should send on a signal for a protocol method", ^{ __block RACTuple *tuple; [[proxy signalForSelector:@selector(lengthOfString:)] subscribeNext:^(RACTuple *t) { tuple = t; }]; expect(@([proxy respondsToSelector:@selector(lengthOfString:)])).to(beTruthy()); expect(@([proxy lengthOfString:@"foo"])).to(equal(@0)); expect(tuple).to(equal(RACTuplePack(@"foo"))); }); qck_it(@"should forward to the proxied delegate", ^{ [proxy setRac_proxiedDelegate:delegate]; expect(@([proxy respondsToSelector:@selector(lengthOfString:)])).to(beTruthy()); expect(@([proxy lengthOfString:@"foo"])).to(equal(@3)); expect(@(delegate.lengthOfStringInvoked)).to(beTruthy()); }); qck_it(@"should not send to the delegate when signals are applied", ^{ [proxy setRac_proxiedDelegate:delegate]; __block RACTuple *tuple; [[proxy signalForSelector:@selector(lengthOfString:)] subscribeNext:^(RACTuple *t) { tuple = t; }]; expect(@([proxy respondsToSelector:@selector(lengthOfString:)])).to(beTruthy()); expect(@([proxy lengthOfString:@"foo"])).to(equal(@0)); expect(tuple).to(equal(RACTuplePack(@"foo"))); expect(@(delegate.lengthOfStringInvoked)).to(beFalsy()); }); QuickSpecEnd @implementation TestDelegate - (NSUInteger)lengthOfString:(NSString *)str { self.lengthOfStringInvoked = YES; return str.length; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACDisposableSpec.m ================================================ // // RACDisposableSpec.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-06-13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "RACDisposable.h" #import "RACScopedDisposable.h" QuickSpecBegin(RACDisposableSpec) qck_it(@"should initialize without a block", ^{ RACDisposable *disposable = [[RACDisposable alloc] init]; expect(disposable).notTo(beNil()); expect(@(disposable.disposed)).to(beFalsy()); [disposable dispose]; expect(@(disposable.disposed)).to(beTruthy()); }); qck_it(@"should execute a block upon disposal", ^{ __block BOOL disposed = NO; RACDisposable *disposable = [RACDisposable disposableWithBlock:^{ disposed = YES; }]; expect(disposable).notTo(beNil()); expect(@(disposed)).to(beFalsy()); expect(@(disposable.disposed)).to(beFalsy()); [disposable dispose]; expect(@(disposed)).to(beTruthy()); expect(@(disposable.disposed)).to(beTruthy()); }); qck_it(@"should not dispose upon deallocation", ^{ __block BOOL disposed = NO; __weak RACDisposable *weakDisposable = nil; @autoreleasepool { RACDisposable *disposable = [RACDisposable disposableWithBlock:^{ disposed = YES; }]; weakDisposable = disposable; expect(weakDisposable).notTo(beNil()); } expect(weakDisposable).to(beNil()); expect(@(disposed)).to(beFalsy()); }); qck_it(@"should create a scoped disposable", ^{ __block BOOL disposed = NO; __weak RACScopedDisposable *weakDisposable = nil; @autoreleasepool { RACScopedDisposable *disposable __attribute__((objc_precise_lifetime)) = [RACScopedDisposable disposableWithBlock:^{ disposed = YES; }]; weakDisposable = disposable; expect(weakDisposable).notTo(beNil()); expect(@(disposed)).to(beFalsy()); } expect(weakDisposable).to(beNil()); expect(@(disposed)).to(beTruthy()); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACEventSpec.m ================================================ // // RACEventSpec.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-01-07. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "RACEvent.h" QuickSpecBegin(RACEventSpec) qck_it(@"should return the singleton completed event", ^{ RACEvent *event = RACEvent.completedEvent; expect(event).notTo(beNil()); expect(event).to(beIdenticalTo(RACEvent.completedEvent)); expect([event copy]).to(beIdenticalTo(event)); expect(@(event.eventType)).to(equal(@(RACEventTypeCompleted))); expect(@(event.finished)).to(beTruthy()); expect(event.error).to(beNil()); expect(event.value).to(beNil()); }); qck_it(@"should return an error event", ^{ NSError *error = [NSError errorWithDomain:@"foo" code:1 userInfo:nil]; RACEvent *event = [RACEvent eventWithError:error]; expect(event).notTo(beNil()); expect(event).to(equal([RACEvent eventWithError:error])); expect([event copy]).to(equal(event)); expect(@(event.eventType)).to(equal(@(RACEventTypeError))); expect(@(event.finished)).to(beTruthy()); expect(event.error).to(equal(error)); expect(event.value).to(beNil()); }); qck_it(@"should return an error event with a nil error", ^{ RACEvent *event = [RACEvent eventWithError:nil]; expect(event).notTo(beNil()); expect(event).to(equal([RACEvent eventWithError:nil])); expect([event copy]).to(equal(event)); expect(@(event.eventType)).to(equal(@(RACEventTypeError))); expect(@(event.finished)).to(beTruthy()); expect(event.error).to(beNil()); expect(event.value).to(beNil()); }); qck_it(@"should return a next event", ^{ NSString *value = @"foo"; RACEvent *event = [RACEvent eventWithValue:value]; expect(event).notTo(beNil()); expect(event).to(equal([RACEvent eventWithValue:value])); expect([event copy]).to(equal(event)); expect(@(event.eventType)).to(equal(@(RACEventTypeNext))); expect(@(event.finished)).to(beFalsy()); expect(event.error).to(beNil()); expect(event.value).to(equal(value)); }); qck_it(@"should return a next event with a nil value", ^{ RACEvent *event = [RACEvent eventWithValue:nil]; expect(event).notTo(beNil()); expect(event).to(equal([RACEvent eventWithValue:nil])); expect([event copy]).to(equal(event)); expect(@(event.eventType)).to(equal(@(RACEventTypeNext))); expect(@(event.finished)).to(beFalsy()); expect(event.error).to(beNil()); expect(event.value).to(beNil()); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACKVOChannelSpec.m ================================================ // // RACKVOChannelSpec.m // ReactiveCocoa // // Created by Uri Baghin on 16/12/2012. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACTestObject.h" #import "RACChannelExamples.h" #import "RACPropertySignalExamples.h" #import "NSObject+RACDeallocating.h" #import "NSObject+RACKVOWrapper.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACKVOChannel.h" #import "RACSignal+Operations.h" QuickSpecBegin(RACKVOChannelSpec) qck_describe(@"RACKVOChannel", ^{ __block RACTestObject *object; __block RACKVOChannel *channel; id value1 = @"test value 1"; id value2 = @"test value 2"; id value3 = @"test value 3"; NSArray *values = @[ value1, value2, value3 ]; qck_beforeEach(^{ object = [[RACTestObject alloc] init]; channel = [[RACKVOChannel alloc] initWithTarget:object keyPath:@keypath(object.stringValue) nilValue:nil]; }); id setupBlock = ^(RACTestObject *testObject, NSString *keyPath, id nilValue, RACSignal *signal) { RACKVOChannel *channel = [[RACKVOChannel alloc] initWithTarget:testObject keyPath:keyPath nilValue:nilValue]; [signal subscribe:channel.followingTerminal]; }; qck_itBehavesLike(RACPropertySignalExamples, ^{ return @{ RACPropertySignalExamplesSetupBlock: setupBlock }; }); qck_itBehavesLike(RACChannelExamples, ^{ return @{ RACChannelExampleCreateBlock: [^{ return [[RACKVOChannel alloc] initWithTarget:object keyPath:@keypath(object.stringValue) nilValue:nil]; } copy] }; }); qck_it(@"should send the object's current value when subscribed to followingTerminal", ^{ __block id receivedValue = @"received value should not be this"; [[channel.followingTerminal take:1] subscribeNext:^(id x) { receivedValue = x; }]; expect(receivedValue).to(beNil()); object.stringValue = value1; [[channel.followingTerminal take:1] subscribeNext:^(id x) { receivedValue = x; }]; expect(receivedValue).to(equal(value1)); }); qck_it(@"should send the object's new value on followingTerminal when it's changed", ^{ object.stringValue = value1; NSMutableArray *receivedValues = [NSMutableArray array]; [channel.followingTerminal subscribeNext:^(id x) { [receivedValues addObject:x]; }]; object.stringValue = value2; object.stringValue = value3; expect(receivedValues).to(equal(values)); }); qck_it(@"should set the object's value using values sent to the followingTerminal", ^{ expect(object.stringValue).to(beNil()); [channel.followingTerminal sendNext:value1]; expect(object.stringValue).to(equal(value1)); [channel.followingTerminal sendNext:value2]; expect(object.stringValue).to(equal(value2)); }); qck_it(@"should be able to subscribe to signals", ^{ NSMutableArray *receivedValues = [NSMutableArray array]; [object rac_observeKeyPath:@keypath(object.stringValue) options:0 observer:self block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { [receivedValues addObject:value]; }]; RACSignal *signal = [RACSignal createSignal:^ RACDisposable * (id subscriber) { [subscriber sendNext:value1]; [subscriber sendNext:value2]; [subscriber sendNext:value3]; return nil; }]; [signal subscribe:channel.followingTerminal]; expect(receivedValues).to(equal(values)); }); qck_it(@"should complete both terminals when the target deallocates", ^{ __block BOOL leadingCompleted = NO; __block BOOL followingCompleted = NO; __block BOOL deallocated = NO; @autoreleasepool { RACTestObject *object __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init]; [object.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ deallocated = YES; }]]; RACKVOChannel *channel = [[RACKVOChannel alloc] initWithTarget:object keyPath:@keypath(object.stringValue) nilValue:nil]; [channel.leadingTerminal subscribeCompleted:^{ leadingCompleted = YES; }]; [channel.followingTerminal subscribeCompleted:^{ followingCompleted = YES; }]; expect(@(deallocated)).to(beFalsy()); expect(@(leadingCompleted)).to(beFalsy()); expect(@(followingCompleted)).to(beFalsy()); } expect(@(deallocated)).to(beTruthy()); expect(@(leadingCompleted)).to(beTruthy()); expect(@(followingCompleted)).to(beTruthy()); }); qck_it(@"should deallocate when the target deallocates", ^{ __block BOOL targetDeallocated = NO; __block BOOL channelDeallocated = NO; @autoreleasepool { RACTestObject *object __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init]; [object.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ targetDeallocated = YES; }]]; RACKVOChannel *channel = [[RACKVOChannel alloc] initWithTarget:object keyPath:@keypath(object.stringValue) nilValue:nil]; [channel.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ channelDeallocated = YES; }]]; expect(@(targetDeallocated)).to(beFalsy()); expect(@(channelDeallocated)).to(beFalsy()); } expect(@(targetDeallocated)).to(beTruthy()); expect(@(channelDeallocated)).to(beTruthy()); }); }); qck_describe(@"RACChannelTo", ^{ __block RACTestObject *a; __block RACTestObject *b; __block RACTestObject *c; __block NSString *testName1; __block NSString *testName2; __block NSString *testName3; qck_beforeEach(^{ a = [[RACTestObject alloc] init]; b = [[RACTestObject alloc] init]; c = [[RACTestObject alloc] init]; testName1 = @"sync it!"; testName2 = @"sync it again!"; testName3 = @"sync it once more!"; }); qck_it(@"should keep objects' properties in sync", ^{ RACChannelTo(a, stringValue) = RACChannelTo(b, stringValue); expect(a.stringValue).to(beNil()); expect(b.stringValue).to(beNil()); a.stringValue = testName1; expect(a.stringValue).to(equal(testName1)); expect(b.stringValue).to(equal(testName1)); b.stringValue = testName2; expect(a.stringValue).to(equal(testName2)); expect(b.stringValue).to(equal(testName2)); a.stringValue = nil; expect(a.stringValue).to(beNil()); expect(b.stringValue).to(beNil()); }); qck_it(@"should keep properties identified by keypaths in sync", ^{ RACChannelTo(a, strongTestObjectValue.stringValue) = RACChannelTo(b, strongTestObjectValue.stringValue); a.strongTestObjectValue = [[RACTestObject alloc] init]; b.strongTestObjectValue = [[RACTestObject alloc] init]; a.strongTestObjectValue.stringValue = testName1; expect(a.strongTestObjectValue.stringValue).to(equal(testName1)); expect(b.strongTestObjectValue.stringValue).to(equal(testName1)); expect(a.strongTestObjectValue).notTo(equal(b.strongTestObjectValue)); b.strongTestObjectValue = nil; expect(a.strongTestObjectValue.stringValue).to(beNil()); c.stringValue = testName2; b.strongTestObjectValue = c; expect(a.strongTestObjectValue.stringValue).to(equal(testName2)); expect(b.strongTestObjectValue.stringValue).to(equal(testName2)); expect(a.strongTestObjectValue).notTo(equal(b.strongTestObjectValue)); }); qck_it(@"should update properties identified by keypaths when the intermediate values change", ^{ RACChannelTo(a, strongTestObjectValue.stringValue) = RACChannelTo(b, strongTestObjectValue.stringValue); a.strongTestObjectValue = [[RACTestObject alloc] init]; b.strongTestObjectValue = [[RACTestObject alloc] init]; c.stringValue = testName1; b.strongTestObjectValue = c; expect(a.strongTestObjectValue.stringValue).to(equal(testName1)); expect(a.strongTestObjectValue).notTo(equal(b.strongTestObjectValue)); }); qck_it(@"should update properties identified by keypaths when the channel was created when one of the two objects had an intermediate nil value", ^{ RACChannelTo(a, strongTestObjectValue.stringValue) = RACChannelTo(b, strongTestObjectValue.stringValue); b.strongTestObjectValue = [[RACTestObject alloc] init]; c.stringValue = testName1; a.strongTestObjectValue = c; expect(a.strongTestObjectValue.stringValue).to(equal(testName1)); expect(b.strongTestObjectValue.stringValue).to(equal(testName1)); expect(a.strongTestObjectValue).notTo(equal(b.strongTestObjectValue)); }); qck_it(@"should take the value of the object being bound to at the start", ^{ a.stringValue = testName1; b.stringValue = testName2; RACChannelTo(a, stringValue) = RACChannelTo(b, stringValue); expect(a.stringValue).to(equal(testName2)); expect(b.stringValue).to(equal(testName2)); }); qck_it(@"should update the value even if it's the same value the object had before it was bound", ^{ a.stringValue = testName1; b.stringValue = testName2; RACChannelTo(a, stringValue) = RACChannelTo(b, stringValue); expect(a.stringValue).to(equal(testName2)); expect(b.stringValue).to(equal(testName2)); b.stringValue = testName1; expect(a.stringValue).to(equal(testName1)); expect(b.stringValue).to(equal(testName1)); }); qck_it(@"should bind transitively", ^{ a.stringValue = testName1; b.stringValue = testName2; c.stringValue = testName3; RACChannelTo(a, stringValue) = RACChannelTo(b, stringValue); RACChannelTo(b, stringValue) = RACChannelTo(c, stringValue); expect(a.stringValue).to(equal(testName3)); expect(b.stringValue).to(equal(testName3)); expect(c.stringValue).to(equal(testName3)); c.stringValue = testName1; expect(a.stringValue).to(equal(testName1)); expect(b.stringValue).to(equal(testName1)); expect(c.stringValue).to(equal(testName1)); b.stringValue = testName2; expect(a.stringValue).to(equal(testName2)); expect(b.stringValue).to(equal(testName2)); expect(c.stringValue).to(equal(testName2)); a.stringValue = testName3; expect(a.stringValue).to(equal(testName3)); expect(b.stringValue).to(equal(testName3)); expect(c.stringValue).to(equal(testName3)); }); qck_it(@"should bind changes made by KVC on arrays", ^{ b.arrayValue = @[]; RACChannelTo(a, arrayValue) = RACChannelTo(b, arrayValue); [[b mutableArrayValueForKeyPath:@keypath(b.arrayValue)] addObject:@1]; expect(a.arrayValue).to(equal(b.arrayValue)); }); qck_it(@"should bind changes made by KVC on sets", ^{ b.setValue = [NSSet set]; RACChannelTo(a, setValue) = RACChannelTo(b, setValue); [[b mutableSetValueForKeyPath:@keypath(b.setValue)] addObject:@1]; expect(a.setValue).to(equal(b.setValue)); }); qck_it(@"should bind changes made by KVC on ordered sets", ^{ b.orderedSetValue = [NSOrderedSet orderedSet]; RACChannelTo(a, orderedSetValue) = RACChannelTo(b, orderedSetValue); [[b mutableOrderedSetValueForKeyPath:@keypath(b.orderedSetValue)] addObject:@1]; expect(a.orderedSetValue).to(equal(b.orderedSetValue)); }); qck_it(@"should handle deallocation of intermediate objects correctly even without support from KVO", ^{ __block BOOL wasDisposed = NO; RACChannelTo(a, weakTestObjectValue.stringValue) = RACChannelTo(b, strongTestObjectValue.stringValue); b.strongTestObjectValue = [[RACTestObject alloc] init]; @autoreleasepool { RACTestObject *object = [[RACTestObject alloc] init]; [object.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ wasDisposed = YES; }]]; a.weakTestObjectValue = object; object.stringValue = testName1; expect(@(wasDisposed)).to(beFalsy()); expect(b.strongTestObjectValue.stringValue).to(equal(testName1)); } expect(@(wasDisposed)).toEventually(beTruthy()); expect(b.strongTestObjectValue.stringValue).to(beNil()); }); qck_it(@"should stop binding when disposed", ^{ RACChannelTerminal *aTerminal = RACChannelTo(a, stringValue); RACChannelTerminal *bTerminal = RACChannelTo(b, stringValue); a.stringValue = testName1; RACDisposable *disposable = [aTerminal subscribe:bTerminal]; expect(a.stringValue).to(equal(testName1)); expect(b.stringValue).to(equal(testName1)); a.stringValue = testName2; expect(a.stringValue).to(equal(testName2)); expect(b.stringValue).to(equal(testName2)); [disposable dispose]; a.stringValue = testName3; expect(a.stringValue).to(equal(testName3)); expect(b.stringValue).to(equal(testName2)); }); qck_it(@"should use the nilValue when sent nil", ^{ RACChannelTerminal *terminal = RACChannelTo(a, integerValue, @5); expect(@(a.integerValue)).to(equal(@0)); [terminal sendNext:@2]; expect(@(a.integerValue)).to(equal(@2)); [terminal sendNext:nil]; expect(@(a.integerValue)).to(equal(@5)); }); qck_it(@"should use the nilValue when an intermediate object is nil", ^{ __block BOOL wasDisposed = NO; RACChannelTo(a, weakTestObjectValue.integerValue, @5) = RACChannelTo(b, strongTestObjectValue.integerValue, @5); b.strongTestObjectValue = [[RACTestObject alloc] init]; @autoreleasepool { RACTestObject *object = [[RACTestObject alloc] init]; [object.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ wasDisposed = YES; }]]; a.weakTestObjectValue = object; object.integerValue = 2; expect(@(wasDisposed)).to(beFalsy()); expect(@(b.strongTestObjectValue.integerValue)).to(equal(@2)); } expect(@(wasDisposed)).toEventually(beTruthy()); expect(@(b.strongTestObjectValue.integerValue)).to(equal(@5)); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACKVOProxySpec.m ================================================ // // RACKVOProxySpec.m // ReactiveCocoa // // Created by Richard Speyer on 4/24/14. // Copyright (c) 2014 GitHub, Inc. All rights reserved. // #import #import #import "RACKVOProxy.h" #import "NSObject+RACKVOWrapper.h" #import "NSObject+RACPropertySubscribing.h" #import "RACSerialDisposable.h" #import "RACSignal+Operations.h" #import "RACScheduler.h" #import "RACSubject.h" @interface TestObject : NSObject { volatile int _testInt; } @property (assign, atomic) int testInt; @end @implementation TestObject - (int)testInt { return _testInt; } // Use manual KVO notifications to avoid any possible race conditions within the // automatic KVO implementation. - (void)setTestInt:(int)value { [self willChangeValueForKey:@keypath(self.testInt)]; _testInt = value; [self didChangeValueForKey:@keypath(self.testInt)]; } + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key { return NO; } @end QuickSpecBegin(RACKVOProxySpec) qck_describe(@"RACKVOProxy", ^{ __block TestObject *testObject; __block dispatch_queue_t concurrentQueue; qck_beforeEach(^{ testObject = [[TestObject alloc] init]; concurrentQueue = dispatch_queue_create("org.reactivecocoa.ReactiveCocoa.RACKVOProxySpec.concurrentQueue", DISPATCH_QUEUE_CONCURRENT); }); qck_afterEach(^{ dispatch_barrier_sync(concurrentQueue, ^{ testObject = nil; }); }); qck_describe(@"basic", ^{ qck_it(@"should handle multiple observations on the same value", ^{ __block int observedValue1 = 0; __block int observedValue2 = 0; [[[RACObserve(testObject, testInt) skip:1] take:1] subscribeNext:^(NSNumber *wrappedInt) { observedValue1 = wrappedInt.intValue; }]; [[[RACObserve(testObject, testInt) skip:1] take:1] subscribeNext:^(NSNumber *wrappedInt) { observedValue2 = wrappedInt.intValue; }]; testObject.testInt = 2; expect(@(observedValue1)).toEventually(equal(@2)); expect(@(observedValue2)).toEventually(equal(@2)); }); qck_it(@"can remove individual observation", ^{ __block int observedValue1 = 0; __block int observedValue2 = 0; RACDisposable *disposable1 = [RACObserve(testObject, testInt) subscribeNext:^(NSNumber *wrappedInt) { observedValue1 = wrappedInt.intValue; }]; [RACObserve(testObject, testInt) subscribeNext:^(NSNumber *wrappedInt) { observedValue2 = wrappedInt.intValue; }]; testObject.testInt = 2; expect(@(observedValue1)).toEventually(equal(@2)); expect(@(observedValue2)).toEventually(equal(@2)); [disposable1 dispose]; testObject.testInt = 3; expect(@(observedValue2)).toEventually(equal(@3)); expect(@(observedValue1)).to(equal(@2)); }); }); qck_describe(@"async", ^{ qck_it(@"should handle changes being made on another queue", ^{ __block int observedValue = 0; [[[RACObserve(testObject, testInt) skip:1] take:1] subscribeNext:^(NSNumber *wrappedInt) { observedValue = wrappedInt.intValue; }]; dispatch_async(concurrentQueue, ^{ testObject.testInt = 2; }); dispatch_barrier_sync(concurrentQueue, ^{}); expect(@(observedValue)).toEventually(equal(@2)); }); qck_it(@"should handle changes being made on another queue using deliverOn", ^{ __block int observedValue = 0; [[[[RACObserve(testObject, testInt) skip:1] take:1] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSNumber *wrappedInt) { observedValue = wrappedInt.intValue; }]; dispatch_async(concurrentQueue, ^{ testObject.testInt = 2; }); dispatch_barrier_sync(concurrentQueue, ^{}); expect(@(observedValue)).toEventually(equal(@2)); }); qck_it(@"async disposal of target", ^{ __block int observedValue; [[RACObserve(testObject, testInt) deliverOn:RACScheduler.mainThreadScheduler] subscribeNext:^(NSNumber *wrappedInt) { observedValue = wrappedInt.intValue; }]; dispatch_async(concurrentQueue, ^{ testObject.testInt = 2; testObject = nil; }); dispatch_barrier_sync(concurrentQueue, ^{}); expect(@(observedValue)).toEventually(equal(@2)); }); }); qck_describe(@"stress", ^{ static const size_t numIterations = 5000; __block dispatch_queue_t iterationQueue; beforeEach(^{ iterationQueue = dispatch_queue_create("org.reactivecocoa.ReactiveCocoa.RACKVOProxySpec.iterationQueue", DISPATCH_QUEUE_CONCURRENT); }); // ReactiveCocoa/ReactiveCocoa#1122 qck_it(@"async disposal of observer", ^{ RACSerialDisposable *disposable = [[RACSerialDisposable alloc] init]; dispatch_apply(numIterations, iterationQueue, ^(size_t index) { RACDisposable *newDisposable = [RACObserve(testObject, testInt) subscribeCompleted:^{}]; [[disposable swapInDisposable:newDisposable] dispose]; dispatch_async(concurrentQueue, ^{ testObject.testInt = (int)index; }); }); dispatch_barrier_sync(iterationQueue, ^{ [disposable dispose]; }); }); qck_it(@"async disposal of signal with in-flight changes", ^{ RACSubject *teardown = [RACSubject subject]; RACSignal *isEvenSignal = [[[[RACObserve(testObject, testInt) map:^(NSNumber *wrappedInt) { return @((wrappedInt.intValue % 2) == 0); }] deliverOn:RACScheduler.mainThreadScheduler] takeUntil:teardown] replayLast]; dispatch_apply(numIterations, iterationQueue, ^(size_t index) { testObject.testInt = (int)index; }); dispatch_barrier_async(iterationQueue, ^{ [teardown sendNext:nil]; }); expect(@([isEvenSignal asynchronouslyWaitUntilCompleted:NULL])).to(beTruthy()); }); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACKVOWrapperSpec.m ================================================ // // RACKVOWrapperSpec.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-08-07. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "NSObject+RACKVOWrapper.h" #import #import "NSObject+RACDeallocating.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACKVOTrampoline.h" #import "RACTestObject.h" @interface RACTestOperation : NSOperation @end // The name of the examples. static NSString * const RACKVOWrapperExamples = @"RACKVOWrapperExamples"; // A block that returns an object to observe in the examples. static NSString * const RACKVOWrapperExamplesTargetBlock = @"RACKVOWrapperExamplesTargetBlock"; // The key path to observe in the examples. // // The key path must have at least one weak property in it. static NSString * const RACKVOWrapperExamplesKeyPath = @"RACKVOWrapperExamplesKeyPath"; // A block that changes the value of a weak property in the observed key path. // The block is passed the object the example is observing and the new value the // weak property should be changed to( static NSString * const RACKVOWrapperExamplesChangeBlock = @"RACKVOWrapperExamplesChangeBlock"; // A block that returns a valid value for the weak property changed by // RACKVOWrapperExamplesChangeBlock. The value must deallocate // normally. static NSString * const RACKVOWrapperExamplesValueBlock = @"RACKVOWrapperExamplesValueBlock"; // Whether RACKVOWrapperExamplesChangeBlock changes the value // of the last key path component in the key path directly. static NSString * const RACKVOWrapperExamplesChangesValueDirectly = @"RACKVOWrapperExamplesChangesValueDirectly"; // The name of the examples. static NSString * const RACKVOWrapperCollectionExamples = @"RACKVOWrapperCollectionExamples"; // A block that returns an object to observe in the examples. static NSString * const RACKVOWrapperCollectionExamplesTargetBlock = @"RACKVOWrapperCollectionExamplesTargetBlock"; // The key path to observe in the examples. // // Must identify a property of type NSOrderedSet. static NSString * const RACKVOWrapperCollectionExamplesKeyPath = @"RACKVOWrapperCollectionExamplesKeyPath"; QuickConfigurationBegin(RACKVOWrapperExampleGroups) + (void)configure:(Configuration *)configuration { sharedExamples(RACKVOWrapperExamples, ^(QCKDSLSharedExampleContext exampleContext) { __block NSObject *target = nil; __block NSString *keyPath = nil; __block void (^changeBlock)(NSObject *, id) = nil; __block id (^valueBlock)(void) = nil; __block BOOL changesValueDirectly = NO; __block NSUInteger priorCallCount = 0; __block NSUInteger posteriorCallCount = 0; __block BOOL priorTriggeredByLastKeyPathComponent = NO; __block BOOL posteriorTriggeredByLastKeyPathComponent = NO; __block BOOL posteriorTriggeredByDeallocation = NO; __block void (^callbackBlock)(id, NSDictionary *, BOOL, BOOL) = nil; qck_beforeEach(^{ NSObject * (^targetBlock)(void) = exampleContext()[RACKVOWrapperExamplesTargetBlock]; target = targetBlock(); keyPath = exampleContext()[RACKVOWrapperExamplesKeyPath]; changeBlock = exampleContext()[RACKVOWrapperExamplesChangeBlock]; valueBlock = exampleContext()[RACKVOWrapperExamplesValueBlock]; changesValueDirectly = [exampleContext()[RACKVOWrapperExamplesChangesValueDirectly] boolValue]; priorCallCount = 0; posteriorCallCount = 0; callbackBlock = [^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { if ([change[NSKeyValueChangeNotificationIsPriorKey] boolValue]) { priorTriggeredByLastKeyPathComponent = affectedOnlyLastComponent; ++priorCallCount; return; } posteriorTriggeredByLastKeyPathComponent = affectedOnlyLastComponent; posteriorTriggeredByDeallocation = causedByDealloc; ++posteriorCallCount; } copy]; }); qck_afterEach(^{ target = nil; keyPath = nil; changeBlock = nil; valueBlock = nil; changesValueDirectly = NO; callbackBlock = nil; }); qck_it(@"should not call the callback block on add if called without NSKeyValueObservingOptionInitial", ^{ [target rac_observeKeyPath:keyPath options:NSKeyValueObservingOptionPrior observer:nil block:callbackBlock]; expect(@(priorCallCount)).to(equal(@0)); expect(@(posteriorCallCount)).to(equal(@0)); }); qck_it(@"should call the callback block on add if called with NSKeyValueObservingOptionInitial", ^{ [target rac_observeKeyPath:keyPath options:NSKeyValueObservingOptionPrior | NSKeyValueObservingOptionInitial observer:nil block:callbackBlock]; expect(@(priorCallCount)).to(equal(@0)); expect(@(posteriorCallCount)).to(equal(@1)); }); qck_it(@"should call the callback block twice per change, once prior and once posterior", ^{ [target rac_observeKeyPath:keyPath options:NSKeyValueObservingOptionPrior observer:nil block:callbackBlock]; priorCallCount = 0; posteriorCallCount = 0; id value1 = valueBlock(); changeBlock(target, value1); expect(@(priorCallCount)).to(equal(@1)); expect(@(posteriorCallCount)).to(equal(@1)); expect(@(priorTriggeredByLastKeyPathComponent)).to(equal(@(changesValueDirectly))); expect(@(posteriorTriggeredByLastKeyPathComponent)).to(equal(@(changesValueDirectly))); expect(@(posteriorTriggeredByDeallocation)).to(beFalsy()); id value2 = valueBlock(); changeBlock(target, value2); expect(@(priorCallCount)).to(equal(@2)); expect(@(posteriorCallCount)).to(equal(@2)); expect(@(priorTriggeredByLastKeyPathComponent)).to(equal(@(changesValueDirectly))); expect(@(posteriorTriggeredByLastKeyPathComponent)).to(equal(@(changesValueDirectly))); expect(@(posteriorTriggeredByDeallocation)).to(beFalsy()); }); qck_it(@"should call the callback block with NSKeyValueChangeNotificationIsPriorKey set before the value is changed, and not set after the value is changed", ^{ __block BOOL priorCalled = NO; __block BOOL posteriorCalled = NO; __block id priorValue = nil; __block id posteriorValue = nil; id value1 = valueBlock(); changeBlock(target, value1); id oldValue = [target valueForKeyPath:keyPath]; [target rac_observeKeyPath:keyPath options:NSKeyValueObservingOptionPrior observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { if ([change[NSKeyValueChangeNotificationIsPriorKey] boolValue]) { priorCalled = YES; priorValue = value; expect(@(posteriorCalled)).to(beFalsy()); return; } posteriorCalled = YES; posteriorValue = value; expect(@(priorCalled)).to(beTruthy()); }]; id value2 = valueBlock(); changeBlock(target, value2); id newValue = [target valueForKeyPath:keyPath]; expect(@(priorCalled)).to(beTruthy()); expect(priorValue).to(equal(oldValue)); expect(@(posteriorCalled)).to(beTruthy()); expect(posteriorValue).to(equal(newValue)); }); qck_it(@"should not call the callback block after it's been disposed", ^{ RACDisposable *disposable = [target rac_observeKeyPath:keyPath options:NSKeyValueObservingOptionPrior observer:nil block:callbackBlock]; priorCallCount = 0; posteriorCallCount = 0; [disposable dispose]; expect(@(priorCallCount)).to(equal(@0)); expect(@(posteriorCallCount)).to(equal(@0)); id value = valueBlock(); changeBlock(target, value); expect(@(priorCallCount)).to(equal(@0)); expect(@(posteriorCallCount)).to(equal(@0)); }); qck_it(@"should call the callback block only once with NSKeyValueChangeNotificationIsPriorKey not set when the value is deallocated", ^{ __block BOOL valueDidDealloc = NO; [target rac_observeKeyPath:keyPath options:NSKeyValueObservingOptionPrior observer:nil block:callbackBlock]; @autoreleasepool { NSObject *value __attribute__((objc_precise_lifetime)) = valueBlock(); [value.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ valueDidDealloc = YES; }]]; changeBlock(target, value); priorCallCount = 0; posteriorCallCount = 0; } expect(@(valueDidDealloc)).to(beTruthy()); expect(@(priorCallCount)).to(equal(@0)); expect(@(posteriorCallCount)).to(equal(@1)); expect(@(posteriorTriggeredByDeallocation)).to(beTruthy()); }); }); qck_sharedExamples(RACKVOWrapperCollectionExamples, ^(QCKDSLSharedExampleContext exampleContext) { __block NSObject *target = nil; __block NSString *keyPath = nil; __block NSMutableOrderedSet *mutableKeyPathProxy = nil; __block void (^callbackBlock)(id, NSDictionary *, BOOL, BOOL) = nil; __block id priorValue = nil; __block id posteriorValue = nil; __block NSDictionary *priorChange = nil; __block NSDictionary *posteriorChange = nil; qck_beforeEach(^{ NSObject * (^targetBlock)(void) = exampleContext()[RACKVOWrapperCollectionExamplesTargetBlock]; target = targetBlock(); keyPath = exampleContext()[RACKVOWrapperCollectionExamplesKeyPath]; callbackBlock = [^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { if ([change[NSKeyValueChangeNotificationIsPriorKey] boolValue]) { priorValue = value; priorChange = change; return; } posteriorValue = value; posteriorChange = change; } copy]; [target setValue:[NSOrderedSet orderedSetWithObject:@0] forKeyPath:keyPath]; [target rac_observeKeyPath:keyPath options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld | NSKeyValueObservingOptionPrior observer:nil block:callbackBlock]; mutableKeyPathProxy = [target mutableOrderedSetValueForKeyPath:keyPath]; }); qck_afterEach(^{ target = nil; keyPath = nil; callbackBlock = nil; priorValue = nil; priorChange = nil; posteriorValue = nil; posteriorChange = nil; }); qck_it(@"should support inserting elements into ordered collections", ^{ [mutableKeyPathProxy insertObject:@1 atIndex:0]; expect(priorValue).to(equal([NSOrderedSet orderedSetWithArray:@[ @0 ]])); expect(posteriorValue).to(equal([NSOrderedSet orderedSetWithArray:(@[ @1, @0 ])])); expect(priorChange[NSKeyValueChangeKindKey]).to(equal(@(NSKeyValueChangeInsertion))); expect(posteriorChange[NSKeyValueChangeKindKey]).to(equal(@(NSKeyValueChangeInsertion))); expect(priorChange[NSKeyValueChangeOldKey]).to(beNil()); expect(posteriorChange[NSKeyValueChangeNewKey]).to(equal(@[ @1 ])); expect(priorChange[NSKeyValueChangeIndexesKey]).to(equal([NSIndexSet indexSetWithIndex:0])); expect(posteriorChange[NSKeyValueChangeIndexesKey]).to(equal([NSIndexSet indexSetWithIndex:0])); }); qck_it(@"should support removing elements from ordered collections", ^{ [mutableKeyPathProxy removeObjectAtIndex:0]; expect(priorValue).to(equal([NSOrderedSet orderedSetWithArray:@[ @0 ]])); expect(posteriorValue).to(equal([NSOrderedSet orderedSetWithArray:@[]])); expect(priorChange[NSKeyValueChangeKindKey]).to(equal(@(NSKeyValueChangeRemoval))); expect(posteriorChange[NSKeyValueChangeKindKey]).to(equal(@(NSKeyValueChangeRemoval))); expect(priorChange[NSKeyValueChangeOldKey]).to(equal(@[ @0 ])); expect(posteriorChange[NSKeyValueChangeNewKey]).to(beNil()); expect(priorChange[NSKeyValueChangeIndexesKey]).to(equal([NSIndexSet indexSetWithIndex:0])); expect(posteriorChange[NSKeyValueChangeIndexesKey]).to(equal([NSIndexSet indexSetWithIndex:0])); }); qck_it(@"should support replacing elements in ordered collections", ^{ [mutableKeyPathProxy replaceObjectAtIndex:0 withObject:@1]; expect(priorValue).to(equal([NSOrderedSet orderedSetWithArray:@[ @0 ]])); expect(posteriorValue).to(equal([NSOrderedSet orderedSetWithArray:@[ @1 ]])); expect(priorChange[NSKeyValueChangeKindKey]).to(equal(@(NSKeyValueChangeReplacement))); expect(posteriorChange[NSKeyValueChangeKindKey]).to(equal(@(NSKeyValueChangeReplacement))); expect(priorChange[NSKeyValueChangeOldKey]).to(equal(@[ @0 ])); expect(posteriorChange[NSKeyValueChangeNewKey]).to(equal(@[ @1 ])); expect(priorChange[NSKeyValueChangeIndexesKey]).to(equal([NSIndexSet indexSetWithIndex:0])); expect(posteriorChange[NSKeyValueChangeIndexesKey]).to(equal([NSIndexSet indexSetWithIndex:0])); }); qck_it(@"should support adding elements to unordered collections", ^{ [mutableKeyPathProxy unionOrderedSet:[NSOrderedSet orderedSetWithObject:@1]]; expect(priorValue).to(equal([NSOrderedSet orderedSetWithArray:@[ @0 ]])); expect(posteriorValue).to(equal([NSOrderedSet orderedSetWithArray:(@[ @0, @1 ])])); expect(priorChange[NSKeyValueChangeKindKey]).to(equal(@(NSKeyValueChangeInsertion))); expect(posteriorChange[NSKeyValueChangeKindKey]).to(equal(@(NSKeyValueChangeInsertion))); expect(priorChange[NSKeyValueChangeOldKey]).to(beNil()); expect(posteriorChange[NSKeyValueChangeNewKey]).to(equal(@[ @1 ])); }); qck_it(@"should support removing elements from unordered collections", ^{ [mutableKeyPathProxy minusOrderedSet:[NSOrderedSet orderedSetWithObject:@0]]; expect(priorValue).to(equal([NSOrderedSet orderedSetWithArray:@[ @0 ]])); expect(posteriorValue).to(equal([NSOrderedSet orderedSetWithArray:@[]])); expect(priorChange[NSKeyValueChangeKindKey]).to(equal(@(NSKeyValueChangeRemoval))); expect(posteriorChange[NSKeyValueChangeKindKey]).to(equal(@(NSKeyValueChangeRemoval))); expect(priorChange[NSKeyValueChangeOldKey]).to(equal(@[ @0 ])); expect(posteriorChange[NSKeyValueChangeNewKey]).to(beNil()); }); }); } QuickConfigurationEnd QuickSpecBegin(RACKVOWrapperSpec) qck_describe(@"-rac_observeKeyPath:options:observer:block:", ^{ qck_describe(@"on simple keys", ^{ NSObject * (^targetBlock)(void) = ^{ return [[RACTestObject alloc] init]; }; void (^changeBlock)(RACTestObject *, id) = ^(RACTestObject *target, id value) { target.weakTestObjectValue = value; }; id (^valueBlock)(void) = ^{ return [[RACTestObject alloc] init]; }; qck_itBehavesLike(RACKVOWrapperExamples, ^{ return @{ RACKVOWrapperExamplesTargetBlock: targetBlock, RACKVOWrapperExamplesKeyPath: @keypath(RACTestObject.new, weakTestObjectValue), RACKVOWrapperExamplesChangeBlock: changeBlock, RACKVOWrapperExamplesValueBlock: valueBlock, RACKVOWrapperExamplesChangesValueDirectly: @YES }; }); qck_itBehavesLike(RACKVOWrapperCollectionExamples, ^{ return @{ RACKVOWrapperCollectionExamplesTargetBlock: targetBlock, RACKVOWrapperCollectionExamplesKeyPath: @keypath(RACTestObject.new, orderedSetValue) }; }); }); qck_describe(@"on composite key paths'", ^{ qck_describe(@"last key path components", ^{ NSObject *(^targetBlock)(void) = ^{ RACTestObject *object = [[RACTestObject alloc] init]; object.strongTestObjectValue = [[RACTestObject alloc] init]; return object; }; void (^changeBlock)(RACTestObject *, id) = ^(RACTestObject *target, id value) { target.strongTestObjectValue.weakTestObjectValue = value; }; id (^valueBlock)(void) = ^{ return [[RACTestObject alloc] init]; }; qck_itBehavesLike(RACKVOWrapperExamples, ^{ return @{ RACKVOWrapperExamplesTargetBlock: targetBlock, RACKVOWrapperExamplesKeyPath: @keypath(RACTestObject.new, strongTestObjectValue.weakTestObjectValue), RACKVOWrapperExamplesChangeBlock: changeBlock, RACKVOWrapperExamplesValueBlock: valueBlock, RACKVOWrapperExamplesChangesValueDirectly: @YES }; }); qck_itBehavesLike(RACKVOWrapperCollectionExamples, ^{ return @{ RACKVOWrapperCollectionExamplesTargetBlock: targetBlock, RACKVOWrapperCollectionExamplesKeyPath: @keypath(RACTestObject.new, strongTestObjectValue.orderedSetValue) }; }); }); qck_describe(@"intermediate key path components", ^{ NSObject *(^targetBlock)(void) = ^{ return [[RACTestObject alloc] init]; }; void (^changeBlock)(RACTestObject *, id) = ^(RACTestObject *target, id value) { target.weakTestObjectValue = value; }; id (^valueBlock)(void) = ^{ RACTestObject *object = [[RACTestObject alloc] init]; object.strongTestObjectValue = [[RACTestObject alloc] init]; return object; }; qck_itBehavesLike(RACKVOWrapperExamples, ^{ return @{ RACKVOWrapperExamplesTargetBlock: targetBlock, RACKVOWrapperExamplesKeyPath: @keypath([[RACTestObject alloc] init], weakTestObjectValue.strongTestObjectValue), RACKVOWrapperExamplesChangeBlock: changeBlock, RACKVOWrapperExamplesValueBlock: valueBlock, RACKVOWrapperExamplesChangesValueDirectly: @NO }; }); }); qck_it(@"should not notice deallocation of the object returned by a dynamic final property", ^{ RACTestObject *object = [[RACTestObject alloc] init]; __block id lastValue = nil; @autoreleasepool { [object rac_observeKeyPath:@keypath(object.dynamicObjectProperty) options:NSKeyValueObservingOptionInitial observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { lastValue = value; }]; expect(lastValue).to(beAKindOf(RACTestObject.class)); } expect(lastValue).to(beAKindOf(RACTestObject.class)); }); qck_it(@"should not notice deallocation of the object returned by a dynamic intermediate property", ^{ RACTestObject *object = [[RACTestObject alloc] init]; __block id lastValue = nil; @autoreleasepool { [object rac_observeKeyPath:@keypath(object.dynamicObjectProperty.integerValue) options:NSKeyValueObservingOptionInitial observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { lastValue = value; }]; expect(lastValue).to(equal(@42)); } expect(lastValue).to(equal(@42)); }); qck_it(@"should not notice deallocation of the object returned by a dynamic method", ^{ RACTestObject *object = [[RACTestObject alloc] init]; __block id lastValue = nil; @autoreleasepool { [object rac_observeKeyPath:@keypath(object.dynamicObjectMethod) options:NSKeyValueObservingOptionInitial observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { lastValue = value; }]; expect(lastValue).to(beAKindOf(RACTestObject.class)); } expect(lastValue).to(beAKindOf(RACTestObject.class)); }); }); qck_it(@"should not call the callback block when the value is the observer", ^{ __block BOOL observerDisposed = NO; __block BOOL observerDeallocationTriggeredChange = NO; __block BOOL targetDisposed = NO; __block BOOL targetDeallocationTriggeredChange = NO; @autoreleasepool { RACTestObject *observer __attribute__((objc_precise_lifetime)) = [RACTestObject new]; [observer.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ observerDisposed = YES; }]]; RACTestObject *target __attribute__((objc_precise_lifetime)) = [RACTestObject new]; [target.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ targetDisposed = YES; }]]; observer.weakTestObjectValue = observer; target.weakTestObjectValue = target; // These observations can only result in dealloc triggered callbacks. [observer rac_observeKeyPath:@keypath(target.weakTestObjectValue) options:0 observer:observer block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { observerDeallocationTriggeredChange = YES; }]; [target rac_observeKeyPath:@keypath(target.weakTestObjectValue) options:0 observer:observer block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { targetDeallocationTriggeredChange = YES; }]; } expect(@(observerDisposed)).to(beTruthy()); expect(@(observerDeallocationTriggeredChange)).to(beFalsy()); expect(@(targetDisposed)).to(beTruthy()); expect(@(targetDeallocationTriggeredChange)).to(beTruthy()); }); qck_it(@"should call the callback block for deallocation of the initial value of a single-key key path", ^{ RACTestObject *target = [RACTestObject new]; __block BOOL objectDisposed = NO; __block BOOL objectDeallocationTriggeredChange = NO; @autoreleasepool { RACTestObject *object __attribute__((objc_precise_lifetime)) = [RACTestObject new]; target.weakTestObjectValue = object; [object.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ objectDisposed = YES; }]]; [target rac_observeKeyPath:@keypath(target.weakTestObjectValue) options:0 observer:target block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { objectDeallocationTriggeredChange = YES; }]; } expect(@(objectDisposed)).to(beTruthy()); expect(@(objectDeallocationTriggeredChange)).to(beTruthy()); }); qck_it(@"should call the callback block for deallocation of an object conforming to protocol property", ^{ RACTestObject *target = [RACTestObject new]; __block BOOL objectDisposed = NO; __block BOOL objectDeallocationTriggeredChange = NO; @autoreleasepool { RACTestObject *object __attribute__((objc_precise_lifetime)) = [RACTestObject new]; target.weakObjectWithProtocol = object; [object.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ objectDisposed = YES; }]]; [target rac_observeKeyPath:@keypath(target.weakObjectWithProtocol) options:0 observer:target block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { objectDeallocationTriggeredChange = YES; }]; } expect(@(objectDisposed)).to(beTruthy()); expect(@(objectDeallocationTriggeredChange)).to(beTruthy()); }); }); qck_describe(@"rac_addObserver:forKeyPath:options:block:", ^{ qck_it(@"should add and remove an observer", ^{ NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{}]; expect(operation).notTo(beNil()); __block BOOL notified = NO; RACDisposable *disposable = [operation rac_observeKeyPath:@"isFinished" options:NSKeyValueObservingOptionNew observer:self block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { expect([change objectForKey:NSKeyValueChangeNewKey]).to(equal(@YES)); expect(@(notified)).to(beFalsy()); notified = YES; }]; expect(disposable).notTo(beNil()); [operation start]; [operation waitUntilFinished]; expect(@(notified)).toEventually(beTruthy()); }); qck_it(@"should accept a nil observer", ^{ NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{}]; RACDisposable *disposable = [operation rac_observeKeyPath:@"isFinished" options:NSKeyValueObservingOptionNew observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {}]; expect(disposable).notTo(beNil()); }); qck_it(@"automatically stops KVO on subclasses when the target deallocates", ^{ void (^testKVOOnSubclass)(Class targetClass, id observer) = ^(Class targetClass, id observer) { __weak id weakTarget = nil; __weak id identifier = nil; @autoreleasepool { // Create an observable target that we control the memory management of. CFTypeRef target = CFBridgingRetain([[targetClass alloc] init]); expect((__bridge id)target).notTo(beNil()); weakTarget = (__bridge id)target; expect(weakTarget).notTo(beNil()); identifier = [(__bridge id)target rac_observeKeyPath:@"isFinished" options:0 observer:observer block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {}]; expect(identifier).notTo(beNil()); CFRelease(target); } expect(weakTarget).to(beNil()); expect(identifier).to(beNil()); }; qck_it(@"stops KVO on NSObject subclasses", ^{ testKVOOnSubclass(NSOperation.class, self); }); qck_it(@"stops KVO on subclasses of already-swizzled classes", ^{ testKVOOnSubclass(RACTestOperation.class, self); }); qck_it(@"stops KVO on NSObject subclasses even with a nil observer", ^{ testKVOOnSubclass(NSOperation.class, nil); }); qck_it(@"stops KVO on subclasses of already-swizzled classes even with a nil observer", ^{ testKVOOnSubclass(RACTestOperation.class, nil); }); }); qck_it(@"should automatically stop KVO when the observer deallocates", ^{ __weak id weakObserver = nil; __weak id weakIdentifier = nil; NSOperation *operation = [[NSOperation alloc] init]; @autoreleasepool { // Create an observer that we control the memory management of. CFTypeRef observer = CFBridgingRetain([[NSOperation alloc] init]); expect((__bridge id)observer).notTo(beNil()); weakObserver = (__bridge id)observer; expect(weakObserver).notTo(beNil()); id identifier = [operation rac_observeKeyPath:@"isFinished" options:0 observer:(__bridge id)observer block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {}]; expect(identifier).notTo(beNil()); weakIdentifier = identifier; expect(weakIdentifier).notTo(beNil()); CFRelease(observer); } expect(weakObserver).to(beNil()); expect(weakIdentifier).to(beNil()); }); qck_it(@"should stop KVO when the observer is disposed", ^{ NSOperationQueue *queue = [[NSOperationQueue alloc] init]; __block NSString *name = nil; RACDisposable *disposable = [queue rac_observeKeyPath:@"name" options:0 observer:self block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { name = queue.name; }]; queue.name = @"1"; expect(name).to(equal(@"1")); [disposable dispose]; queue.name = @"2"; expect(name).to(equal(@"1")); }); qck_it(@"should distinguish between observers being disposed", ^{ NSOperationQueue *queue = [[NSOperationQueue alloc] init]; __block NSString *name1 = nil; __block NSString *name2 = nil; RACDisposable *disposable = [queue rac_observeKeyPath:@"name" options:0 observer:self block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { name1 = queue.name; }]; [queue rac_observeKeyPath:@"name" options:0 observer:self block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { name2 = queue.name; }]; queue.name = @"1"; expect(name1).to(equal(@"1")); expect(name2).to(equal(@"1")); [disposable dispose]; queue.name = @"2"; expect(name1).to(equal(@"1")); expect(name2).to(equal(@"2")); }); }); QuickSpecEnd @implementation RACTestOperation @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACMulticastConnectionSpec.m ================================================ // // RACMulticastConnectionSpec.m // ReactiveCocoa // // Created by Josh Abernathy on 10/8/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACMulticastConnection.h" #import "RACDisposable.h" #import "RACSignal+Operations.h" #import "RACSubscriber.h" #import "RACReplaySubject.h" #import "RACScheduler.h" #import QuickSpecBegin(RACMulticastConnectionSpec) __block NSUInteger subscriptionCount = 0; __block RACMulticastConnection *connection; qck_beforeEach(^{ subscriptionCount = 0; connection = [[RACSignal createSignal:^(id subscriber) { subscriptionCount++; return (RACDisposable *)nil; }] publish]; expect(@(subscriptionCount)).to(equal(@0)); }); qck_describe(@"-connect", ^{ qck_it(@"should subscribe to the underlying signal", ^{ [connection connect]; expect(@(subscriptionCount)).to(equal(@1)); }); qck_it(@"should return the same disposable for each invocation", ^{ RACDisposable *d1 = [connection connect]; RACDisposable *d2 = [connection connect]; expect(d1).to(equal(d2)); expect(@(subscriptionCount)).to(equal(@1)); }); qck_it(@"shouldn't reconnect after disposal", ^{ RACDisposable *disposable1 = [connection connect]; expect(@(subscriptionCount)).to(equal(@1)); [disposable1 dispose]; RACDisposable *disposable2 = [connection connect]; expect(@(subscriptionCount)).to(equal(@1)); expect(disposable1).to(equal(disposable2)); }); qck_it(@"shouldn't race when connecting", ^{ dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); RACMulticastConnection *connection = [[RACSignal defer:^ id { dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); return nil; }] publish]; __block RACDisposable *disposable; [RACScheduler.scheduler schedule:^{ disposable = [connection connect]; dispatch_semaphore_signal(semaphore); }]; expect([connection connect]).notTo(beNil()); dispatch_semaphore_signal(semaphore); expect(disposable).toEventuallyNot(beNil()); }); }); qck_describe(@"-autoconnect", ^{ __block RACSignal *autoconnectedSignal; qck_beforeEach(^{ autoconnectedSignal = [connection autoconnect]; }); qck_it(@"should subscribe to the multicasted signal on the first subscription", ^{ expect(@(subscriptionCount)).to(equal(@0)); [autoconnectedSignal subscribeNext:^(id x) {}]; expect(@(subscriptionCount)).to(equal(@1)); [autoconnectedSignal subscribeNext:^(id x) {}]; expect(@(subscriptionCount)).to(equal(@1)); }); qck_it(@"should dispose of the multicasted subscription when the signal has no subscribers", ^{ __block BOOL disposed = NO; __block id connectionSubscriber = nil; RACSignal *signal = [[[RACSignal createSignal:^(id subscriber) { // Keep the subscriber alive so it doesn't trigger disposal on dealloc connectionSubscriber = subscriber; subscriptionCount++; return [RACDisposable disposableWithBlock:^{ disposed = YES; }]; }] publish] autoconnect]; RACDisposable *disposable = [signal subscribeNext:^(id x) {}]; expect(@(disposed)).to(beFalsy()); [disposable dispose]; expect(@(disposed)).to(beTruthy()); }); qck_it(@"shouldn't reconnect after disposal", ^{ RACDisposable *disposable = [autoconnectedSignal subscribeNext:^(id x) {}]; expect(@(subscriptionCount)).to(equal(@1)); [disposable dispose]; disposable = [autoconnectedSignal subscribeNext:^(id x) {}]; expect(@(subscriptionCount)).to(equal(@1)); [disposable dispose]; }); qck_it(@"should replay values after disposal when multicasted to a replay subject", ^{ RACSubject *subject = [RACSubject subject]; RACSignal *signal = [[subject multicast:[RACReplaySubject subject]] autoconnect]; NSMutableArray *results1 = [NSMutableArray array]; RACDisposable *disposable = [signal subscribeNext:^(id x) { [results1 addObject:x]; }]; [subject sendNext:@1]; [subject sendNext:@2]; expect(results1).to(equal((@[ @1, @2 ]))); [disposable dispose]; NSMutableArray *results2 = [NSMutableArray array]; [signal subscribeNext:^(id x) { [results2 addObject:x]; }]; expect(results2).toEventually(equal((@[ @1, @2 ]))); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACPropertySignalExamples.h ================================================ // // RACPropertySignalExamples.h // ReactiveCocoa // // Created by Josh Abernathy on 9/28/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // // The name of the shared examples for a signal-driven property. extern NSString * const RACPropertySignalExamples; // The block should have the signature: // // void (^)(RACTestObject *testObject, NSString *keyPath, id nilValue, RACSignal *signal) // // and should tie the value of the key path on testObject to signal. `nilValue` // will be used when the signal sends a `nil` value. extern NSString * const RACPropertySignalExamplesSetupBlock; ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACPropertySignalExamples.m ================================================ // // RACPropertySignalExamples.m // ReactiveCocoa // // Created by Josh Abernathy on 9/28/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACTestObject.h" #import #import "NSObject+RACDeallocating.h" #import "NSObject+RACPropertySubscribing.h" #import "NSObject+RACSelectorSignal.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACSubject.h" NSString * const RACPropertySignalExamples = @"RACPropertySignalExamples"; NSString * const RACPropertySignalExamplesSetupBlock = @"RACPropertySignalExamplesSetupBlock"; QuickConfigurationBegin(RACPropertySignalExampleGroups) + (void)configure:(Configuration *)configuration { sharedExamples(RACPropertySignalExamples, ^(QCKDSLSharedExampleContext exampleContext) { __block RACTestObject *testObject = nil; __block void (^setupBlock)(RACTestObject *, NSString *keyPath, id nilValue, RACSignal *); qck_beforeEach(^{ setupBlock = exampleContext()[RACPropertySignalExamplesSetupBlock]; testObject = [[RACTestObject alloc] init]; }); qck_it(@"should set the value of the property with the latest value from the signal", ^{ RACSubject *subject = [RACSubject subject]; setupBlock(testObject, @keypath(testObject.objectValue), nil, subject); expect(testObject.objectValue).to(beNil()); [subject sendNext:@1]; expect(testObject.objectValue).to(equal(@1)); [subject sendNext:@2]; expect(testObject.objectValue).to(equal(@2)); [subject sendNext:nil]; expect(testObject.objectValue).to(beNil()); }); qck_it(@"should set the given nilValue for an object property", ^{ RACSubject *subject = [RACSubject subject]; setupBlock(testObject, @keypath(testObject.objectValue), @"foo", subject); expect(testObject.objectValue).to(beNil()); [subject sendNext:@1]; expect(testObject.objectValue).to(equal(@1)); [subject sendNext:@2]; expect(testObject.objectValue).to(equal(@2)); [subject sendNext:nil]; expect(testObject.objectValue).to(equal(@"foo")); }); qck_it(@"should leave the value of the property alone after the signal completes", ^{ RACSubject *subject = [RACSubject subject]; setupBlock(testObject, @keypath(testObject.objectValue), nil, subject); expect(testObject.objectValue).to(beNil()); [subject sendNext:@1]; expect(testObject.objectValue).to(equal(@1)); [subject sendCompleted]; expect(testObject.objectValue).to(equal(@1)); }); qck_it(@"should set the value of a non-object property with the latest value from the signal", ^{ RACSubject *subject = [RACSubject subject]; setupBlock(testObject, @keypath(testObject.integerValue), nil, subject); expect(@(testObject.integerValue)).to(equal(@0)); [subject sendNext:@1]; expect(@(testObject.integerValue)).to(equal(@1)); [subject sendNext:@2]; expect(@(testObject.integerValue)).to(equal(@2)); [subject sendNext:@0]; expect(@(testObject.integerValue)).to(equal(@0)); }); qck_it(@"should set the given nilValue for a non-object property", ^{ RACSubject *subject = [RACSubject subject]; setupBlock(testObject, @keypath(testObject.integerValue), @42, subject); expect(@(testObject.integerValue)).to(equal(@0)); [subject sendNext:@1]; expect(@(testObject.integerValue)).to(equal(@1)); [subject sendNext:@2]; expect(@(testObject.integerValue)).to(equal(@2)); [subject sendNext:nil]; expect(@(testObject.integerValue)).to(equal(@42)); }); qck_it(@"should not invoke -setNilValueForKey: with a nilValue", ^{ RACSubject *subject = [RACSubject subject]; setupBlock(testObject, @keypath(testObject.integerValue), @42, subject); __block BOOL setNilValueForKeyInvoked = NO; [[testObject rac_signalForSelector:@selector(setNilValueForKey:)] subscribeNext:^(NSString *key) { setNilValueForKeyInvoked = YES; }]; [subject sendNext:nil]; expect(@(testObject.integerValue)).to(equal(@42)); expect(@(setNilValueForKeyInvoked)).to(beFalsy()); }); qck_it(@"should invoke -setNilValueForKey: without a nilValue", ^{ RACSubject *subject = [RACSubject subject]; setupBlock(testObject, @keypath(testObject.integerValue), nil, subject); [subject sendNext:@1]; expect(@(testObject.integerValue)).to(equal(@1)); testObject.catchSetNilValueForKey = YES; __block BOOL setNilValueForKeyInvoked = NO; [[testObject rac_signalForSelector:@selector(setNilValueForKey:)] subscribeNext:^(NSString *key) { setNilValueForKeyInvoked = YES; }]; [subject sendNext:nil]; expect(@(testObject.integerValue)).to(equal(@1)); expect(@(setNilValueForKeyInvoked)).to(beTruthy()); }); }); } QuickConfigurationEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACSchedulerSpec.m ================================================ // // RACSchedulerSpec.m // ReactiveCocoa // // Created by Josh Abernathy on 11/29/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACScheduler.h" #import "RACScheduler+Private.h" #import "RACQueueScheduler+Subclass.h" #import "RACDisposable.h" #import #import "RACTestExampleScheduler.h" #import // This shouldn't be used directly. Use the `expectCurrentSchedulers` block // below instead. static void expectCurrentSchedulersInner(NSArray *schedulers, NSMutableArray *currentSchedulerArray) { if (schedulers.count > 0) { RACScheduler *topScheduler = schedulers[0]; [topScheduler schedule:^{ RACScheduler *currentScheduler = RACScheduler.currentScheduler; if (currentScheduler != nil) [currentSchedulerArray addObject:currentScheduler]; expectCurrentSchedulersInner([schedulers subarrayWithRange:NSMakeRange(1, schedulers.count - 1)], currentSchedulerArray); }]; } } QuickSpecBegin(RACSchedulerSpec) qck_it(@"should know its current scheduler", ^{ // Recursively schedules a block in each of the given schedulers and records // the +currentScheduler at each step. It then expects the array of // +currentSchedulers and the expected array to be equal. // // schedulers - The array of schedulers to recursively schedule. // expectedCurrentSchedulers - The array of +currentSchedulers to expect. void (^expectCurrentSchedulers)(NSArray *, NSArray *) = ^(NSArray *schedulers, NSArray *expectedCurrentSchedulers) { NSMutableArray *currentSchedulerArray = [NSMutableArray array]; expectCurrentSchedulersInner(schedulers, currentSchedulerArray); expect(currentSchedulerArray).toEventually(equal(expectedCurrentSchedulers)); }; RACScheduler *backgroundScheduler = [RACScheduler scheduler]; expectCurrentSchedulers(@[ backgroundScheduler, RACScheduler.immediateScheduler ], @[ backgroundScheduler, backgroundScheduler ]); expectCurrentSchedulers(@[ backgroundScheduler, RACScheduler.subscriptionScheduler ], @[ backgroundScheduler, backgroundScheduler ]); NSArray *mainThreadJumper = @[ RACScheduler.mainThreadScheduler, backgroundScheduler, RACScheduler.mainThreadScheduler ]; expectCurrentSchedulers(mainThreadJumper, mainThreadJumper); NSArray *backgroundJumper = @[ backgroundScheduler, RACScheduler.mainThreadScheduler, backgroundScheduler ]; expectCurrentSchedulers(backgroundJumper, backgroundJumper); }); qck_describe(@"+mainThreadScheduler", ^{ qck_it(@"should cancel scheduled blocks when disposed", ^{ __block BOOL firstBlockRan = NO; __block BOOL secondBlockRan = NO; RACDisposable *disposable = [RACScheduler.mainThreadScheduler schedule:^{ firstBlockRan = YES; }]; expect(disposable).notTo(beNil()); [RACScheduler.mainThreadScheduler schedule:^{ secondBlockRan = YES; }]; [disposable dispose]; expect(@(secondBlockRan)).to(beFalsy()); expect(@(secondBlockRan)).toEventually(beTruthy()); expect(@(firstBlockRan)).to(beFalsy()); }); qck_it(@"should schedule future blocks", ^{ __block BOOL done = NO; [RACScheduler.mainThreadScheduler after:[NSDate date] schedule:^{ done = YES; }]; expect(@(done)).to(beFalsy()); expect(@(done)).toEventually(beTruthy()); }); qck_it(@"should cancel future blocks when disposed", ^{ __block BOOL firstBlockRan = NO; __block BOOL secondBlockRan = NO; RACDisposable *disposable = [RACScheduler.mainThreadScheduler after:[NSDate date] schedule:^{ firstBlockRan = YES; }]; expect(disposable).notTo(beNil()); [RACScheduler.mainThreadScheduler after:[NSDate date] schedule:^{ secondBlockRan = YES; }]; [disposable dispose]; expect(@(secondBlockRan)).to(beFalsy()); expect(@(secondBlockRan)).toEventually(beTruthy()); expect(@(firstBlockRan)).to(beFalsy()); }); qck_it(@"should schedule recurring blocks", ^{ __block NSUInteger count = 0; RACDisposable *disposable = [RACScheduler.mainThreadScheduler after:[NSDate date] repeatingEvery:0.05 withLeeway:0 schedule:^{ count++; }]; expect(@(count)).to(equal(@0)); expect(@(count)).toEventually(beGreaterThanOrEqualTo(@1)); expect(@(count)).toEventually(beGreaterThanOrEqualTo(@2)); expect(@(count)).toEventually(beGreaterThanOrEqualTo(@3)); [disposable dispose]; [NSRunLoop.mainRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; expect(@(count)).to(beGreaterThanOrEqualTo(@3)); }); }); qck_describe(@"+scheduler", ^{ __block RACScheduler *scheduler; __block NSDate * (^futureDate)(void); qck_beforeEach(^{ scheduler = [RACScheduler scheduler]; futureDate = ^{ return [NSDate dateWithTimeIntervalSinceNow:0.01]; }; }); qck_it(@"should cancel scheduled blocks when disposed", ^{ __block BOOL firstBlockRan = NO; __block BOOL secondBlockRan = NO; // Start off on the scheduler so the enqueued blocks won't run until we // return. [scheduler schedule:^{ RACDisposable *disposable = [scheduler schedule:^{ firstBlockRan = YES; }]; expect(disposable).notTo(beNil()); [scheduler schedule:^{ secondBlockRan = YES; }]; [disposable dispose]; }]; expect(@(secondBlockRan)).toEventually(beTruthy()); expect(@(firstBlockRan)).to(beFalsy()); }); qck_it(@"should schedule future blocks", ^{ __block BOOL done = NO; [scheduler after:futureDate() schedule:^{ done = YES; }]; expect(@(done)).to(beFalsy()); expect(@(done)).toEventually(beTruthy()); }); qck_it(@"should cancel future blocks when disposed", ^{ __block BOOL firstBlockRan = NO; __block BOOL secondBlockRan = NO; NSDate *date = futureDate(); RACDisposable *disposable = [scheduler after:date schedule:^{ firstBlockRan = YES; }]; expect(disposable).notTo(beNil()); [disposable dispose]; [scheduler after:date schedule:^{ secondBlockRan = YES; }]; expect(@(secondBlockRan)).to(beFalsy()); expect(@(secondBlockRan)).toEventually(beTruthy()); expect(@(firstBlockRan)).to(beFalsy()); }); qck_it(@"should schedule recurring blocks", ^{ __block NSUInteger count = 0; RACDisposable *disposable = [scheduler after:[NSDate date] repeatingEvery:0.05 withLeeway:0 schedule:^{ count++; }]; expect(@(count)).to(beGreaterThanOrEqualTo(@0)); expect(@(count)).toEventually(beGreaterThanOrEqualTo(@1)); expect(@(count)).toEventually(beGreaterThanOrEqualTo(@2)); expect(@(count)).toEventually(beGreaterThanOrEqualTo(@3)); [disposable dispose]; [NSThread sleepForTimeInterval:0.1]; expect(@(count)).to(beGreaterThanOrEqualTo(@3)); }); }); qck_describe(@"+subscriptionScheduler", ^{ qck_describe(@"setting +currentScheduler", ^{ __block RACScheduler *currentScheduler; qck_beforeEach(^{ currentScheduler = nil; }); qck_it(@"should be the +mainThreadScheduler when scheduled from the main queue", ^{ dispatch_async(dispatch_get_main_queue(), ^{ [RACScheduler.subscriptionScheduler schedule:^{ currentScheduler = RACScheduler.currentScheduler; }]; }); expect(currentScheduler).toEventually(equal(RACScheduler.mainThreadScheduler)); }); qck_it(@"should be a +scheduler when scheduled from an unknown queue", ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [RACScheduler.subscriptionScheduler schedule:^{ currentScheduler = RACScheduler.currentScheduler; }]; }); expect(currentScheduler).toEventuallyNot(beNil()); expect(currentScheduler).notTo(equal(RACScheduler.mainThreadScheduler)); }); qck_it(@"should equal the background scheduler from which the block was scheduled", ^{ RACScheduler *backgroundScheduler = [RACScheduler scheduler]; [backgroundScheduler schedule:^{ [RACScheduler.subscriptionScheduler schedule:^{ currentScheduler = RACScheduler.currentScheduler; }]; }]; expect(currentScheduler).toEventually(equal(backgroundScheduler)); }); }); qck_it(@"should execute scheduled blocks immediately if it's in a scheduler already", ^{ __block BOOL done = NO; __block BOOL executedImmediately = NO; [[RACScheduler scheduler] schedule:^{ [RACScheduler.subscriptionScheduler schedule:^{ executedImmediately = YES; }]; done = YES; }]; expect(@(done)).toEventually(beTruthy()); expect(@(executedImmediately)).to(beTruthy()); }); }); qck_describe(@"+immediateScheduler", ^{ qck_it(@"should immediately execute scheduled blocks", ^{ __block BOOL executed = NO; RACDisposable *disposable = [RACScheduler.immediateScheduler schedule:^{ executed = YES; }]; expect(disposable).to(beNil()); expect(@(executed)).to(beTruthy()); }); qck_it(@"should block for future scheduled blocks", ^{ __block BOOL executed = NO; RACDisposable *disposable = [RACScheduler.immediateScheduler after:[NSDate dateWithTimeIntervalSinceNow:0.01] schedule:^{ executed = YES; }]; expect(@(executed)).to(beTruthy()); expect(disposable).to(beNil()); }); }); qck_describe(@"-scheduleRecursiveBlock:", ^{ qck_describe(@"with a synchronous scheduler", ^{ qck_it(@"should behave like a normal block when it doesn't invoke itself", ^{ __block BOOL executed = NO; [RACScheduler.immediateScheduler scheduleRecursiveBlock:^(void (^recurse)(void)) { expect(@(executed)).to(beFalsy()); executed = YES; }]; expect(@(executed)).to(beTruthy()); }); qck_it(@"should reschedule itself after the caller completes", ^{ __block NSUInteger count = 0; [RACScheduler.immediateScheduler scheduleRecursiveBlock:^(void (^recurse)(void)) { NSUInteger thisCount = ++count; if (thisCount < 3) { recurse(); // The block shouldn't have been invoked again yet, only // scheduled. expect(@(count)).to(equal(@(thisCount))); } }]; expect(@(count)).to(equal(@3)); }); qck_it(@"should unroll deep recursion", ^{ static const NSUInteger depth = 100000; __block NSUInteger scheduleCount = 0; [RACScheduler.immediateScheduler scheduleRecursiveBlock:^(void (^recurse)(void)) { scheduleCount++; if (scheduleCount < depth) recurse(); }]; expect(@(scheduleCount)).to(equal(@(depth))); }); }); qck_describe(@"with an asynchronous scheduler", ^{ qck_it(@"should behave like a normal block when it doesn't invoke itself", ^{ __block BOOL executed = NO; [RACScheduler.mainThreadScheduler scheduleRecursiveBlock:^(void (^recurse)(void)) { expect(@(executed)).to(beFalsy()); executed = YES; }]; expect(@(executed)).toEventually(beTruthy()); }); qck_it(@"should reschedule itself after the caller completes", ^{ __block NSUInteger count = 0; [RACScheduler.mainThreadScheduler scheduleRecursiveBlock:^(void (^recurse)(void)) { NSUInteger thisCount = ++count; if (thisCount < 3) { recurse(); // The block shouldn't have been invoked again yet, only // scheduled. expect(@(count)).to(equal(@(thisCount))); } }]; expect(@(count)).toEventually(equal(@3)); }); qck_it(@"should reschedule when invoked asynchronously", ^{ __block NSUInteger count = 0; RACScheduler *asynchronousScheduler = [RACScheduler scheduler]; [RACScheduler.mainThreadScheduler scheduleRecursiveBlock:^(void (^recurse)(void)) { [asynchronousScheduler after:[NSDate dateWithTimeIntervalSinceNow:0.01] schedule:^{ NSUInteger thisCount = ++count; if (thisCount < 3) { recurse(); // The block shouldn't have been invoked again yet, only // scheduled. expect(@(count)).to(equal(@(thisCount))); } }]; }]; expect(@(count)).toEventually(equal(@3)); }); qck_it(@"shouldn't reschedule itself when disposed", ^{ __block NSUInteger count = 0; __block RACDisposable *disposable = [RACScheduler.mainThreadScheduler scheduleRecursiveBlock:^(void (^recurse)(void)) { ++count; expect(disposable).notTo(beNil()); [disposable dispose]; recurse(); }]; expect(@(count)).toEventually(equal(@1)); }); }); }); qck_describe(@"subclassing", ^{ __block RACTestExampleScheduler *scheduler; qck_beforeEach(^{ scheduler = [[RACTestExampleScheduler alloc] initWithQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)]; }); qck_it(@"should invoke blocks scheduled with -schedule:", ^{ __block BOOL invoked = NO; [scheduler schedule:^{ invoked = YES; }]; expect(@(invoked)).toEventually(beTruthy()); }); qck_it(@"should invoke blocks scheduled with -after:schedule:", ^{ __block BOOL invoked = NO; [scheduler after:[NSDate dateWithTimeIntervalSinceNow:0.01] schedule:^{ invoked = YES; }]; expect(@(invoked)).toEventually(beTruthy()); }); qck_it(@"should set a valid current scheduler", ^{ __block RACScheduler *currentScheduler; [scheduler schedule:^{ currentScheduler = RACScheduler.currentScheduler; }]; expect(currentScheduler).toEventually(equal(scheduler)); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACSequenceAdditionsSpec.m ================================================ // // RACSequenceAdditionsSpec.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-11-01. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACSequenceExamples.h" #import "NSArray+RACSequenceAdditions.h" #import "NSDictionary+RACSequenceAdditions.h" #import "NSOrderedSet+RACSequenceAdditions.h" #import "NSSet+RACSequenceAdditions.h" #import "NSString+RACSequenceAdditions.h" #import "NSIndexSet+RACSequenceAdditions.h" #import "RACSequence.h" #import "RACTuple.h" QuickSpecBegin(RACSequenceAdditionsSpec) __block NSArray *numbers; qck_beforeEach(^{ NSMutableArray *mutableNumbers = [NSMutableArray array]; for (NSUInteger i = 0; i < 100; i++) { [mutableNumbers addObject:@(i)]; } numbers = [mutableNumbers copy]; }); qck_describe(@"NSArray sequences", ^{ __block NSMutableArray *values; __block RACSequence *sequence; qck_beforeEach(^{ values = [numbers mutableCopy]; sequence = values.rac_sequence; expect(sequence).notTo(beNil()); }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: sequence, RACSequenceExampleExpectedValues: values }; }); qck_describe(@"should be immutable", ^{ __block NSArray *unchangedValues; qck_beforeEach(^{ unchangedValues = [values copy]; [values addObject:@6]; }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: sequence, RACSequenceExampleExpectedValues: unchangedValues }; }); }); qck_it(@"should fast enumerate after zipping", ^{ // This certain list of values causes issues, for some reason. NSArray *values = @[ @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0, @0 ]; RACSequence *zippedSequence = [RACSequence zip:@[ values.rac_sequence, values.rac_sequence ] reduce:^(id obj1, id obj2) { return obj1; }]; NSMutableArray *collectedValues = [NSMutableArray array]; for (id value in zippedSequence) { [collectedValues addObject:value]; } expect(collectedValues).to(equal(values)); }); }); qck_describe(@"NSDictionary sequences", ^{ __block NSMutableDictionary *dict; __block NSMutableArray *tuples; __block RACSequence *tupleSequence; __block NSArray *keys; __block RACSequence *keySequence; __block NSArray *values; __block RACSequence *valueSequence; qck_beforeEach(^{ dict = [@{ @"foo": @"bar", @"baz": @"buzz", @5: NSNull.null } mutableCopy]; tuples = [NSMutableArray array]; for (id key in dict) { RACTuple *tuple = RACTuplePack(key, dict[key]); [tuples addObject:tuple]; } tupleSequence = dict.rac_sequence; expect(tupleSequence).notTo(beNil()); keys = [dict.allKeys copy]; keySequence = dict.rac_keySequence; expect(keySequence).notTo(beNil()); values = [dict.allValues copy]; valueSequence = dict.rac_valueSequence; expect(valueSequence).notTo(beNil()); }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: tupleSequence, RACSequenceExampleExpectedValues: tuples }; }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: keySequence, RACSequenceExampleExpectedValues: keys }; }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: valueSequence, RACSequenceExampleExpectedValues: values }; }); qck_describe(@"should be immutable", ^{ qck_beforeEach(^{ dict[@"foo"] = @"rab"; dict[@6] = @7; }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: tupleSequence, RACSequenceExampleExpectedValues: tuples }; }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: keySequence, RACSequenceExampleExpectedValues: keys }; }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: valueSequence, RACSequenceExampleExpectedValues: values }; }); }); }); qck_describe(@"NSOrderedSet sequences", ^{ __block NSMutableOrderedSet *values; __block RACSequence *sequence; qck_beforeEach(^{ values = [NSMutableOrderedSet orderedSetWithArray:numbers]; sequence = values.rac_sequence; expect(sequence).notTo(beNil()); }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: sequence, RACSequenceExampleExpectedValues: values.array }; }); qck_describe(@"should be immutable", ^{ __block NSArray *unchangedValues; qck_beforeEach(^{ unchangedValues = [values.array copy]; [values addObject:@6]; }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: sequence, RACSequenceExampleExpectedValues: unchangedValues }; }); }); }); qck_describe(@"NSSet sequences", ^{ __block NSMutableSet *values; __block RACSequence *sequence; qck_beforeEach(^{ values = [NSMutableSet setWithArray:numbers]; sequence = values.rac_sequence; expect(sequence).notTo(beNil()); }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: sequence, RACSequenceExampleExpectedValues: values.allObjects }; }); qck_describe(@"should be immutable", ^{ __block NSArray *unchangedValues; qck_beforeEach(^{ unchangedValues = [values.allObjects copy]; [values addObject:@6]; }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: sequence, RACSequenceExampleExpectedValues: unchangedValues }; }); }); }); qck_describe(@"NSString sequences", ^{ __block NSMutableString *string; __block NSArray *values; __block RACSequence *sequence; qck_beforeEach(^{ string = [@"foobar" mutableCopy]; values = @[ @"f", @"o", @"o", @"b", @"a", @"r" ]; sequence = string.rac_sequence; expect(sequence).notTo(beNil()); }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: sequence, RACSequenceExampleExpectedValues: values }; }); qck_describe(@"should be immutable", ^{ qck_beforeEach(^{ [string appendString:@"buzz"]; }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: sequence, RACSequenceExampleExpectedValues: values }; }); }); qck_it(@"should work with composed characters", ^{ NSString *string = @"\u2665\uFE0F\u2666\uFE0F"; NSArray *expectedSequence = @[ @"\u2665\uFE0F", @"\u2666\uFE0F" ]; expect(string.rac_sequence.array).to(equal(expectedSequence)); }); }); qck_describe(@"RACTuple sequences", ^{ __block RACTuple *tuple; __block RACSequence *sequence; qck_beforeEach(^{ tuple = RACTuplePack(@"foo", nil, @"bar", NSNull.null, RACTupleNil.tupleNil); sequence = tuple.rac_sequence; expect(sequence).notTo(beNil()); }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: sequence, RACSequenceExampleExpectedValues: @[ @"foo", NSNull.null, @"bar", NSNull.null, NSNull.null ] }; }); }); qck_describe(@"NSIndexSet sequences", ^{ __block NSMutableIndexSet *values; __block RACSequence *sequence; NSArray * (^valuesFromIndexSet)(NSIndexSet *indexSet) = ^NSArray *(NSIndexSet *indexSet) { NSMutableArray *arr = [NSMutableArray array]; [indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { [arr addObject:@(idx)]; }]; return [arr copy]; }; qck_beforeEach(^{ values = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 10)]; sequence = values.rac_sequence; expect(sequence).notTo(beNil()); }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: sequence, RACSequenceExampleExpectedValues: valuesFromIndexSet(values) }; }); qck_describe(@"should be immutable", ^{ __block NSArray *unchangedValues; qck_beforeEach(^{ unchangedValues = valuesFromIndexSet(values); [values addIndex:20]; }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: sequence, RACSequenceExampleExpectedValues: unchangedValues }; }); }); qck_describe(@"should not fire if empty", ^{ __block NSIndexSet *emptyIndexSet; __block RACSequence *emptySequence; qck_beforeEach(^{ emptyIndexSet = [NSIndexSet indexSet]; emptySequence = emptyIndexSet.rac_sequence; expect(emptySequence).notTo(beNil()); }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: emptySequence, RACSequenceExampleExpectedValues: valuesFromIndexSet(emptyIndexSet) }; }); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACSequenceExamples.h ================================================ // // RACSequenceExamples.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-11-01. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // // The name of the shared examples for RACSequence instances. extern NSString * const RACSequenceExamples; // RACSequence * extern NSString * const RACSequenceExampleSequence; // NSArray * extern NSString * const RACSequenceExampleExpectedValues; ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACSequenceExamples.m ================================================ // // RACSequenceExamples.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-11-01. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACSequenceExamples.h" #import "RACScheduler.h" #import "RACSequence.h" #import "RACSignal+Operations.h" NSString * const RACSequenceExamples = @"RACSequenceExamples"; NSString * const RACSequenceExampleSequence = @"RACSequenceExampleSequence"; NSString * const RACSequenceExampleExpectedValues = @"RACSequenceExampleExpectedValues"; QuickConfigurationBegin(RACSequenceExampleGroups) + (void)configure:(Configuration *)configuration { sharedExamples(RACSequenceExamples, ^(QCKDSLSharedExampleContext exampleContext) { __block RACSequence *sequence; __block NSArray *values; qck_beforeEach(^{ sequence = exampleContext()[RACSequenceExampleSequence]; values = [exampleContext()[RACSequenceExampleExpectedValues] copy]; }); qck_it(@"should implement ", ^{ NSMutableArray *collectedValues = [NSMutableArray array]; for (id value in sequence) { [collectedValues addObject:value]; } expect(collectedValues).to(equal(values)); }); qck_it(@"should return an array", ^{ expect(sequence.array).to(equal(values)); }); qck_describe(@"-signalWithScheduler:", ^{ qck_it(@"should return an immediately scheduled signal", ^{ RACSignal *signal = [sequence signalWithScheduler:RACScheduler.immediateScheduler]; expect(signal.toArray).to(equal(values)); }); qck_it(@"should return a background scheduled signal", ^{ RACSignal *signal = [sequence signalWithScheduler:[RACScheduler scheduler]]; expect(signal.toArray).to(equal(values)); }); qck_it(@"should only evaluate one value per scheduling", ^{ RACScheduler* scheduler = [RACScheduler schedulerWithPriority:RACSchedulerPriorityHigh]; RACSignal *signal = [sequence signalWithScheduler:scheduler]; __block BOOL flag = YES; __block BOOL completed = NO; [signal subscribeNext:^(id x) { expect(@(flag)).to(beTruthy()); flag = NO; [scheduler schedule:^{ // This should get executed before the next value (which // verifies that it's YES). flag = YES; }]; } completed:^{ completed = YES; }]; expect(@(completed)).toEventually(beTruthy()); }); }); qck_it(@"should be equal to itself", ^{ expect(sequence).to(equal(sequence)); }); qck_it(@"should be equal to the same sequence of values", ^{ RACSequence *newSequence = RACSequence.empty; for (id value in values) { RACSequence *valueSeq = [RACSequence return:value]; expect(valueSeq).notTo(beNil()); newSequence = [newSequence concat:valueSeq]; } expect(sequence).to(equal(newSequence)); expect(@(sequence.hash)).to(equal(@(newSequence.hash))); }); qck_it(@"should not be equal to a different sequence of values", ^{ RACSequence *anotherSequence = [RACSequence return:@(-1)]; expect(sequence).notTo(equal(anotherSequence)); }); qck_it(@"should return an identical object for -copy", ^{ expect([sequence copy]).to(beIdenticalTo(sequence)); }); qck_it(@"should archive", ^{ NSData *data = [NSKeyedArchiver archivedDataWithRootObject:sequence]; expect(data).notTo(beNil()); RACSequence *unarchived = [NSKeyedUnarchiver unarchiveObjectWithData:data]; expect(unarchived).to(equal(sequence)); }); qck_it(@"should fold right", ^{ RACSequence *result = [sequence foldRightWithStart:[RACSequence empty] reduce:^(id first, RACSequence *rest) { return [rest.head startWith:first]; }]; expect(result.array).to(equal(values)); }); qck_it(@"should fold left", ^{ RACSequence *result = [sequence foldLeftWithStart:[RACSequence empty] reduce:^(RACSequence *first, id rest) { return [first concat:[RACSequence return:rest]]; }]; expect(result.array).to(equal(values)); }); }); } QuickConfigurationEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACSequenceSpec.m ================================================ // // RACSequenceSpec.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-11-01. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACSequenceExamples.h" #import "RACStreamExamples.h" #import "NSArray+RACSequenceAdditions.h" #import "NSObject+RACDeallocating.h" #import "NSObject+RACPropertySubscribing.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACSequence.h" #import "RACUnit.h" QuickSpecBegin(RACSequenceSpec) qck_describe(@"RACStream", ^{ id verifyValues = ^(RACSequence *sequence, NSArray *expectedValues) { NSMutableArray *collectedValues = [NSMutableArray array]; while (sequence.head != nil) { [collectedValues addObject:sequence.head]; sequence = sequence.tail; } expect(collectedValues).to(equal(expectedValues)); }; __block RACSequence *infiniteSequence = [RACSequence sequenceWithHeadBlock:^{ return RACUnit.defaultUnit; } tailBlock:^{ return infiniteSequence; }]; qck_itBehavesLike(RACStreamExamples, ^{ return @{ RACStreamExamplesClass: RACSequence.class, RACStreamExamplesVerifyValuesBlock: verifyValues, RACStreamExamplesInfiniteStream: infiniteSequence }; }); }); qck_describe(@"+sequenceWithHeadBlock:tailBlock:", ^{ __block RACSequence *sequence; __block BOOL headInvoked; __block BOOL tailInvoked; qck_beforeEach(^{ headInvoked = NO; tailInvoked = NO; sequence = [RACSequence sequenceWithHeadBlock:^{ headInvoked = YES; return @0; } tailBlock:^{ tailInvoked = YES; return [RACSequence return:@1]; }]; expect(sequence).notTo(beNil()); }); qck_it(@"should use the values from the head and tail blocks", ^{ expect(sequence.head).to(equal(@0)); expect(sequence.tail.head).to(equal(@1)); expect(sequence.tail.tail).to(beNil()); }); qck_it(@"should lazily invoke head and tail blocks", ^{ expect(@(headInvoked)).to(beFalsy()); expect(@(tailInvoked)).to(beFalsy()); expect(sequence.head).to(equal(@0)); expect(@(headInvoked)).to(beTruthy()); expect(@(tailInvoked)).to(beFalsy()); expect(sequence.tail).notTo(beNil()); expect(@(tailInvoked)).to(beTruthy()); }); qck_afterEach(^{ qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: sequence, RACSequenceExampleExpectedValues: @[ @0, @1 ] }; }); }); }); qck_describe(@"empty sequences", ^{ qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: [RACSequence empty], RACSequenceExampleExpectedValues: @[] }; }); }); qck_describe(@"non-empty sequences", ^{ qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: [[[RACSequence return:@0] concat:[RACSequence return:@1]] concat:[RACSequence return:@2]], RACSequenceExampleExpectedValues: @[ @0, @1, @2 ] }; }); }); qck_describe(@"eager sequences", ^{ __block RACSequence *lazySequence; __block BOOL headInvoked; __block BOOL tailInvoked; NSArray *values = @[ @0, @1 ]; qck_beforeEach(^{ headInvoked = NO; tailInvoked = NO; lazySequence = [RACSequence sequenceWithHeadBlock:^{ headInvoked = YES; return @0; } tailBlock:^{ tailInvoked = YES; return [RACSequence return:@1]; }]; expect(lazySequence).notTo(beNil()); }); qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: lazySequence.eagerSequence, RACSequenceExampleExpectedValues: values }; }); qck_it(@"should evaluate all values immediately", ^{ RACSequence *eagerSequence = lazySequence.eagerSequence; expect(@(headInvoked)).to(beTruthy()); expect(@(tailInvoked)).to(beTruthy()); expect(eagerSequence.array).to(equal(values)); }); }); qck_describe(@"-take:", ^{ qck_it(@"should complete take: without needing the head of the second item in the sequence", ^{ __block NSUInteger valuesTaken = 0; __block RACSequence *sequence = [RACSequence sequenceWithHeadBlock:^{ ++valuesTaken; return RACUnit.defaultUnit; } tailBlock:^{ return sequence; }]; NSArray *values = [sequence take:1].array; expect(values).to(equal(@[ RACUnit.defaultUnit ])); expect(@(valuesTaken)).to(equal(@1)); }); }); qck_describe(@"-bind:", ^{ qck_it(@"should only evaluate head when the resulting sequence is evaluated", ^{ __block BOOL headInvoked = NO; RACSequence *original = [RACSequence sequenceWithHeadBlock:^{ headInvoked = YES; return RACUnit.defaultUnit; } tailBlock:^ id { return nil; }]; RACSequence *bound = [original bind:^{ return ^(id value, BOOL *stop) { return [RACSequence return:value]; }; }]; expect(bound).notTo(beNil()); expect(@(headInvoked)).to(beFalsy()); expect(bound.head).to(equal(RACUnit.defaultUnit)); expect(@(headInvoked)).to(beTruthy()); }); }); qck_describe(@"-objectEnumerator", ^{ qck_it(@"should only evaluate head as it's enumerated", ^{ __block BOOL firstHeadInvoked = NO; __block BOOL secondHeadInvoked = NO; __block BOOL thirdHeadInvoked = NO; RACSequence *sequence = [RACSequence sequenceWithHeadBlock:^id{ firstHeadInvoked = YES; return @1; } tailBlock:^RACSequence *{ return [RACSequence sequenceWithHeadBlock:^id{ secondHeadInvoked = YES; return @2; } tailBlock:^RACSequence *{ return [RACSequence sequenceWithHeadBlock:^id{ thirdHeadInvoked = YES; return @3; } tailBlock:^RACSequence *{ return RACSequence.empty; }]; }]; }]; NSEnumerator *enumerator = sequence.objectEnumerator; expect(@(firstHeadInvoked)).to(beFalsy()); expect(@(secondHeadInvoked)).to(beFalsy()); expect(@(thirdHeadInvoked)).to(beFalsy()); expect([enumerator nextObject]).to(equal(@1)); expect(@(firstHeadInvoked)).to(beTruthy()); expect(@(secondHeadInvoked)).to(beFalsy()); expect(@(thirdHeadInvoked)).to(beFalsy()); expect([enumerator nextObject]).to(equal(@2)); expect(@(secondHeadInvoked)).to(beTruthy()); expect(@(thirdHeadInvoked)).to(beFalsy()); expect([enumerator nextObject]).to(equal(@3)); expect(@(thirdHeadInvoked)).to(beTruthy()); expect([enumerator nextObject]).to(beNil()); }); qck_it(@"should let the sequence dealloc as it's enumerated", ^{ __block BOOL firstSequenceDeallocd = NO; __block BOOL secondSequenceDeallocd = NO; __block BOOL thirdSequenceDeallocd = NO; NSEnumerator *enumerator = nil; @autoreleasepool { RACSequence *thirdSequence __attribute__((objc_precise_lifetime)) = [RACSequence sequenceWithHeadBlock:^id{ return @3; } tailBlock:^RACSequence *{ return RACSequence.empty; }]; [thirdSequence.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ thirdSequenceDeallocd = YES; }]]; RACSequence *secondSequence __attribute__((objc_precise_lifetime)) = [RACSequence sequenceWithHeadBlock:^id{ return @2; } tailBlock:^RACSequence *{ return thirdSequence; }]; [secondSequence.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ secondSequenceDeallocd = YES; }]]; RACSequence *firstSequence __attribute__((objc_precise_lifetime)) = [RACSequence sequenceWithHeadBlock:^id{ return @1; } tailBlock:^RACSequence *{ return secondSequence; }]; [firstSequence.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ firstSequenceDeallocd = YES; }]]; enumerator = firstSequence.objectEnumerator; } @autoreleasepool { expect([enumerator nextObject]).to(equal(@1)); } @autoreleasepool { expect([enumerator nextObject]).to(equal(@2)); } expect(@(firstSequenceDeallocd)).toEventually(beTruthy()); @autoreleasepool { expect([enumerator nextObject]).to(equal(@3)); } expect(@(secondSequenceDeallocd)).toEventually(beTruthy()); @autoreleasepool { expect([enumerator nextObject]).to(beNil()); } expect(@(thirdSequenceDeallocd)).toEventually(beTruthy()); }); }); qck_it(@"shouldn't overflow the stack when deallocated on a background queue", ^{ NSUInteger length = 10000; NSMutableArray *values = [NSMutableArray arrayWithCapacity:length]; for (NSUInteger i = 0; i < length; ++i) { [values addObject:@(i)]; } __block BOOL finished = NO; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @autoreleasepool { (void)[[values.rac_sequence map:^(id value) { return value; }] array]; } finished = YES; }); expect(@(finished)).toEventually(beTruthy()); }); qck_describe(@"-foldLeftWithStart:reduce:", ^{ qck_it(@"should reduce with start first", ^{ RACSequence *sequence = [[[RACSequence return:@0] concat:[RACSequence return:@1]] concat:[RACSequence return:@2]]; NSNumber *result = [sequence foldLeftWithStart:@3 reduce:^(NSNumber *first, NSNumber *rest) { return first; }]; expect(result).to(equal(@3)); }); qck_it(@"should be left associative", ^{ RACSequence *sequence = [[[RACSequence return:@1] concat:[RACSequence return:@2]] concat:[RACSequence return:@3]]; NSNumber *result = [sequence foldLeftWithStart:@0 reduce:^(NSNumber *first, NSNumber *rest) { int difference = first.intValue - rest.intValue; return @(difference); }]; expect(result).to(equal(@-6)); }); }); qck_describe(@"-foldRightWithStart:reduce:", ^{ qck_it(@"should be lazy", ^{ __block BOOL headInvoked = NO; __block BOOL tailInvoked = NO; RACSequence *sequence = [RACSequence sequenceWithHeadBlock:^{ headInvoked = YES; return @0; } tailBlock:^{ tailInvoked = YES; return [RACSequence return:@1]; }]; NSNumber *result = [sequence foldRightWithStart:@2 reduce:^(NSNumber *first, RACSequence *rest) { return first; }]; expect(result).to(equal(@0)); expect(@(headInvoked)).to(beTruthy()); expect(@(tailInvoked)).to(beFalsy()); }); qck_it(@"should reduce with start last", ^{ RACSequence *sequence = [[[RACSequence return:@0] concat:[RACSequence return:@1]] concat:[RACSequence return:@2]]; NSNumber *result = [sequence foldRightWithStart:@3 reduce:^(NSNumber *first, RACSequence *rest) { return rest.head; }]; expect(result).to(equal(@3)); }); qck_it(@"should be right associative", ^{ RACSequence *sequence = [[[RACSequence return:@1] concat:[RACSequence return:@2]] concat:[RACSequence return:@3]]; NSNumber *result = [sequence foldRightWithStart:@0 reduce:^(NSNumber *first, RACSequence *rest) { int difference = first.intValue - [rest.head intValue]; return @(difference); }]; expect(result).to(equal(@2)); }); }); qck_describe(@"-any", ^{ __block RACSequence *sequence; qck_beforeEach(^{ sequence = [[[RACSequence return:@0] concat:[RACSequence return:@1]] concat:[RACSequence return:@2]]; }); qck_it(@"should return true when at least one exists", ^{ BOOL result = [sequence any:^ BOOL (NSNumber *value) { return value.integerValue > 0; }]; expect(@(result)).to(beTruthy()); }); qck_it(@"should return false when no such thing exists", ^{ BOOL result = [sequence any:^ BOOL (NSNumber *value) { return value.integerValue == 3; }]; expect(@(result)).to(beFalsy()); }); }); qck_describe(@"-all", ^{ __block RACSequence *sequence; qck_beforeEach(^{ sequence = [[[RACSequence return:@0] concat:[RACSequence return:@1]] concat:[RACSequence return:@2]]; }); qck_it(@"should return true when all values pass", ^{ BOOL result = [sequence all:^ BOOL (NSNumber *value) { return value.integerValue >= 0; }]; expect(@(result)).to(beTruthy()); }); qck_it(@"should return false when at least one value fails", ^{ BOOL result = [sequence all:^ BOOL (NSNumber *value) { return value.integerValue < 2; }]; expect(@(result)).to(beFalsy()); }); }); qck_describe(@"-objectPassingTest:", ^{ __block RACSequence *sequence; qck_beforeEach(^{ sequence = [[[RACSequence return:@0] concat:[RACSequence return:@1]] concat:[RACSequence return:@2]]; }); qck_it(@"should return leftmost object that passes the test", ^{ NSNumber *result = [sequence objectPassingTest:^ BOOL (NSNumber *value) { return value.intValue > 0; }]; expect(result).to(equal(@1)); }); qck_it(@"should return nil if no objects pass the test", ^{ NSNumber *result = [sequence objectPassingTest:^ BOOL (NSNumber *value) { return value.intValue < 0; }]; expect(result).to(beNil()); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACSerialDisposableSpec.m ================================================ // // RACSerialDisposableSpec.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-07-22. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "RACSerialDisposable.h" QuickSpecBegin(RACSerialDisposableSpec) qck_it(@"should initialize with -init", ^{ RACSerialDisposable *serial = [[RACSerialDisposable alloc] init]; expect(serial).notTo(beNil()); expect(serial.disposable).to(beNil()); }); qck_it(@"should initialize an inner disposable with -initWithBlock:", ^{ __block BOOL disposed = NO; RACSerialDisposable *serial = [RACSerialDisposable disposableWithBlock:^{ disposed = YES; }]; expect(serial).notTo(beNil()); expect(serial.disposable).notTo(beNil()); [serial.disposable dispose]; expect(@(serial.disposed)).to(beFalsy()); expect(@(disposed)).to(beTruthy()); }); qck_it(@"should initialize with a disposable", ^{ RACDisposable *inner = [[RACDisposable alloc] init]; RACSerialDisposable *serial = [RACSerialDisposable serialDisposableWithDisposable:inner]; expect(serial).notTo(beNil()); expect(serial.disposable).to(equal(inner)); }); qck_it(@"should dispose of the inner disposable", ^{ __block BOOL disposed = NO; RACDisposable *inner = [RACDisposable disposableWithBlock:^{ disposed = YES; }]; RACSerialDisposable *serial = [RACSerialDisposable serialDisposableWithDisposable:inner]; expect(@(serial.disposed)).to(beFalsy()); expect(@(disposed)).to(beFalsy()); [serial dispose]; expect(@(serial.disposed)).to(beTruthy()); expect(serial.disposable).to(beNil()); expect(@(disposed)).to(beTruthy()); }); qck_it(@"should dispose of a new inner disposable if it's already been disposed", ^{ __block BOOL disposed = NO; RACDisposable *inner = [RACDisposable disposableWithBlock:^{ disposed = YES; }]; RACSerialDisposable *serial = [[RACSerialDisposable alloc] init]; expect(@(serial.disposed)).to(beFalsy()); [serial dispose]; expect(@(serial.disposed)).to(beTruthy()); expect(@(disposed)).to(beFalsy()); serial.disposable = inner; expect(@(disposed)).to(beTruthy()); expect(serial.disposable).to(beNil()); }); qck_it(@"should allow the inner disposable to be set to nil", ^{ __block BOOL disposed = NO; RACDisposable *inner = [RACDisposable disposableWithBlock:^{ disposed = YES; }]; RACSerialDisposable *serial = [RACSerialDisposable serialDisposableWithDisposable:inner]; expect(@(disposed)).to(beFalsy()); serial.disposable = nil; expect(serial.disposable).to(beNil()); serial.disposable = inner; expect(serial.disposable).to(equal(inner)); [serial dispose]; expect(@(disposed)).to(beTruthy()); expect(serial.disposable).to(beNil()); }); qck_it(@"should swap inner disposables", ^{ __block BOOL firstDisposed = NO; RACDisposable *first = [RACDisposable disposableWithBlock:^{ firstDisposed = YES; }]; __block BOOL secondDisposed = NO; RACDisposable *second = [RACDisposable disposableWithBlock:^{ secondDisposed = YES; }]; RACSerialDisposable *serial = [RACSerialDisposable serialDisposableWithDisposable:first]; expect([serial swapInDisposable:second]).to(equal(first)); expect(@(serial.disposed)).to(beFalsy()); expect(@(firstDisposed)).to(beFalsy()); expect(@(secondDisposed)).to(beFalsy()); [serial dispose]; expect(@(serial.disposed)).to(beTruthy()); expect(serial.disposable).to(beNil()); expect(@(firstDisposed)).to(beFalsy()); expect(@(secondDisposed)).to(beTruthy()); }); qck_it(@"should release the inner disposable upon deallocation", ^{ __weak RACDisposable *weakInnerDisposable; __weak RACSerialDisposable *weakSerialDisposable; @autoreleasepool { RACDisposable *innerDisposable __attribute__((objc_precise_lifetime)) = [[RACDisposable alloc] init]; weakInnerDisposable = innerDisposable; RACSerialDisposable *serialDisposable __attribute__((objc_precise_lifetime)) = [[RACSerialDisposable alloc] init]; serialDisposable.disposable = innerDisposable; weakSerialDisposable = serialDisposable; } expect(weakSerialDisposable).to(beNil()); expect(weakInnerDisposable).to(beNil()); }); qck_it(@"should not crash when racing between swapInDisposable and disposable", ^{ __block BOOL stop = NO; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (long long)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ stop = YES; }); RACSerialDisposable *serialDisposable = [[RACSerialDisposable alloc] init]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ while (!stop) { [serialDisposable swapInDisposable:[RACDisposable disposableWithBlock:^{}]]; } }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ while (!stop) { (void)[serialDisposable disposable]; } }); expect(@(stop)).toEventually(beTruthy()); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACSignalSpec.m ================================================ // // RACSignalSpec.m // ReactiveCocoa // // Created by Josh Abernathy on 3/2/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACPropertySignalExamples.h" #import "RACSequenceExamples.h" #import "RACStreamExamples.h" #import "RACTestObject.h" #import #import "NSObject+RACDeallocating.h" #import "NSObject+RACPropertySubscribing.h" #import "RACBehaviorSubject.h" #import "RACCommand.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACEvent.h" #import "RACGroupedSignal.h" #import "RACMulticastConnection.h" #import "RACReplaySubject.h" #import "RACScheduler.h" #import "RACSignal+Operations.h" #import "RACSubject.h" #import "RACSubscriber+Private.h" #import "RACSubscriber.h" #import "RACTestScheduler.h" #import "RACTuple.h" #import "RACUnit.h" #import // Set in a beforeAll below. static NSError *RACSignalTestError; static NSString * const RACSignalMergeConcurrentCompletionExampleGroup = @"RACSignalMergeConcurrentCompletionExampleGroup"; static NSString * const RACSignalMaxConcurrent = @"RACSignalMaxConcurrent"; QuickConfigurationBegin(mergeConcurrentCompletionName) + (void)configure:(Configuration *)configuration { sharedExamples(RACSignalMergeConcurrentCompletionExampleGroup, ^(QCKDSLSharedExampleContext exampleContext) { qck_it(@"should complete only after the source and all its signals have completed", ^{ RACSubject *subject1 = [RACSubject subject]; RACSubject *subject2 = [RACSubject subject]; RACSubject *subject3 = [RACSubject subject]; RACSubject *signalsSubject = [RACSubject subject]; __block BOOL completed = NO; [[signalsSubject flatten:[exampleContext()[RACSignalMaxConcurrent] unsignedIntegerValue]] subscribeCompleted:^{ completed = YES; }]; [signalsSubject sendNext:subject1]; [subject1 sendCompleted]; expect(@(completed)).to(beFalsy()); [signalsSubject sendNext:subject2]; [signalsSubject sendNext:subject3]; [signalsSubject sendCompleted]; expect(@(completed)).to(beFalsy()); [subject2 sendCompleted]; expect(@(completed)).to(beFalsy()); [subject3 sendCompleted]; expect(@(completed)).to(beTruthy()); }); }); } QuickConfigurationEnd QuickSpecBegin(RACSignalSpec) qck_beforeSuite(^{ // We do this instead of a macro to ensure that to(equal() will work // correctly (by matching identity), even if -[NSError isEqual:] is broken. RACSignalTestError = [NSError errorWithDomain:@"foo" code:100 userInfo:nil]; }); qck_describe(@"RACStream", ^{ id verifyValues = ^(RACSignal *signal, NSArray *expectedValues) { expect(signal).notTo(beNil()); NSMutableArray *collectedValues = [NSMutableArray array]; __block BOOL success = NO; __block NSError *error = nil; [signal subscribeNext:^(id value) { [collectedValues addObject:value]; } error:^(NSError *receivedError) { error = receivedError; } completed:^{ success = YES; }]; expect(@(success)).toEventually(beTruthy()); expect(error).to(beNil()); expect(collectedValues).to(equal(expectedValues)); }; RACSignal *infiniteSignal = [RACSignal createSignal:^(id subscriber) { __block volatile int32_t done = 0; [RACScheduler.mainThreadScheduler schedule:^{ while (!done) { [subscriber sendNext:RACUnit.defaultUnit]; } }]; return [RACDisposable disposableWithBlock:^{ OSAtomicIncrement32Barrier(&done); }]; }]; qck_itBehavesLike(RACStreamExamples, ^{ return @{ RACStreamExamplesClass: RACSignal.class, RACStreamExamplesVerifyValuesBlock: verifyValues, RACStreamExamplesInfiniteStream: infiniteSignal }; }); }); qck_describe(@"-bind:", ^{ __block RACSubject *signals; __block BOOL disposed; __block id lastValue; __block RACSubject *values; qck_beforeEach(^{ // Tests send a (RACSignal, BOOL) pair that are used below in -bind:. signals = [RACSubject subject]; disposed = NO; RACSignal *source = [RACSignal createSignal:^(id subscriber) { [signals subscribe:subscriber]; return [RACDisposable disposableWithBlock:^{ disposed = YES; }]; }]; RACSignal *bind = [source bind:^{ return ^(RACTuple *x, BOOL *stop) { RACTupleUnpack(RACSignal *signal, NSNumber *stopValue) = x; *stop = stopValue.boolValue; return signal; }; }]; lastValue = nil; [bind subscribeNext:^(id x) { lastValue = x; }]; // Send `bind` an open ended subject to subscribe to( These tests make // use of this in two ways: // 1. Used to test a regression bug where -bind: would not actually // stop when instructed to. This bug manifested itself only when // there were subscriptions that lived on past the point at which // -bind: was stopped. This subject represents such a subscription. // 2. Test that values sent by this subject are received by `bind`'s // subscriber, even *after* -bind: has been instructed to stop. values = [RACSubject subject]; [signals sendNext:RACTuplePack(values, @NO)]; expect(@(disposed)).to(beFalsy()); }); qck_it(@"should dispose source signal when stopped with nil signal", ^{ // Tell -bind: to stop by sending it a `nil` signal. [signals sendNext:RACTuplePack(nil, @NO)]; expect(@(disposed)).to(beTruthy()); // Should still receive values sent after stopping. expect(lastValue).to(beNil()); [values sendNext:RACUnit.defaultUnit]; expect(lastValue).to(equal(RACUnit.defaultUnit)); }); qck_it(@"should dispose source signal when stop flag set to YES", ^{ // Tell -bind: to stop by setting the stop flag to YES. [signals sendNext:RACTuplePack([RACSignal return:@1], @YES)]; expect(@(disposed)).to(beTruthy()); // Should still recieve last signal sent at the time of setting stop to YES. expect(lastValue).to(equal(@1)); // Should still receive values sent after stopping. [values sendNext:@2]; expect(lastValue).to(equal(@2)); }); qck_it(@"should properly stop subscribing to new signals after error", ^{ RACSignal *signal = [RACSignal createSignal:^ id (id subscriber) { [subscriber sendNext:@0]; [subscriber sendNext:@1]; return nil; }]; __block BOOL subscribedAfterError = NO; RACSignal *bind = [signal bind:^{ return ^(NSNumber *x, BOOL *stop) { if (x.integerValue == 0) return [RACSignal error:nil]; return [RACSignal defer:^{ subscribedAfterError = YES; return [RACSignal empty]; }]; }; }]; [bind subscribeCompleted:^{}]; expect(@(subscribedAfterError)).to(beFalsy()); }); qck_it(@"should not subscribe to signals following error in +merge:", ^{ __block BOOL firstSubscribed = NO; __block BOOL secondSubscribed = NO; __block BOOL errored = NO; RACSignal *signal = [[RACSignal merge:@[ [RACSignal defer:^{ firstSubscribed = YES; return [RACSignal error:nil]; }], [RACSignal defer:^{ secondSubscribed = YES; return [RACSignal return:nil]; }] ]] doError:^(NSError *error) { errored = YES; }]; [signal subscribeCompleted:^{}]; expect(@(firstSubscribed)).to(beTruthy()); expect(@(secondSubscribed)).to(beFalsy()); expect(@(errored)).to(beTruthy()); }); }); qck_describe(@"subscribing", ^{ __block RACSignal *signal = nil; id nextValueSent = @"1"; qck_beforeEach(^{ signal = [RACSignal createSignal:^ RACDisposable * (id subscriber) { [subscriber sendNext:nextValueSent]; [subscriber sendCompleted]; return nil; }]; }); qck_it(@"should get next values", ^{ __block id nextValueReceived = nil; [signal subscribeNext:^(id x) { nextValueReceived = x; } error:^(NSError *error) { } completed:^{ }]; expect(nextValueReceived).to(equal(nextValueSent)); }); qck_it(@"should get completed", ^{ __block BOOL didGetCompleted = NO; [signal subscribeNext:^(id x) { } error:^(NSError *error) { } completed:^{ didGetCompleted = YES; }]; expect(@(didGetCompleted)).to(beTruthy()); }); qck_it(@"should not get an error", ^{ __block BOOL didGetError = NO; [signal subscribeNext:^(id x) { } error:^(NSError *error) { didGetError = YES; } completed:^{ }]; expect(@(didGetError)).to(beFalsy()); }); qck_it(@"shouldn't get anything after dispose", ^{ RACTestScheduler *scheduler = [[RACTestScheduler alloc] init]; NSMutableArray *receivedValues = [NSMutableArray array]; RACSignal *signal = [RACSignal createSignal:^ id (id subscriber) { [subscriber sendNext:@0]; [scheduler afterDelay:0 schedule:^{ [subscriber sendNext:@1]; }]; return nil; }]; RACDisposable *disposable = [signal subscribeNext:^(id x) { [receivedValues addObject:x]; }]; NSArray *expectedValues = @[ @0 ]; expect(receivedValues).to(equal(expectedValues)); [disposable dispose]; [scheduler stepAll]; expect(receivedValues).to(equal(expectedValues)); }); qck_it(@"should have a current scheduler in didSubscribe block", ^{ __block RACScheduler *currentScheduler; RACSignal *signal = [RACSignal createSignal:^ RACDisposable * (id subscriber) { currentScheduler = RACScheduler.currentScheduler; [subscriber sendCompleted]; return nil; }]; [signal subscribeNext:^(id x) {}]; expect(currentScheduler).notTo(beNil()); currentScheduler = nil; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [signal subscribeNext:^(id x) {}]; }); expect(currentScheduler).toEventuallyNot(beNil()); }); qck_it(@"should automatically dispose of other subscriptions from +createSignal:", ^{ __block BOOL innerDisposed = NO; __block id innerSubscriber = nil; RACSignal *innerSignal = [RACSignal createSignal:^(id subscriber) { // Keep the subscriber alive so it doesn't trigger disposal on dealloc innerSubscriber = subscriber; return [RACDisposable disposableWithBlock:^{ innerDisposed = YES; }]; }]; RACSignal *outerSignal = [RACSignal createSignal:^ RACDisposable * (id subscriber) { [innerSignal subscribe:subscriber]; return nil; }]; RACDisposable *disposable = [outerSignal subscribeCompleted:^{}]; expect(disposable).notTo(beNil()); expect(@(innerDisposed)).to(beFalsy()); [disposable dispose]; expect(@(innerDisposed)).to(beTruthy()); }); }); qck_describe(@"-takeUntil:", ^{ qck_it(@"should support value as trigger", ^{ __block BOOL shouldBeGettingItems = YES; RACSubject *subject = [RACSubject subject]; RACSubject *cutOffSubject = [RACSubject subject]; [[subject takeUntil:cutOffSubject] subscribeNext:^(id x) { expect(@(shouldBeGettingItems)).to(beTruthy()); }]; shouldBeGettingItems = YES; [subject sendNext:@"test 1"]; [subject sendNext:@"test 2"]; [cutOffSubject sendNext:[RACUnit defaultUnit]]; shouldBeGettingItems = NO; [subject sendNext:@"test 3"]; }); qck_it(@"should support completion as trigger", ^{ __block BOOL shouldBeGettingItems = YES; RACSubject *subject = [RACSubject subject]; RACSubject *cutOffSubject = [RACSubject subject]; [[subject takeUntil:cutOffSubject] subscribeNext:^(id x) { expect(@(shouldBeGettingItems)).to(beTruthy()); }]; [cutOffSubject sendCompleted]; shouldBeGettingItems = NO; [subject sendNext:@"should not go through"]; }); qck_it(@"should squelch any values sent immediately upon subscription", ^{ RACSignal *valueSignal = [RACSignal return:RACUnit.defaultUnit]; RACSignal *cutOffSignal = [RACSignal empty]; __block BOOL gotNext = NO; __block BOOL completed = NO; [[valueSignal takeUntil:cutOffSignal] subscribeNext:^(id _) { gotNext = YES; } completed:^{ completed = YES; }]; expect(@(gotNext)).to(beFalsy()); expect(@(completed)).to(beTruthy()); }); }); qck_describe(@"-takeUntilReplacement:", ^{ qck_it(@"should forward values from the receiver until it's replaced", ^{ RACSubject *receiver = [RACSubject subject]; RACSubject *replacement = [RACSubject subject]; NSMutableArray *receivedValues = [NSMutableArray array]; [[receiver takeUntilReplacement:replacement] subscribeNext:^(id x) { [receivedValues addObject:x]; }]; expect(receivedValues).to(equal(@[])); [receiver sendNext:@1]; expect(receivedValues).to(equal(@[ @1 ])); [receiver sendNext:@2]; expect(receivedValues).to(equal((@[ @1, @2 ]))); [replacement sendNext:@3]; expect(receivedValues).to(equal((@[ @1, @2, @3 ]))); [receiver sendNext:@4]; expect(receivedValues).to(equal((@[ @1, @2, @3 ]))); [replacement sendNext:@5]; expect(receivedValues).to(equal((@[ @1, @2, @3, @5 ]))); }); qck_it(@"should forward error from the receiver", ^{ RACSubject *receiver = [RACSubject subject]; __block BOOL receivedError = NO; [[receiver takeUntilReplacement:RACSignal.never] subscribeError:^(NSError *error) { receivedError = YES; }]; [receiver sendError:nil]; expect(@(receivedError)).to(beTruthy()); }); qck_it(@"should not forward completed from the receiver", ^{ RACSubject *receiver = [RACSubject subject]; __block BOOL receivedCompleted = NO; [[receiver takeUntilReplacement:RACSignal.never] subscribeCompleted: ^{ receivedCompleted = YES; }]; [receiver sendCompleted]; expect(@(receivedCompleted)).to(beFalsy()); }); qck_it(@"should forward error from the replacement signal", ^{ RACSubject *replacement = [RACSubject subject]; __block BOOL receivedError = NO; [[RACSignal.never takeUntilReplacement:replacement] subscribeError:^(NSError *error) { receivedError = YES; }]; [replacement sendError:nil]; expect(@(receivedError)).to(beTruthy()); }); qck_it(@"should forward completed from the replacement signal", ^{ RACSubject *replacement = [RACSubject subject]; __block BOOL receivedCompleted = NO; [[RACSignal.never takeUntilReplacement:replacement] subscribeCompleted: ^{ receivedCompleted = YES; }]; [replacement sendCompleted]; expect(@(receivedCompleted)).to(beTruthy()); }); qck_it(@"should not forward values from the receiver if both send synchronously", ^{ RACSignal *receiver = [RACSignal createSignal:^ RACDisposable * (id subscriber) { [subscriber sendNext:@1]; [subscriber sendNext:@2]; [subscriber sendNext:@3]; return nil; }]; RACSignal *replacement = [RACSignal createSignal:^ RACDisposable * (id subscriber) { [subscriber sendNext:@4]; [subscriber sendNext:@5]; [subscriber sendNext:@6]; return nil; }]; NSMutableArray *receivedValues = [NSMutableArray array]; [[receiver takeUntilReplacement:replacement] subscribeNext:^(id x) { [receivedValues addObject:x]; }]; expect(receivedValues).to(equal((@[ @4, @5, @6 ]))); }); qck_it(@"should dispose of the receiver when it's disposed of", ^{ __block BOOL receiverDisposed = NO; RACSignal *receiver = [RACSignal createSignal:^(id subscriber) { return [RACDisposable disposableWithBlock:^{ receiverDisposed = YES; }]; }]; [[[receiver takeUntilReplacement:RACSignal.never] subscribeCompleted:^{}] dispose]; expect(@(receiverDisposed)).to(beTruthy()); }); qck_it(@"should dispose of the replacement signal when it's disposed of", ^{ __block BOOL replacementDisposed = NO; RACSignal *replacement = [RACSignal createSignal:^(id subscriber) { return [RACDisposable disposableWithBlock:^{ replacementDisposed = YES; }]; }]; [[[RACSignal.never takeUntilReplacement:replacement] subscribeCompleted:^{}] dispose]; expect(@(replacementDisposed)).to(beTruthy()); }); qck_it(@"should dispose of the receiver when the replacement signal sends an event", ^{ __block BOOL receiverDisposed = NO; __block id receiverSubscriber = nil; RACSignal *receiver = [RACSignal createSignal:^(id subscriber) { // Keep the subscriber alive so it doesn't trigger disposal on dealloc receiverSubscriber = subscriber; return [RACDisposable disposableWithBlock:^{ receiverDisposed = YES; }]; }]; RACSubject *replacement = [RACSubject subject]; [[receiver takeUntilReplacement:replacement] subscribeCompleted:^{}]; expect(@(receiverDisposed)).to(beFalsy()); [replacement sendNext:nil]; expect(@(receiverDisposed)).to(beTruthy()); }); }); qck_describe(@"disposal", ^{ qck_it(@"should dispose of the didSubscribe disposable", ^{ __block BOOL innerDisposed = NO; RACSignal *signal = [RACSignal createSignal:^(id subscriber) { return [RACDisposable disposableWithBlock:^{ innerDisposed = YES; }]; }]; expect(@(innerDisposed)).to(beFalsy()); RACDisposable *disposable = [signal subscribeNext:^(id x) {}]; expect(disposable).notTo(beNil()); [disposable dispose]; expect(@(innerDisposed)).to(beTruthy()); }); qck_it(@"should dispose of the didSubscribe disposable asynchronously", ^{ __block BOOL innerDisposed = NO; RACSignal *signal = [RACSignal createSignal:^(id subscriber) { return [RACDisposable disposableWithBlock:^{ innerDisposed = YES; }]; }]; [[RACScheduler scheduler] schedule:^{ RACDisposable *disposable = [signal subscribeNext:^(id x) {}]; [disposable dispose]; }]; expect(@(innerDisposed)).toEventually(beTruthy()); }); }); qck_describe(@"querying", ^{ __block RACSignal *signal = nil; id nextValueSent = @"1"; qck_beforeEach(^{ signal = [RACSignal createSignal:^ RACDisposable * (id subscriber) { [subscriber sendNext:nextValueSent]; [subscriber sendNext:@"other value"]; [subscriber sendCompleted]; return nil; }]; }); qck_it(@"should return first 'next' value with -firstOrDefault:success:error:", ^{ RACSignal *signal = [RACSignal createSignal:^ id (id subscriber) { [subscriber sendNext:@1]; [subscriber sendNext:@2]; [subscriber sendNext:@3]; [subscriber sendCompleted]; return nil; }]; expect(signal).notTo(beNil()); __block BOOL success = NO; __block NSError *error = nil; expect([signal firstOrDefault:@5 success:&success error:&error]).to(equal(@1)); expect(@(success)).to(beTruthy()); expect(error).to(beNil()); }); qck_it(@"should return first default value with -firstOrDefault:success:error:", ^{ RACSignal *signal = [RACSignal createSignal:^ id (id subscriber) { [subscriber sendCompleted]; return nil; }]; expect(signal).notTo(beNil()); __block BOOL success = NO; __block NSError *error = nil; expect([signal firstOrDefault:@5 success:&success error:&error]).to(equal(@5)); expect(@(success)).to(beTruthy()); expect(error).to(beNil()); }); qck_it(@"should return error with -firstOrDefault:success:error:", ^{ RACSignal *signal = [RACSignal createSignal:^ id (id subscriber) { [subscriber sendError:RACSignalTestError]; return nil; }]; expect(signal).notTo(beNil()); __block BOOL success = NO; __block NSError *error = nil; expect([signal firstOrDefault:@5 success:&success error:&error]).to(equal(@5)); expect(@(success)).to(beFalsy()); expect(error).to(equal(RACSignalTestError)); }); qck_it(@"shouldn't crash when returning an error from a background scheduler", ^{ RACSignal *signal = [RACSignal createSignal:^ id (id subscriber) { [[RACScheduler scheduler] schedule:^{ [subscriber sendError:RACSignalTestError]; }]; return nil; }]; expect(signal).notTo(beNil()); __block BOOL success = NO; __block NSError *error = nil; expect([signal firstOrDefault:@5 success:&success error:&error]).to(equal(@5)); expect(@(success)).to(beFalsy()); expect(error).to(equal(RACSignalTestError)); }); qck_it(@"should terminate the subscription after returning from -firstOrDefault:success:error:", ^{ __block BOOL disposed = NO; RACSignal *signal = [RACSignal createSignal:^(id subscriber) { [subscriber sendNext:RACUnit.defaultUnit]; return [RACDisposable disposableWithBlock:^{ disposed = YES; }]; }]; expect(signal).notTo(beNil()); expect(@(disposed)).to(beFalsy()); expect([signal firstOrDefault:nil success:NULL error:NULL]).to(equal(RACUnit.defaultUnit)); expect(@(disposed)).to(beTruthy()); }); qck_it(@"should return YES from -waitUntilCompleted: when successful", ^{ RACSignal *signal = [RACSignal createSignal:^ id (id subscriber) { [subscriber sendNext:RACUnit.defaultUnit]; [subscriber sendCompleted]; return nil; }]; __block NSError *error = nil; expect(@([signal waitUntilCompleted:&error])).to(beTruthy()); expect(error).to(beNil()); }); qck_it(@"should return NO from -waitUntilCompleted: upon error", ^{ RACSignal *signal = [RACSignal createSignal:^ id (id subscriber) { [subscriber sendNext:RACUnit.defaultUnit]; [subscriber sendError:RACSignalTestError]; return nil; }]; __block NSError *error = nil; expect(@([signal waitUntilCompleted:&error])).to(beFalsy()); expect(error).to(equal(RACSignalTestError)); }); qck_it(@"should return a delayed value from -asynchronousFirstOrDefault:success:error:", ^{ RACSignal *signal = [[RACSignal return:RACUnit.defaultUnit] delay:0]; __block BOOL scheduledBlockRan = NO; [RACScheduler.mainThreadScheduler schedule:^{ scheduledBlockRan = YES; }]; expect(@(scheduledBlockRan)).to(beFalsy()); BOOL success = NO; NSError *error = nil; id value = [signal asynchronousFirstOrDefault:nil success:&success error:&error]; expect(@(scheduledBlockRan)).to(beTruthy()); expect(value).to(equal(RACUnit.defaultUnit)); expect(@(success)).to(beTruthy()); expect(error).to(beNil()); }); qck_it(@"should return a default value from -asynchronousFirstOrDefault:success:error:", ^{ RACSignal *signal = [[RACSignal error:RACSignalTestError] delay:0]; __block BOOL scheduledBlockRan = NO; [RACScheduler.mainThreadScheduler schedule:^{ scheduledBlockRan = YES; }]; expect(@(scheduledBlockRan)).to(beFalsy()); BOOL success = NO; NSError *error = nil; id value = [signal asynchronousFirstOrDefault:RACUnit.defaultUnit success:&success error:&error]; expect(@(scheduledBlockRan)).to(beTruthy()); expect(value).to(equal(RACUnit.defaultUnit)); expect(@(success)).to(beFalsy()); expect(error).to(equal(RACSignalTestError)); }); qck_it(@"should return a delayed error from -asynchronousFirstOrDefault:success:error:", ^{ RACSignal *signal = [[RACSignal createSignal:^(id subscriber) { return [[RACScheduler scheduler] schedule:^{ [subscriber sendError:RACSignalTestError]; }]; }] deliverOn:RACScheduler.mainThreadScheduler]; __block NSError *error = nil; __block BOOL success = NO; expect([signal asynchronousFirstOrDefault:nil success:&success error:&error]).to(beNil()); expect(@(success)).to(beFalsy()); expect(error).to(equal(RACSignalTestError)); }); qck_it(@"should terminate the subscription after returning from -asynchronousFirstOrDefault:success:error:", ^{ __block BOOL disposed = NO; RACSignal *signal = [RACSignal createSignal:^(id subscriber) { [[RACScheduler scheduler] schedule:^{ [subscriber sendNext:RACUnit.defaultUnit]; }]; return [RACDisposable disposableWithBlock:^{ disposed = YES; }]; }]; expect(signal).notTo(beNil()); expect(@(disposed)).to(beFalsy()); expect([signal asynchronousFirstOrDefault:nil success:NULL error:NULL]).to(equal(RACUnit.defaultUnit)); expect(@(disposed)).toEventually(beTruthy()); }); qck_it(@"should return a delayed success from -asynchronouslyWaitUntilCompleted:", ^{ RACSignal *signal = [[RACSignal return:RACUnit.defaultUnit] delay:0]; __block BOOL scheduledBlockRan = NO; [RACScheduler.mainThreadScheduler schedule:^{ scheduledBlockRan = YES; }]; expect(@(scheduledBlockRan)).to(beFalsy()); NSError *error = nil; BOOL success = [signal asynchronouslyWaitUntilCompleted:&error]; expect(@(scheduledBlockRan)).to(beTruthy()); expect(@(success)).to(beTruthy()); expect(error).to(beNil()); }); }); qck_describe(@"continuation", ^{ qck_it(@"should repeat after completion", ^{ __block NSUInteger numberOfSubscriptions = 0; RACScheduler *scheduler = [RACScheduler scheduler]; RACSignal *signal = [RACSignal createSignal:^ RACDisposable * (id subscriber) { return [scheduler schedule:^{ if (numberOfSubscriptions == 3) { [subscriber sendError:RACSignalTestError]; return; } numberOfSubscriptions++; [subscriber sendNext:@"1"]; [subscriber sendCompleted]; [subscriber sendError:RACSignalTestError]; }]; }]; __block NSUInteger nextCount = 0; __block BOOL gotCompleted = NO; [[signal repeat] subscribeNext:^(id x) { nextCount++; } error:^(NSError *error) { } completed:^{ gotCompleted = YES; }]; expect(@(nextCount)).toEventually(equal(@3)); expect(@(gotCompleted)).to(beFalsy()); }); qck_it(@"should stop repeating when disposed", ^{ RACSignal *signal = [RACSignal createSignal:^ id (id subscriber) { [subscriber sendNext:@1]; [subscriber sendCompleted]; return nil; }]; NSMutableArray *values = [NSMutableArray array]; __block BOOL completed = NO; __block RACDisposable *disposable = [[[signal repeat] subscribeOn:RACScheduler.mainThreadScheduler] subscribeNext:^(id x) { [values addObject:x]; [disposable dispose]; } completed:^{ completed = YES; }]; expect(values).toEventually(equal(@[ @1 ])); expect(@(completed)).to(beFalsy()); }); qck_it(@"should stop repeating when disposed by -take:", ^{ RACSignal *signal = [RACSignal createSignal:^ id (id subscriber) { [subscriber sendNext:@1]; [subscriber sendCompleted]; return nil; }]; NSMutableArray *values = [NSMutableArray array]; __block BOOL completed = NO; [[[signal repeat] take:1] subscribeNext:^(id x) { [values addObject:x]; } completed:^{ completed = YES; }]; expect(values).toEventually(equal(@[ @1 ])); expect(@(completed)).to(beTruthy()); }); }); qck_describe(@"+combineLatestWith:", ^{ __block RACSubject *subject1 = nil; __block RACSubject *subject2 = nil; __block RACSignal *combined = nil; qck_beforeEach(^{ subject1 = [RACSubject subject]; subject2 = [RACSubject subject]; combined = [RACSignal combineLatest:@[ subject1, subject2 ]]; }); qck_it(@"should send next only once both signals send next", ^{ __block RACTuple *tuple; [combined subscribeNext:^(id x) { tuple = x; }]; expect(tuple).to(beNil()); [subject1 sendNext:@"1"]; expect(tuple).to(beNil()); [subject2 sendNext:@"2"]; expect(tuple).to(equal(RACTuplePack(@"1", @"2"))); }); qck_it(@"should send nexts when either signal sends multiple times", ^{ NSMutableArray *results = [NSMutableArray array]; [combined subscribeNext:^(id x) { [results addObject:x]; }]; [subject1 sendNext:@"1"]; [subject2 sendNext:@"2"]; [subject1 sendNext:@"3"]; [subject2 sendNext:@"4"]; expect(results[0]).to(equal(RACTuplePack(@"1", @"2"))); expect(results[1]).to(equal(RACTuplePack(@"3", @"2"))); expect(results[2]).to(equal(RACTuplePack(@"3", @"4"))); }); qck_it(@"should complete when only both signals complete", ^{ __block BOOL completed = NO; [combined subscribeCompleted:^{ completed = YES; }]; expect(@(completed)).to(beFalsy()); [subject1 sendCompleted]; expect(@(completed)).to(beFalsy()); [subject2 sendCompleted]; expect(@(completed)).to(beTruthy()); }); qck_it(@"should error when either signal errors", ^{ __block NSError *receivedError = nil; [combined subscribeError:^(NSError *error) { receivedError = error; }]; [subject1 sendError:RACSignalTestError]; expect(receivedError).to(equal(RACSignalTestError)); }); qck_it(@"shouldn't create a retain cycle", ^{ __block BOOL subjectDeallocd = NO; __block BOOL signalDeallocd = NO; @autoreleasepool { RACSubject *subject __attribute__((objc_precise_lifetime)) = [RACSubject subject]; [subject.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ subjectDeallocd = YES; }]]; RACSignal *signal __attribute__((objc_precise_lifetime)) = [RACSignal combineLatest:@[ subject ]]; [signal.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ signalDeallocd = YES; }]]; [signal subscribeCompleted:^{}]; [subject sendCompleted]; } expect(@(subjectDeallocd)).toEventually(beTruthy()); expect(@(signalDeallocd)).toEventually(beTruthy()); }); qck_it(@"should combine the same signal", ^{ RACSignal *combined = [subject1 combineLatestWith:subject1]; __block RACTuple *tuple; [combined subscribeNext:^(id x) { tuple = x; }]; [subject1 sendNext:@"foo"]; expect(tuple).to(equal(RACTuplePack(@"foo", @"foo"))); [subject1 sendNext:@"bar"]; expect(tuple).to(equal(RACTuplePack(@"bar", @"bar"))); }); qck_it(@"should combine the same side-effecting signal", ^{ __block NSUInteger counter = 0; RACSignal *sideEffectingSignal = [RACSignal createSignal:^ RACDisposable * (id subscriber) { [subscriber sendNext:@(++counter)]; [subscriber sendCompleted]; return nil; }]; RACSignal *combined = [sideEffectingSignal combineLatestWith:sideEffectingSignal]; expect(@(counter)).to(equal(@0)); NSMutableArray *receivedValues = [NSMutableArray array]; [combined subscribeNext:^(id x) { [receivedValues addObject:x]; }]; expect(@(counter)).to(equal(@2)); NSArray *expected = @[ RACTuplePack(@1, @2) ]; expect(receivedValues).to(equal(expected)); }); }); qck_describe(@"+combineLatest:", ^{ qck_it(@"should return tuples even when only combining one signal", ^{ RACSubject *subject = [RACSubject subject]; __block RACTuple *tuple; [[RACSignal combineLatest:@[ subject ]] subscribeNext:^(id x) { tuple = x; }]; [subject sendNext:@"foo"]; expect(tuple).to(equal(RACTuplePack(@"foo"))); }); qck_it(@"should complete immediately when not given any signals", ^{ RACSignal *signal = [RACSignal combineLatest:@[]]; __block BOOL completed = NO; [signal subscribeCompleted:^{ completed = YES; }]; expect(@(completed)).to(beTruthy()); }); qck_it(@"should only complete after all its signals complete", ^{ RACSubject *subject1 = [RACSubject subject]; RACSubject *subject2 = [RACSubject subject]; RACSubject *subject3 = [RACSubject subject]; RACSignal *combined = [RACSignal combineLatest:@[ subject1, subject2, subject3 ]]; __block BOOL completed = NO; [combined subscribeCompleted:^{ completed = YES; }]; expect(@(completed)).to(beFalsy()); [subject1 sendCompleted]; expect(@(completed)).to(beFalsy()); [subject2 sendCompleted]; expect(@(completed)).to(beFalsy()); [subject3 sendCompleted]; expect(@(completed)).to(beTruthy()); }); }); qck_describe(@"+combineLatest:reduce:", ^{ __block RACSubject *subject1; __block RACSubject *subject2; __block RACSubject *subject3; qck_beforeEach(^{ subject1 = [RACSubject subject]; subject2 = [RACSubject subject]; subject3 = [RACSubject subject]; }); qck_it(@"should send nils for nil values", ^{ __block id receivedVal1; __block id receivedVal2; __block id receivedVal3; RACSignal *combined = [RACSignal combineLatest:@[ subject1, subject2, subject3 ] reduce:^ id (id val1, id val2, id val3) { receivedVal1 = val1; receivedVal2 = val2; receivedVal3 = val3; return nil; }]; __block BOOL gotValue = NO; [combined subscribeNext:^(id x) { gotValue = YES; }]; [subject1 sendNext:nil]; [subject2 sendNext:nil]; [subject3 sendNext:nil]; expect(@(gotValue)).to(beTruthy()); expect(receivedVal1).to(beNil()); expect(receivedVal2).to(beNil()); expect(receivedVal3).to(beNil()); }); qck_it(@"should send the return result of the reduce block", ^{ RACSignal *combined = [RACSignal combineLatest:@[ subject1, subject2, subject3 ] reduce:^(NSString *string1, NSString *string2, NSString *string3) { return [NSString stringWithFormat:@"%@: %@%@", string1, string2, string3]; }]; __block id received; [combined subscribeNext:^(id x) { received = x; }]; [subject1 sendNext:@"hello"]; [subject2 sendNext:@"world"]; [subject3 sendNext:@"!!1"]; expect(received).to(equal(@"hello: world!!1")); }); qck_it(@"should handle multiples of the same signals", ^{ RACSignal *combined = [RACSignal combineLatest:@[ subject1, subject2, subject1, subject3 ] reduce:^(NSString *string1, NSString *string2, NSString *string3, NSString *string4) { return [NSString stringWithFormat:@"%@ : %@ = %@ : %@", string1, string2, string3, string4]; }]; NSMutableArray *receivedValues = NSMutableArray.array; [combined subscribeNext:^(id x) { [receivedValues addObject:x]; }]; [subject1 sendNext:@"apples"]; expect(receivedValues.lastObject).to(beNil()); [subject2 sendNext:@"oranges"]; expect(receivedValues.lastObject).to(beNil()); [subject3 sendNext:@"cattle"]; expect(receivedValues.lastObject).to(equal(@"apples : oranges = apples : cattle")); [subject1 sendNext:@"horses"]; expect(receivedValues.lastObject).to(equal(@"horses : oranges = horses : cattle")); }); qck_it(@"should handle multiples of the same side-effecting signal", ^{ __block NSUInteger counter = 0; RACSignal *sideEffectingSignal = [RACSignal createSignal:^ id (id subscriber) { [subscriber sendNext:@(++counter)]; [subscriber sendCompleted]; return nil; }]; RACSignal *combined = [RACSignal combineLatest:@[ sideEffectingSignal, sideEffectingSignal, sideEffectingSignal ] reduce:^(id x, id y, id z) { return [NSString stringWithFormat:@"%@%@%@", x, y, z]; }]; NSMutableArray *receivedValues = [NSMutableArray array]; expect(@(counter)).to(equal(@0)); [combined subscribeNext:^(id x) { [receivedValues addObject:x]; }]; expect(@(counter)).to(equal(@3)); expect(receivedValues).to(equal(@[ @"123" ])); }); }); qck_describe(@"distinctUntilChanged", ^{ qck_it(@"should only send values that are distinct from the previous value", ^{ RACSignal *sub = [[RACSignal createSignal:^ RACDisposable * (id subscriber) { [subscriber sendNext:@1]; [subscriber sendNext:@2]; [subscriber sendNext:@2]; [subscriber sendNext:@1]; [subscriber sendNext:@1]; [subscriber sendCompleted]; return nil; }] distinctUntilChanged]; NSArray *values = sub.toArray; NSArray *expected = @[ @1, @2, @1 ]; expect(values).to(equal(expected)); }); qck_it(@"shouldn't consider nils to always be distinct", ^{ RACSignal *sub = [[RACSignal createSignal:^ RACDisposable * (id subscriber) { [subscriber sendNext:@1]; [subscriber sendNext:nil]; [subscriber sendNext:nil]; [subscriber sendNext:nil]; [subscriber sendNext:@1]; [subscriber sendCompleted]; return nil; }] distinctUntilChanged]; NSArray *values = sub.toArray; NSArray *expected = @[ @1, [NSNull null], @1 ]; expect(values).to(equal(expected)); }); qck_it(@"should consider initial nil to be distinct", ^{ RACSignal *sub = [[RACSignal createSignal:^ RACDisposable * (id subscriber) { [subscriber sendNext:nil]; [subscriber sendNext:nil]; [subscriber sendNext:@1]; [subscriber sendCompleted]; return nil; }] distinctUntilChanged]; NSArray *values = sub.toArray; NSArray *expected = @[ [NSNull null], @1 ]; expect(values).to(equal(expected)); }); }); qck_describe(@"RACObserve", ^{ __block RACTestObject *testObject; qck_beforeEach(^{ testObject = [[RACTestObject alloc] init]; }); qck_it(@"should work with object properties", ^{ NSArray *expected = @[ @"hello", @"world" ]; testObject.objectValue = expected[0]; NSMutableArray *valuesReceived = [NSMutableArray array]; [RACObserve(testObject, objectValue) subscribeNext:^(id x) { [valuesReceived addObject:x]; }]; testObject.objectValue = expected[1]; expect(valuesReceived).to(equal(expected)); }); qck_it(@"should work with non-object properties", ^{ NSArray *expected = @[ @42, @43 ]; testObject.integerValue = [expected[0] integerValue]; NSMutableArray *valuesReceived = [NSMutableArray array]; [RACObserve(testObject, integerValue) subscribeNext:^(id x) { [valuesReceived addObject:x]; }]; testObject.integerValue = [expected[1] integerValue]; expect(valuesReceived).to(equal(expected)); }); qck_it(@"should read the initial value upon subscription", ^{ testObject.objectValue = @"foo"; RACSignal *signal = RACObserve(testObject, objectValue); testObject.objectValue = @"bar"; expect([signal first]).to(equal(@"bar")); }); }); qck_describe(@"-setKeyPath:onObject:", ^{ id setupBlock = ^(RACTestObject *testObject, NSString *keyPath, id nilValue, RACSignal *signal) { [signal setKeyPath:keyPath onObject:testObject nilValue:nilValue]; }; qck_itBehavesLike(RACPropertySignalExamples, ^{ return @{ RACPropertySignalExamplesSetupBlock: setupBlock }; }); qck_it(@"shouldn't send values to dealloc'd objects", ^{ RACSubject *subject = [RACSubject subject]; @autoreleasepool { RACTestObject *testObject __attribute__((objc_precise_lifetime)) = [[RACTestObject alloc] init]; [subject setKeyPath:@keypath(testObject.objectValue) onObject:testObject]; expect(testObject.objectValue).to(beNil()); [subject sendNext:@1]; expect(testObject.objectValue).to(equal(@1)); [subject sendNext:@2]; expect(testObject.objectValue).to(equal(@2)); } // This shouldn't do anything. [subject sendNext:@3]; }); qck_it(@"should allow a new derivation after the signal's completed", ^{ RACSubject *subject1 = [RACSubject subject]; RACTestObject *testObject = [[RACTestObject alloc] init]; [subject1 setKeyPath:@keypath(testObject.objectValue) onObject:testObject]; [subject1 sendCompleted]; RACSubject *subject2 = [RACSubject subject]; // This will assert if the previous completion didn't dispose of the // subscription. [subject2 setKeyPath:@keypath(testObject.objectValue) onObject:testObject]; }); qck_it(@"should set the given value when nil is received", ^{ RACSubject *subject = [RACSubject subject]; RACTestObject *testObject = [[RACTestObject alloc] init]; [subject setKeyPath:@keypath(testObject.integerValue) onObject:testObject nilValue:@5]; [subject sendNext:@1]; expect(@(testObject.integerValue)).to(equal(@1)); [subject sendNext:nil]; expect(@(testObject.integerValue)).to(equal(@5)); [subject sendCompleted]; expect(@(testObject.integerValue)).to(equal(@5)); }); qck_it(@"should keep object alive over -sendNext:", ^{ RACSubject *subject = [RACSubject subject]; __block RACTestObject *testObject = [[RACTestObject alloc] init]; __block id deallocValue; __unsafe_unretained RACTestObject *unsafeTestObject = testObject; [testObject.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ deallocValue = unsafeTestObject.slowObjectValue; }]]; [subject setKeyPath:@keypath(testObject.slowObjectValue) onObject:testObject]; expect(testObject.slowObjectValue).to(beNil()); // Attempt to deallocate concurrently. [[RACScheduler scheduler] afterDelay:0.01 schedule:^{ testObject = nil; }]; expect(deallocValue).to(beNil()); [subject sendNext:@1]; expect(deallocValue).to(equal(@1)); }); }); qck_describe(@"memory management", ^{ qck_it(@"should dealloc signals if the signal does nothing", ^{ __block BOOL deallocd = NO; @autoreleasepool { RACSignal *signal __attribute__((objc_precise_lifetime)) = [RACSignal createSignal:^ id (id subscriber) { return nil; }]; [signal.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ deallocd = YES; }]]; } expect(@(deallocd)).toEventually(beTruthy()); }); qck_it(@"should dealloc signals if the signal immediately completes", ^{ __block BOOL deallocd = NO; @autoreleasepool { __block BOOL done = NO; RACSignal *signal __attribute__((objc_precise_lifetime)) = [RACSignal createSignal:^ id (id subscriber) { [subscriber sendCompleted]; return nil; }]; [signal.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ deallocd = YES; }]]; [signal subscribeCompleted:^{ done = YES; }]; expect(@(done)).toEventually(beTruthy()); } expect(@(deallocd)).toEventually(beTruthy()); }); qck_it(@"should dealloc a replay subject if it completes immediately", ^{ __block BOOL completed = NO; __block BOOL deallocd = NO; @autoreleasepool { RACReplaySubject *subject __attribute__((objc_precise_lifetime)) = [RACReplaySubject subject]; [subject sendCompleted]; [subject.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ deallocd = YES; }]]; [subject subscribeCompleted:^{ completed = YES; }]; } expect(@(completed)).toEventually(beTruthy()); expect(@(deallocd)).toEventually(beTruthy()); }); qck_it(@"should dealloc if the signal was created on a background queue", ^{ __block BOOL completed = NO; __block BOOL deallocd = NO; @autoreleasepool { [[RACScheduler scheduler] schedule:^{ RACSignal *signal __attribute__((objc_precise_lifetime)) = [RACSignal createSignal:^ id (id subscriber) { [subscriber sendCompleted]; return nil; }]; [signal.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ deallocd = YES; }]]; [signal subscribeCompleted:^{ completed = YES; }]; }]; } expect(@(completed)).toEventually(beTruthy()); expect(@(deallocd)).toEventually(beTruthy()); }); qck_it(@"should dealloc if the signal was created on a background queue, never gets any subscribers, and the background queue gets delayed", ^{ __block BOOL deallocd = NO; dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); @autoreleasepool { [[RACScheduler scheduler] schedule:^{ RACSignal *signal __attribute__((objc_precise_lifetime)) = [RACSignal createSignal:^ id (id subscriber) { return nil; }]; [signal.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ deallocd = YES; dispatch_semaphore_signal(semaphore); }]]; [NSThread sleepForTimeInterval:1]; expect(@(deallocd)).to(beFalsy()); }]; } dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); expect(@(deallocd)).to(beTruthy()); }); qck_it(@"should retain intermediate signals when subscribing", ^{ RACSubject *subject = [RACSubject subject]; expect(subject).notTo(beNil()); __block BOOL gotNext = NO; __block BOOL completed = NO; RACDisposable *disposable; @autoreleasepool { RACSignal *intermediateSignal = [subject doNext:^(id _) { gotNext = YES; }]; expect(intermediateSignal).notTo(beNil()); disposable = [intermediateSignal subscribeCompleted:^{ completed = YES; }]; } [subject sendNext:@5]; expect(@(gotNext)).to(beTruthy()); [subject sendCompleted]; expect(@(completed)).to(beTruthy()); [disposable dispose]; }); }); qck_describe(@"-merge:", ^{ __block RACSubject *sub1; __block RACSubject *sub2; __block RACSignal *merged; qck_beforeEach(^{ sub1 = [RACSubject subject]; sub2 = [RACSubject subject]; merged = [sub1 merge:sub2]; }); qck_it(@"should send all values from both signals", ^{ NSMutableArray *values = [NSMutableArray array]; [merged subscribeNext:^(id x) { [values addObject:x]; }]; [sub1 sendNext:@1]; [sub2 sendNext:@2]; [sub2 sendNext:@3]; [sub1 sendNext:@4]; NSArray *expected = @[ @1, @2, @3, @4 ]; expect(values).to(equal(expected)); }); qck_it(@"should send an error if one occurs", ^{ __block NSError *errorReceived; [merged subscribeError:^(NSError *error) { errorReceived = error; }]; [sub1 sendError:RACSignalTestError]; expect(errorReceived).to(equal(RACSignalTestError)); }); qck_it(@"should complete only after both signals complete", ^{ NSMutableArray *values = [NSMutableArray array]; __block BOOL completed = NO; [merged subscribeNext:^(id x) { [values addObject:x]; } completed:^{ completed = YES; }]; [sub1 sendNext:@1]; [sub2 sendNext:@2]; [sub2 sendNext:@3]; [sub2 sendCompleted]; expect(@(completed)).to(beFalsy()); [sub1 sendNext:@4]; [sub1 sendCompleted]; expect(@(completed)).to(beTruthy()); NSArray *expected = @[ @1, @2, @3, @4 ]; expect(values).to(equal(expected)); }); qck_it(@"should complete only after both signals complete for any number of subscribers", ^{ __block BOOL completed1 = NO; __block BOOL completed2 = NO; [merged subscribeCompleted:^{ completed1 = YES; }]; [merged subscribeCompleted:^{ completed2 = YES; }]; expect(@(completed1)).to(beFalsy()); expect(@(completed2)).to(beFalsy()); [sub1 sendCompleted]; [sub2 sendCompleted]; expect(@(completed1)).to(beTruthy()); expect(@(completed2)).to(beTruthy()); }); }); qck_describe(@"+merge:", ^{ __block RACSubject *sub1; __block RACSubject *sub2; __block RACSignal *merged; qck_beforeEach(^{ sub1 = [RACSubject subject]; sub2 = [RACSubject subject]; merged = [RACSignal merge:@[ sub1, sub2 ].objectEnumerator]; }); qck_it(@"should send all values from both signals", ^{ NSMutableArray *values = [NSMutableArray array]; [merged subscribeNext:^(id x) { [values addObject:x]; }]; [sub1 sendNext:@1]; [sub2 sendNext:@2]; [sub2 sendNext:@3]; [sub1 sendNext:@4]; NSArray *expected = @[ @1, @2, @3, @4 ]; expect(values).to(equal(expected)); }); qck_it(@"should send an error if one occurs", ^{ __block NSError *errorReceived; [merged subscribeError:^(NSError *error) { errorReceived = error; }]; [sub1 sendError:RACSignalTestError]; expect(errorReceived).to(equal(RACSignalTestError)); }); qck_it(@"should complete only after both signals complete", ^{ NSMutableArray *values = [NSMutableArray array]; __block BOOL completed = NO; [merged subscribeNext:^(id x) { [values addObject:x]; } completed:^{ completed = YES; }]; [sub1 sendNext:@1]; [sub2 sendNext:@2]; [sub2 sendNext:@3]; [sub2 sendCompleted]; expect(@(completed)).to(beFalsy()); [sub1 sendNext:@4]; [sub1 sendCompleted]; expect(@(completed)).to(beTruthy()); NSArray *expected = @[ @1, @2, @3, @4 ]; expect(values).to(equal(expected)); }); qck_it(@"should complete immediately when not given any signals", ^{ RACSignal *signal = [RACSignal merge:@[].objectEnumerator]; __block BOOL completed = NO; [signal subscribeCompleted:^{ completed = YES; }]; expect(@(completed)).to(beTruthy()); }); qck_it(@"should complete only after both signals complete for any number of subscribers", ^{ __block BOOL completed1 = NO; __block BOOL completed2 = NO; [merged subscribeCompleted:^{ completed1 = YES; }]; [merged subscribeCompleted:^{ completed2 = YES; }]; expect(@(completed1)).to(beFalsy()); expect(@(completed2)).to(beFalsy()); [sub1 sendCompleted]; [sub2 sendCompleted]; expect(@(completed1)).to(beTruthy()); expect(@(completed2)).to(beTruthy()); }); }); qck_describe(@"-flatten:", ^{ __block BOOL subscribedTo1 = NO; __block BOOL subscribedTo2 = NO; __block BOOL subscribedTo3 = NO; __block RACSignal *sub1; __block RACSignal *sub2; __block RACSignal *sub3; __block RACSubject *subject1; __block RACSubject *subject2; __block RACSubject *subject3; __block RACSubject *signalsSubject; __block NSMutableArray *values; qck_beforeEach(^{ subscribedTo1 = NO; subject1 = [RACSubject subject]; sub1 = [RACSignal defer:^{ subscribedTo1 = YES; return subject1; }]; subscribedTo2 = NO; subject2 = [RACSubject subject]; sub2 = [RACSignal defer:^{ subscribedTo2 = YES; return subject2; }]; subscribedTo3 = NO; subject3 = [RACSubject subject]; sub3 = [RACSignal defer:^{ subscribedTo3 = YES; return subject3; }]; signalsSubject = [RACSubject subject]; values = [NSMutableArray array]; }); qck_describe(@"when its max is 0", ^{ qck_it(@"should merge all the signals concurrently", ^{ [[signalsSubject flatten:0] subscribeNext:^(id x) { [values addObject:x]; }]; expect(@(subscribedTo1)).to(beFalsy()); expect(@(subscribedTo2)).to(beFalsy()); expect(@(subscribedTo3)).to(beFalsy()); [signalsSubject sendNext:sub1]; [signalsSubject sendNext:sub2]; expect(@(subscribedTo1)).to(beTruthy()); expect(@(subscribedTo2)).to(beTruthy()); expect(@(subscribedTo3)).to(beFalsy()); [subject1 sendNext:@1]; [signalsSubject sendNext:sub3]; expect(@(subscribedTo1)).to(beTruthy()); expect(@(subscribedTo2)).to(beTruthy()); expect(@(subscribedTo3)).to(beTruthy()); [subject1 sendCompleted]; [subject2 sendNext:@2]; [subject2 sendCompleted]; [subject3 sendNext:@3]; [subject3 sendCompleted]; NSArray *expected = @[ @1, @2, @3 ]; expect(values).to(equal(expected)); }); qck_itBehavesLike(RACSignalMergeConcurrentCompletionExampleGroup, ^{ return @{ RACSignalMaxConcurrent: @0 }; }); }); qck_describe(@"when its max is > 0", ^{ qck_it(@"should merge only the given number at a time", ^{ [[signalsSubject flatten:1] subscribeNext:^(id x) { [values addObject:x]; }]; expect(@(subscribedTo1)).to(beFalsy()); expect(@(subscribedTo2)).to(beFalsy()); expect(@(subscribedTo3)).to(beFalsy()); [signalsSubject sendNext:sub1]; [signalsSubject sendNext:sub2]; expect(@(subscribedTo1)).to(beTruthy()); expect(@(subscribedTo2)).to(beFalsy()); expect(@(subscribedTo3)).to(beFalsy()); [subject1 sendNext:@1]; [signalsSubject sendNext:sub3]; expect(@(subscribedTo1)).to(beTruthy()); expect(@(subscribedTo2)).to(beFalsy()); expect(@(subscribedTo3)).to(beFalsy()); [signalsSubject sendCompleted]; expect(@(subscribedTo1)).to(beTruthy()); expect(@(subscribedTo2)).to(beFalsy()); expect(@(subscribedTo3)).to(beFalsy()); [subject1 sendCompleted]; expect(@(subscribedTo2)).to(beTruthy()); expect(@(subscribedTo3)).to(beFalsy()); [subject2 sendNext:@2]; [subject2 sendCompleted]; expect(@(subscribedTo3)).to(beTruthy()); [subject3 sendNext:@3]; [subject3 sendCompleted]; NSArray *expected = @[ @1, @2, @3 ]; expect(values).to(equal(expected)); }); qck_itBehavesLike(RACSignalMergeConcurrentCompletionExampleGroup, ^{ return @{ RACSignalMaxConcurrent: @1 }; }); }); qck_it(@"shouldn't create a retain cycle", ^{ __block BOOL subjectDeallocd = NO; __block BOOL signalDeallocd = NO; @autoreleasepool { RACSubject *subject __attribute__((objc_precise_lifetime)) = [RACSubject subject]; [subject.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ subjectDeallocd = YES; }]]; RACSignal *signal __attribute__((objc_precise_lifetime)) = [subject flatten]; [signal.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ signalDeallocd = YES; }]]; [signal subscribeCompleted:^{}]; [subject sendCompleted]; } expect(@(subjectDeallocd)).toEventually(beTruthy()); expect(@(signalDeallocd)).toEventually(beTruthy()); }); qck_it(@"should not crash when disposing while subscribing", ^{ RACDisposable *disposable = [[signalsSubject flatten:0] subscribeCompleted:^{ }]; [signalsSubject sendNext:[RACSignal createSignal:^ RACDisposable * (id subscriber) { [disposable dispose]; [subscriber sendCompleted]; return nil; }]]; [signalsSubject sendCompleted]; }); qck_it(@"should dispose after last synchronous signal subscription and should not crash", ^{ RACSignal *flattened = [signalsSubject flatten:1]; RACDisposable *flattenDisposable = [flattened subscribeCompleted:^{}]; RACSignal *syncSignal = [RACSignal createSignal:^ RACDisposable *(id subscriber) { expect(@(flattenDisposable.disposed)).to(beFalsy()); [subscriber sendCompleted]; expect(@(flattenDisposable.disposed)).to(beTruthy()); return nil; }]; RACSignal *asyncSignal = [sub1 delay:0]; [signalsSubject sendNext:asyncSignal]; [signalsSubject sendNext:syncSignal]; [signalsSubject sendCompleted]; [subject1 sendCompleted]; expect(@(flattenDisposable.disposed)).toEventually(beTruthy()); }); qck_it(@"should not crash when disposed because of takeUntil:", ^{ for (int i = 0; i < 100; i++) { RACSubject *flattenedReceiver = [RACSubject subject]; RACSignal *done = [flattenedReceiver map:^(NSNumber *n) { return @(n.integerValue == 1); }]; RACSignal *flattened = [signalsSubject flatten:1]; RACDisposable *flattenDisposable = [[flattened takeUntil:[done ignore:@NO]] subscribe:flattenedReceiver]; RACSignal *syncSignal = [RACSignal createSignal:^ RACDisposable *(id subscriber) { expect(@(flattenDisposable.disposed)).to(beFalsy()); [subscriber sendNext:@1]; expect(@(flattenDisposable.disposed)).to(beTruthy()); [subscriber sendCompleted]; return nil; }]; RACSignal *asyncSignal = [sub1 delay:0]; [subject1 sendNext:@0]; [signalsSubject sendNext:asyncSignal]; [signalsSubject sendNext:syncSignal]; [signalsSubject sendCompleted]; [subject1 sendCompleted]; expect(@(flattenDisposable.disposed)).toEventually(beTruthy()); } }); }); qck_describe(@"-switchToLatest", ^{ __block RACSubject *subject; __block NSMutableArray *values; __block NSError *lastError = nil; __block BOOL completed = NO; qck_beforeEach(^{ subject = [RACSubject subject]; values = [NSMutableArray array]; lastError = nil; completed = NO; [[subject switchToLatest] subscribeNext:^(id x) { expect(lastError).to(beNil()); expect(@(completed)).to(beFalsy()); [values addObject:x]; } error:^(NSError *error) { expect(lastError).to(beNil()); expect(@(completed)).to(beFalsy()); lastError = error; } completed:^{ expect(lastError).to(beNil()); expect(@(completed)).to(beFalsy()); completed = YES; }]; }); qck_it(@"should send values from the most recent signal", ^{ [subject sendNext:[RACSignal createSignal:^ RACDisposable * (id subscriber) { [subscriber sendNext:@1]; [subscriber sendNext:@2]; return nil; }]]; [subject sendNext:[RACSignal createSignal:^ RACDisposable * (id subscriber) { [subscriber sendNext:@3]; [subscriber sendNext:@4]; return nil; }]]; NSArray *expected = @[ @1, @2, @3, @4 ]; expect(values).to(equal(expected)); }); qck_it(@"should send errors from the most recent signal", ^{ [subject sendNext:[RACSignal createSignal:^ id (id subscriber) { [subscriber sendError:[NSError errorWithDomain:@"" code:-1 userInfo:nil]]; return nil; }]]; expect(lastError).notTo(beNil()); }); qck_it(@"should not send completed if only the switching signal completes", ^{ [subject sendNext:RACSignal.never]; expect(@(completed)).to(beFalsy()); [subject sendCompleted]; expect(@(completed)).to(beFalsy()); }); qck_it(@"should send completed when the switching signal completes and the last sent signal does", ^{ [subject sendNext:RACSignal.empty]; expect(@(completed)).to(beFalsy()); [subject sendCompleted]; expect(@(completed)).to(beTruthy()); }); qck_it(@"should accept nil signals", ^{ [subject sendNext:nil]; [subject sendNext:[RACSignal createSignal:^ RACDisposable * (id subscriber) { [subscriber sendNext:@1]; [subscriber sendNext:@2]; return nil; }]]; NSArray *expected = @[ @1, @2 ]; expect(values).to(equal(expected)); }); qck_it(@"should return a cold signal", ^{ __block NSUInteger subscriptions = 0; RACSignal *signalOfSignals = [RACSignal createSignal:^ RACDisposable * (id subscriber) { subscriptions++; [subscriber sendNext:[RACSignal empty]]; return nil; }]; RACSignal *switched = [signalOfSignals switchToLatest]; [[switched publish] connect]; expect(@(subscriptions)).to(equal(@1)); [[switched publish] connect]; expect(@(subscriptions)).to(equal(@2)); }); }); qck_describe(@"+switch:cases:default:", ^{ __block RACSubject *keySubject; __block RACSubject *subjectZero; __block RACSubject *subjectOne; __block RACSubject *subjectTwo; __block RACSubject *defaultSubject; __block NSMutableArray *values; __block NSError *lastError = nil; __block BOOL completed = NO; qck_beforeEach(^{ keySubject = [RACSubject subject]; subjectZero = [RACSubject subject]; subjectOne = [RACSubject subject]; subjectTwo = [RACSubject subject]; defaultSubject = [RACSubject subject]; values = [NSMutableArray array]; lastError = nil; completed = NO; }); qck_describe(@"switching between values with a default", ^{ __block RACSignal *switchSignal; qck_beforeEach(^{ switchSignal = [RACSignal switch:keySubject cases:@{ @0: subjectZero, @1: subjectOne, @2: subjectTwo, } default:[RACSignal never]]; [switchSignal subscribeNext:^(id x) { expect(lastError).to(beNil()); expect(@(completed)).to(beFalsy()); [values addObject:x]; } error:^(NSError *error) { expect(lastError).to(beNil()); expect(@(completed)).to(beFalsy()); lastError = error; } completed:^{ expect(lastError).to(beNil()); expect(@(completed)).to(beFalsy()); completed = YES; }]; }); qck_it(@"should not send any values before a key is sent", ^{ [subjectZero sendNext:RACUnit.defaultUnit]; [subjectOne sendNext:RACUnit.defaultUnit]; [subjectTwo sendNext:RACUnit.defaultUnit]; expect(values).to(equal(@[])); expect(lastError).to(beNil()); expect(@(completed)).to(beFalsy()); }); qck_it(@"should send events based on the latest key", ^{ [keySubject sendNext:@0]; [subjectZero sendNext:@"zero"]; [subjectZero sendNext:@"zero"]; [subjectOne sendNext:@"one"]; [subjectTwo sendNext:@"two"]; NSArray *expected = @[ @"zero", @"zero" ]; expect(values).to(equal(expected)); [keySubject sendNext:@1]; [subjectZero sendNext:@"zero"]; [subjectOne sendNext:@"one"]; [subjectTwo sendNext:@"two"]; expected = @[ @"zero", @"zero", @"one" ]; expect(values).to(equal(expected)); expect(lastError).to(beNil()); expect(@(completed)).to(beFalsy()); [keySubject sendNext:@2]; [subjectZero sendError:[NSError errorWithDomain:@"" code:-1 userInfo:nil]]; [subjectOne sendError:[NSError errorWithDomain:@"" code:-1 userInfo:nil]]; expect(lastError).to(beNil()); [subjectTwo sendError:[NSError errorWithDomain:@"" code:-1 userInfo:nil]]; expect(lastError).notTo(beNil()); }); qck_it(@"should not send completed when only the key signal completes", ^{ [keySubject sendNext:@0]; [subjectZero sendNext:@"zero"]; [keySubject sendCompleted]; expect(values).to(equal(@[ @"zero" ])); expect(@(completed)).to(beFalsy()); }); qck_it(@"should send completed when the key signal and the latest sent signal complete", ^{ [keySubject sendNext:@0]; [subjectZero sendNext:@"zero"]; [keySubject sendCompleted]; [subjectZero sendCompleted]; expect(values).to(equal(@[ @"zero" ])); expect(@(completed)).to(beTruthy()); }); }); qck_it(@"should use the default signal if key that was sent does not have an associated signal", ^{ [[RACSignal switch:keySubject cases:@{ @0: subjectZero, @1: subjectOne, } default:defaultSubject] subscribeNext:^(id x) { [values addObject:x]; }]; [keySubject sendNext:@"not a valid key"]; [defaultSubject sendNext:@"default"]; expect(values).to(equal(@[ @"default" ])); [keySubject sendNext:nil]; [defaultSubject sendNext:@"default"]; expect(values).to(equal((@[ @"default", @"default" ]))); }); qck_it(@"should send an error if key that was sent does not have an associated signal and there's no default", ^{ [[RACSignal switch:keySubject cases:@{ @0: subjectZero, @1: subjectOne, } default:nil] subscribeNext:^(id x) { [values addObject:x]; } error:^(NSError *error) { lastError = error; }]; [keySubject sendNext:@0]; [subjectZero sendNext:@"zero"]; expect(values).to(equal(@[ @"zero" ])); expect(lastError).to(beNil()); [keySubject sendNext:nil]; expect(values).to(equal(@[ @"zero" ])); expect(lastError).notTo(beNil()); expect(lastError.domain).to(equal(RACSignalErrorDomain)); expect(@(lastError.code)).to(equal(@(RACSignalErrorNoMatchingCase))); }); qck_it(@"should match RACTupleNil case when a nil value is sent", ^{ [[RACSignal switch:keySubject cases:@{ RACTupleNil.tupleNil: subjectZero, } default:defaultSubject] subscribeNext:^(id x) { [values addObject:x]; }]; [keySubject sendNext:nil]; [subjectZero sendNext:@"zero"]; expect(values).to(equal(@[ @"zero" ])); }); }); qck_describe(@"+if:then:else", ^{ __block RACSubject *boolSubject; __block RACSubject *trueSubject; __block RACSubject *falseSubject; __block NSMutableArray *values; __block NSError *lastError = nil; __block BOOL completed = NO; qck_beforeEach(^{ boolSubject = [RACSubject subject]; trueSubject = [RACSubject subject]; falseSubject = [RACSubject subject]; values = [NSMutableArray array]; lastError = nil; completed = NO; [[RACSignal if:boolSubject then:trueSubject else:falseSubject] subscribeNext:^(id x) { expect(lastError).to(beNil()); expect(@(completed)).to(beFalsy()); [values addObject:x]; } error:^(NSError *error) { expect(lastError).to(beNil()); expect(@(completed)).to(beFalsy()); lastError = error; } completed:^{ expect(lastError).to(beNil()); expect(@(completed)).to(beFalsy()); completed = YES; }]; }); qck_it(@"should not send any values before a boolean is sent", ^{ [trueSubject sendNext:RACUnit.defaultUnit]; [falseSubject sendNext:RACUnit.defaultUnit]; expect(values).to(equal(@[])); expect(lastError).to(beNil()); expect(@(completed)).to(beFalsy()); }); qck_it(@"should send events based on the latest boolean", ^{ [boolSubject sendNext:@YES]; [trueSubject sendNext:@"foo"]; [falseSubject sendNext:@"buzz"]; [trueSubject sendNext:@"bar"]; NSArray *expected = @[ @"foo", @"bar" ]; expect(values).to(equal(expected)); expect(lastError).to(beNil()); expect(@(completed)).to(beFalsy()); [boolSubject sendNext:@NO]; [trueSubject sendNext:@"baz"]; [falseSubject sendNext:@"buzz"]; [trueSubject sendNext:@"barfoo"]; expected = @[ @"foo", @"bar", @"buzz" ]; expect(values).to(equal(expected)); expect(lastError).to(beNil()); expect(@(completed)).to(beFalsy()); [trueSubject sendError:[NSError errorWithDomain:@"" code:-1 userInfo:nil]]; expect(lastError).to(beNil()); [falseSubject sendError:[NSError errorWithDomain:@"" code:-1 userInfo:nil]]; expect(lastError).notTo(beNil()); }); qck_it(@"should not send completed when only the BOOL signal completes", ^{ [boolSubject sendNext:@YES]; [trueSubject sendNext:@"foo"]; [boolSubject sendCompleted]; expect(values).to(equal(@[ @"foo" ])); expect(@(completed)).to(beFalsy()); }); qck_it(@"should send completed when the BOOL signal and the latest sent signal complete", ^{ [boolSubject sendNext:@YES]; [trueSubject sendNext:@"foo"]; [trueSubject sendCompleted]; [boolSubject sendCompleted]; expect(values).to(equal(@[ @"foo" ])); expect(@(completed)).to(beTruthy()); }); }); qck_describe(@"+interval:onScheduler: and +interval:onScheduler:withLeeway:", ^{ static const NSTimeInterval interval = 0.1; static const NSTimeInterval leeway = 0.2; __block void (^testTimer)(RACSignal *, NSNumber *, NSNumber *) = nil; qck_beforeEach(^{ testTimer = [^(RACSignal *timer, NSNumber *minInterval, NSNumber *leeway) { __block NSUInteger nextsReceived = 0; NSTimeInterval startTime = NSDate.timeIntervalSinceReferenceDate; [[timer take:3] subscribeNext:^(NSDate *date) { ++nextsReceived; NSTimeInterval currentTime = date.timeIntervalSinceReferenceDate; // Uniformly distribute the expected interval for all // received values. We do this instead of saving a timestamp // because a delayed interval may cause the _next_ value to // send sooner than the interval. NSTimeInterval expectedMinInterval = minInterval.doubleValue * nextsReceived; NSTimeInterval expectedMaxInterval = expectedMinInterval + leeway.doubleValue * 3 + 0.1; expect(@(currentTime - startTime)).to(beGreaterThanOrEqualTo(@(expectedMinInterval))); expect(@(currentTime - startTime)).to(beLessThanOrEqualTo(@(expectedMaxInterval))); }]; expect(@(nextsReceived)).toEventually(equal(@3)); } copy]; }); qck_describe(@"+interval:onScheduler:", ^{ qck_it(@"should work on the main thread scheduler", ^{ testTimer([RACSignal interval:interval onScheduler:RACScheduler.mainThreadScheduler], @(interval), @0); }); qck_it(@"should work on a background scheduler", ^{ testTimer([RACSignal interval:interval onScheduler:[RACScheduler scheduler]], @(interval), @0); }); }); qck_describe(@"+interval:onScheduler:withLeeway:", ^{ qck_it(@"should work on the main thread scheduler", ^{ testTimer([RACSignal interval:interval onScheduler:RACScheduler.mainThreadScheduler withLeeway:leeway], @(interval), @(leeway)); }); qck_it(@"should work on a background scheduler", ^{ testTimer([RACSignal interval:interval onScheduler:[RACScheduler scheduler] withLeeway:leeway], @(interval), @(leeway)); }); }); }); qck_describe(@"-timeout:onScheduler:", ^{ __block RACSubject *subject; qck_beforeEach(^{ subject = [RACSubject subject]; }); qck_it(@"should time out", ^{ RACTestScheduler *scheduler = [[RACTestScheduler alloc] init]; __block NSError *receivedError = nil; [[subject timeout:1 onScheduler:scheduler] subscribeError:^(NSError *e) { receivedError = e; }]; expect(receivedError).to(beNil()); [scheduler stepAll]; expect(receivedError).toEventuallyNot(beNil()); expect(receivedError.domain).to(equal(RACSignalErrorDomain)); expect(@(receivedError.code)).to(equal(@(RACSignalErrorTimedOut))); }); qck_it(@"should pass through events while not timed out", ^{ __block id next = nil; __block BOOL completed = NO; [[subject timeout:1 onScheduler:RACScheduler.mainThreadScheduler] subscribeNext:^(id x) { next = x; } completed:^{ completed = YES; }]; [subject sendNext:RACUnit.defaultUnit]; expect(next).to(equal(RACUnit.defaultUnit)); [subject sendCompleted]; expect(@(completed)).to(beTruthy()); }); qck_it(@"should not time out after disposal", ^{ RACTestScheduler *scheduler = [[RACTestScheduler alloc] init]; __block NSError *receivedError = nil; RACDisposable *disposable = [[subject timeout:1 onScheduler:scheduler] subscribeError:^(NSError *e) { receivedError = e; }]; [disposable dispose]; [scheduler stepAll]; expect(receivedError).to(beNil()); }); }); qck_describe(@"-delay:", ^{ __block RACSubject *subject; __block RACSignal *delayedSignal; qck_beforeEach(^{ subject = [RACSubject subject]; delayedSignal = [subject delay:0]; }); qck_it(@"should delay nexts", ^{ __block id next = nil; [delayedSignal subscribeNext:^(id x) { next = x; }]; [subject sendNext:@"foo"]; expect(next).to(beNil()); expect(next).toEventually(equal(@"foo")); }); qck_it(@"should delay completed", ^{ __block BOOL completed = NO; [delayedSignal subscribeCompleted:^{ completed = YES; }]; [subject sendCompleted]; expect(@(completed)).to(beFalsy()); expect(@(completed)).toEventually(beTruthy()); }); qck_it(@"should not delay errors", ^{ __block NSError *error = nil; [delayedSignal subscribeError:^(NSError *e) { error = e; }]; [subject sendError:RACSignalTestError]; expect(error).to(equal(RACSignalTestError)); }); qck_it(@"should cancel delayed events when disposed", ^{ __block id next = nil; RACDisposable *disposable = [delayedSignal subscribeNext:^(id x) { next = x; }]; [subject sendNext:@"foo"]; __block BOOL done = NO; [RACScheduler.mainThreadScheduler after:[NSDate date] schedule:^{ done = YES; }]; [disposable dispose]; expect(@(done)).toEventually(beTruthy()); expect(next).to(beNil()); }); }); qck_describe(@"-catch:", ^{ qck_it(@"should subscribe to ensuing signal on error", ^{ RACSubject *subject = [RACSubject subject]; RACSignal *signal = [subject catch:^(NSError *error) { return [RACSignal return:@41]; }]; __block id value = nil; [signal subscribeNext:^(id x) { value = x; }]; [subject sendError:RACSignalTestError]; expect(value).to(equal(@41)); }); qck_it(@"should prevent source error from propagating", ^{ RACSubject *subject = [RACSubject subject]; RACSignal *signal = [subject catch:^(NSError *error) { return [RACSignal empty]; }]; __block BOOL errorReceived = NO; [signal subscribeError:^(NSError *error) { errorReceived = YES; }]; [subject sendError:RACSignalTestError]; expect(@(errorReceived)).to(beFalsy()); }); qck_it(@"should propagate error from ensuing signal", ^{ RACSubject *subject = [RACSubject subject]; NSError *secondaryError = [NSError errorWithDomain:@"bubs" code:41 userInfo:nil]; RACSignal *signal = [subject catch:^(NSError *error) { return [RACSignal error:secondaryError]; }]; __block NSError *errorReceived = nil; [signal subscribeError:^(NSError *error) { errorReceived = error; }]; [subject sendError:RACSignalTestError]; expect(errorReceived).to(equal(secondaryError)); }); qck_it(@"should dispose ensuing signal", ^{ RACSubject *subject = [RACSubject subject]; __block BOOL disposed = NO; RACSignal *signal = [subject catch:^(NSError *error) { return [RACSignal createSignal:^(id subscriber) { return [RACDisposable disposableWithBlock:^{ disposed = YES; }]; }]; }]; RACDisposable *disposable = [signal subscribeCompleted:^{}]; [subject sendError:RACSignalTestError]; [disposable dispose]; expect(@(disposed)).toEventually(beTruthy()); }); }); qck_describe(@"+try:", ^{ __block id value; __block NSError *receivedError; qck_beforeEach(^{ value = nil; receivedError = nil; }); qck_it(@"should pass the value if it is non-nil", ^{ RACSignal *signal = [RACSignal try:^(NSError **error) { return @"foo"; }]; [signal subscribeNext:^(id x) { value = x; } error:^(NSError *error) { receivedError = error; }]; expect(value).to(equal(@"foo")); expect(receivedError).to(beNil()); }); qck_it(@"should ignore the error if the value is non-nil", ^{ RACSignal *signal = [RACSignal try:^(NSError **error) { if (error != nil) *error = RACSignalTestError; return @"foo"; }]; [signal subscribeNext:^(id x) { value = x; } error:^(NSError *error) { receivedError = error; }]; expect(receivedError).to(beNil()); expect(value).to(equal(@"foo")); }); qck_it(@"should send the error if the return value is nil", ^{ RACSignal *signal = [RACSignal try:^id(NSError **error) { if (error) *error = RACSignalTestError; return nil; }]; [signal subscribeNext:^(id x) { value = x; } error:^(NSError *error) { receivedError = error; }]; expect(value).to(beNil()); expect(receivedError).to(equal(RACSignalTestError)); }); }); qck_describe(@"-try:", ^{ __block RACSubject *subject; __block NSError *receivedError; __block NSMutableArray *nextValues; __block BOOL completed; qck_beforeEach(^{ subject = [RACSubject subject]; nextValues = [NSMutableArray array]; completed = NO; receivedError = nil; [[subject try:^(NSString *value, NSError **error) { if (value != nil) return YES; if (error != nil) *error = RACSignalTestError; return NO; }] subscribeNext:^(id x) { [nextValues addObject:x]; } error:^(NSError *error) { receivedError = error; } completed:^{ completed = YES; }]; }); qck_it(@"should pass values while YES is returned from the tryBlock", ^{ [subject sendNext:@"foo"]; [subject sendNext:@"bar"]; [subject sendNext:@"baz"]; [subject sendNext:@"buzz"]; [subject sendCompleted]; NSArray *receivedValues = [nextValues copy]; NSArray *expectedValues = @[ @"foo", @"bar", @"baz", @"buzz" ]; expect(receivedError).to(beNil()); expect(receivedValues).to(equal(expectedValues)); expect(@(completed)).to(beTruthy()); }); qck_it(@"should pass values until NO is returned from the tryBlock", ^{ [subject sendNext:@"foo"]; [subject sendNext:@"bar"]; [subject sendNext:nil]; [subject sendNext:@"buzz"]; [subject sendCompleted]; NSArray *receivedValues = [nextValues copy]; NSArray *expectedValues = @[ @"foo", @"bar" ]; expect(receivedError).to(equal(RACSignalTestError)); expect(receivedValues).to(equal(expectedValues)); expect(@(completed)).to(beFalsy()); }); }); qck_describe(@"-tryMap:", ^{ __block RACSubject *subject; __block NSError *receivedError; __block NSMutableArray *nextValues; __block BOOL completed; qck_beforeEach(^{ subject = [RACSubject subject]; nextValues = [NSMutableArray array]; completed = NO; receivedError = nil; [[subject tryMap:^ id (NSString *value, NSError **error) { if (value != nil) return [NSString stringWithFormat:@"%@_a", value]; if (error != nil) *error = RACSignalTestError; return nil; }] subscribeNext:^(id x) { [nextValues addObject:x]; } error:^(NSError *error) { receivedError = error; } completed:^{ completed = YES; }]; }); qck_it(@"should map values with the mapBlock", ^{ [subject sendNext:@"foo"]; [subject sendNext:@"bar"]; [subject sendNext:@"baz"]; [subject sendNext:@"buzz"]; [subject sendCompleted]; NSArray *receivedValues = [nextValues copy]; NSArray *expectedValues = @[ @"foo_a", @"bar_a", @"baz_a", @"buzz_a" ]; expect(receivedError).to(beNil()); expect(receivedValues).to(equal(expectedValues)); expect(@(completed)).to(beTruthy()); }); qck_it(@"should map values with the mapBlock, until the mapBlock returns nil", ^{ [subject sendNext:@"foo"]; [subject sendNext:@"bar"]; [subject sendNext:nil]; [subject sendNext:@"buzz"]; [subject sendCompleted]; NSArray *receivedValues = [nextValues copy]; NSArray *expectedValues = @[ @"foo_a", @"bar_a" ]; expect(receivedError).to(equal(RACSignalTestError)); expect(receivedValues).to(equal(expectedValues)); expect(@(completed)).to(beFalsy()); }); }); qck_describe(@"throttling", ^{ __block RACSubject *subject; qck_beforeEach(^{ subject = [RACSubject subject]; }); qck_describe(@"-throttle:", ^{ __block RACSignal *throttledSignal; qck_beforeEach(^{ throttledSignal = [subject throttle:0]; }); qck_it(@"should throttle nexts", ^{ NSMutableArray *valuesReceived = [NSMutableArray array]; [throttledSignal subscribeNext:^(id x) { [valuesReceived addObject:x]; }]; [subject sendNext:@"foo"]; [subject sendNext:@"bar"]; expect(valuesReceived).to(equal(@[])); NSArray *expected = @[ @"bar" ]; expect(valuesReceived).toEventually(equal(expected)); [subject sendNext:@"buzz"]; expect(valuesReceived).to(equal(expected)); expected = @[ @"bar", @"buzz" ]; expect(valuesReceived).toEventually(equal(expected)); }); qck_it(@"should forward completed immediately", ^{ __block BOOL completed = NO; [throttledSignal subscribeCompleted:^{ completed = YES; }]; [subject sendCompleted]; expect(@(completed)).to(beTruthy()); }); qck_it(@"should forward errors immediately", ^{ __block NSError *error = nil; [throttledSignal subscribeError:^(NSError *e) { error = e; }]; [subject sendError:RACSignalTestError]; expect(error).to(equal(RACSignalTestError)); }); qck_it(@"should cancel future nexts when disposed", ^{ __block id next = nil; RACDisposable *disposable = [throttledSignal subscribeNext:^(id x) { next = x; }]; [subject sendNext:@"foo"]; __block BOOL done = NO; [RACScheduler.mainThreadScheduler after:[NSDate date] schedule:^{ done = YES; }]; [disposable dispose]; expect(@(done)).toEventually(beTruthy()); expect(next).to(beNil()); }); }); qck_describe(@"-throttle:valuesPassingTest:", ^{ __block RACSignal *throttledSignal; __block BOOL shouldThrottle; qck_beforeEach(^{ shouldThrottle = YES; __block id value = nil; throttledSignal = [[subject doNext:^(id x) { value = x; }] throttle:0 valuesPassingTest:^(id x) { // Make sure that we're given the latest value. expect(x).to(beIdenticalTo(value)); return shouldThrottle; }]; expect(throttledSignal).notTo(beNil()); }); qck_describe(@"nexts", ^{ __block NSMutableArray *valuesReceived; __block NSMutableArray *expected; qck_beforeEach(^{ expected = [[NSMutableArray alloc] init]; valuesReceived = [[NSMutableArray alloc] init]; [throttledSignal subscribeNext:^(id x) { [valuesReceived addObject:x]; }]; }); qck_it(@"should forward unthrottled values immediately", ^{ shouldThrottle = NO; [subject sendNext:@"foo"]; [expected addObject:@"foo"]; expect(valuesReceived).to(equal(expected)); }); qck_it(@"should delay throttled values", ^{ [subject sendNext:@"bar"]; expect(valuesReceived).to(equal(expected)); [expected addObject:@"bar"]; expect(valuesReceived).toEventually(equal(expected)); }); qck_it(@"should drop buffered values when a throttled value arrives", ^{ [subject sendNext:@"foo"]; [subject sendNext:@"bar"]; [subject sendNext:@"buzz"]; expect(valuesReceived).to(equal(expected)); [expected addObject:@"buzz"]; expect(valuesReceived).toEventually(equal(expected)); }); qck_it(@"should drop buffered values when an immediate value arrives", ^{ [subject sendNext:@"foo"]; [subject sendNext:@"bar"]; shouldThrottle = NO; [subject sendNext:@"buzz"]; [expected addObject:@"buzz"]; expect(valuesReceived).to(equal(expected)); // Make sure that nothing weird happens when sending another // throttled value. shouldThrottle = YES; [subject sendNext:@"baz"]; expect(valuesReceived).to(equal(expected)); [expected addObject:@"baz"]; expect(valuesReceived).toEventually(equal(expected)); }); qck_it(@"should not be resent upon completion", ^{ [subject sendNext:@"bar"]; [expected addObject:@"bar"]; expect(valuesReceived).toEventually(equal(expected)); [subject sendCompleted]; expect(valuesReceived).to(equal(expected)); }); }); qck_it(@"should forward completed immediately", ^{ __block BOOL completed = NO; [throttledSignal subscribeCompleted:^{ completed = YES; }]; [subject sendCompleted]; expect(@(completed)).to(beTruthy()); }); qck_it(@"should forward errors immediately", ^{ __block NSError *error = nil; [throttledSignal subscribeError:^(NSError *e) { error = e; }]; [subject sendError:RACSignalTestError]; expect(error).to(equal(RACSignalTestError)); }); qck_it(@"should cancel future nexts when disposed", ^{ __block id next = nil; RACDisposable *disposable = [throttledSignal subscribeNext:^(id x) { next = x; }]; [subject sendNext:@"foo"]; __block BOOL done = NO; [RACScheduler.mainThreadScheduler after:[NSDate date] schedule:^{ done = YES; }]; [disposable dispose]; expect(@(done)).toEventually(beTruthy()); expect(next).to(beNil()); }); }); }); qck_describe(@"-then:", ^{ qck_it(@"should continue onto returned signal", ^{ RACSubject *subject = [RACSubject subject]; __block id value = nil; [[subject then:^{ return [RACSignal return:@2]; }] subscribeNext:^(id x) { value = x; }]; [subject sendNext:@1]; // The value shouldn't change until the first signal completes. expect(value).to(beNil()); [subject sendCompleted]; expect(value).to(equal(@2)); }); qck_it(@"should sequence even if no next value is sent", ^{ RACSubject *subject = [RACSubject subject]; __block id value = nil; [[subject then:^{ return [RACSignal return:RACUnit.defaultUnit]; }] subscribeNext:^(id x) { value = x; }]; [subject sendCompleted]; expect(value).to(equal(RACUnit.defaultUnit)); }); }); qck_describe(@"-sequence", ^{ RACSignal *signal = [RACSignal createSignal:^ RACDisposable * (id subscriber) { [subscriber sendNext:@1]; [subscriber sendNext:@2]; [subscriber sendNext:@3]; [subscriber sendNext:@4]; [subscriber sendCompleted]; return nil; }]; qck_itBehavesLike(RACSequenceExamples, ^{ return @{ RACSequenceExampleSequence: signal.sequence, RACSequenceExampleExpectedValues: @[ @1, @2, @3, @4 ] }; }); }); qck_it(@"should complete take: even if the original signal doesn't", ^{ RACSignal *sendOne = [RACSignal createSignal:^ RACDisposable * (id subscriber) { [subscriber sendNext:RACUnit.defaultUnit]; return nil; }]; __block id value = nil; __block BOOL completed = NO; [[sendOne take:1] subscribeNext:^(id received) { value = received; } completed:^{ completed = YES; }]; expect(value).to(equal(RACUnit.defaultUnit)); expect(@(completed)).to(beTruthy()); }); qck_it(@"should complete take: even if the signal is recursive", ^{ RACSubject *subject = [RACSubject subject]; const NSUInteger number = 3; const NSUInteger guard = number + 1; NSMutableArray *values = NSMutableArray.array; __block BOOL completed = NO; [[subject take:number] subscribeNext:^(NSNumber* received) { [values addObject:received]; if (values.count >= guard) { [subject sendError:RACSignalTestError]; } [subject sendNext:@(received.integerValue + 1)]; } completed:^{ completed = YES; }]; [subject sendNext:@0]; NSMutableArray* expectedValues = [NSMutableArray arrayWithCapacity:number]; for (NSUInteger i = 0 ; i < number ; ++i) { [expectedValues addObject:@(i)]; } expect(values).to(equal(expectedValues)); expect(@(completed)).to(beTruthy()); }); qck_describe(@"+zip:", ^{ __block RACSubject *subject1 = nil; __block RACSubject *subject2 = nil; __block BOOL hasSentError = NO; __block BOOL hasSentCompleted = NO; __block RACDisposable *disposable = nil; __block void (^send2NextAndErrorTo1)(void) = nil; __block void (^send3NextAndErrorTo1)(void) = nil; __block void (^send2NextAndCompletedTo2)(void) = nil; __block void (^send3NextAndCompletedTo2)(void) = nil; qck_beforeEach(^{ send2NextAndErrorTo1 = [^{ [subject1 sendNext:@1]; [subject1 sendNext:@2]; [subject1 sendError:RACSignalTestError]; } copy]; send3NextAndErrorTo1 = [^{ [subject1 sendNext:@1]; [subject1 sendNext:@2]; [subject1 sendNext:@3]; [subject1 sendError:RACSignalTestError]; } copy]; send2NextAndCompletedTo2 = [^{ [subject2 sendNext:@1]; [subject2 sendNext:@2]; [subject2 sendCompleted]; } copy]; send3NextAndCompletedTo2 = [^{ [subject2 sendNext:@1]; [subject2 sendNext:@2]; [subject2 sendNext:@3]; [subject2 sendCompleted]; } copy]; subject1 = [RACSubject subject]; subject2 = [RACSubject subject]; hasSentError = NO; hasSentCompleted = NO; disposable = [[RACSignal zip:@[ subject1, subject2 ]] subscribeError:^(NSError *error) { hasSentError = YES; } completed:^{ hasSentCompleted = YES; }]; }); qck_afterEach(^{ [disposable dispose]; }); qck_it(@"should complete as soon as no new zipped values are possible", ^{ [subject1 sendNext:@1]; [subject2 sendNext:@1]; expect(@(hasSentCompleted)).to(beFalsy()); [subject1 sendNext:@2]; [subject1 sendCompleted]; expect(@(hasSentCompleted)).to(beFalsy()); [subject2 sendNext:@2]; expect(@(hasSentCompleted)).to(beTruthy()); }); qck_it(@"outcome should not be dependent on order of signals", ^{ [subject2 sendCompleted]; expect(@(hasSentCompleted)).to(beTruthy()); }); qck_it(@"should forward errors sent earlier than (time-wise) and before (position-wise) a complete", ^{ send2NextAndErrorTo1(); send3NextAndCompletedTo2(); expect(@(hasSentError)).to(beTruthy()); expect(@(hasSentCompleted)).to(beFalsy()); }); qck_it(@"should forward errors sent earlier than (time-wise) and after (position-wise) a complete", ^{ send3NextAndErrorTo1(); send2NextAndCompletedTo2(); expect(@(hasSentError)).to(beTruthy()); expect(@(hasSentCompleted)).to(beFalsy()); }); qck_it(@"should forward errors sent later than (time-wise) and before (position-wise) a complete", ^{ send3NextAndCompletedTo2(); send2NextAndErrorTo1(); expect(@(hasSentError)).to(beTruthy()); expect(@(hasSentCompleted)).to(beFalsy()); }); qck_it(@"should ignore errors sent later than (time-wise) and after (position-wise) a complete", ^{ send2NextAndCompletedTo2(); send3NextAndErrorTo1(); expect(@(hasSentError)).to(beFalsy()); expect(@(hasSentCompleted)).to(beTruthy()); }); qck_it(@"should handle signals sending values unevenly", ^{ __block NSError *receivedError = nil; __block BOOL hasCompleted = NO; RACSubject *a = [RACSubject subject]; RACSubject *b = [RACSubject subject]; RACSubject *c = [RACSubject subject]; NSMutableArray *receivedValues = NSMutableArray.array; NSArray *expectedValues = nil; [[RACSignal zip:@[ a, b, c ] reduce:^(NSNumber *a, NSNumber *b, NSNumber *c) { return [NSString stringWithFormat:@"%@%@%@", a, b, c]; }] subscribeNext:^(id x) { [receivedValues addObject:x]; } error:^(NSError *error) { receivedError = error; } completed:^{ hasCompleted = YES; }]; [a sendNext:@1]; [a sendNext:@2]; [a sendNext:@3]; [b sendNext:@1]; [c sendNext:@1]; [c sendNext:@2]; // a: [===......] // b: [=........] // c: [==.......] expectedValues = @[ @"111" ]; expect(receivedValues).to(equal(expectedValues)); expect(receivedError).to(beNil()); expect(@(hasCompleted)).to(beFalsy()); [b sendNext:@2]; [b sendNext:@3]; [b sendNext:@4]; [b sendCompleted]; // a: [===......] // b: [====C....] // c: [==.......] expectedValues = @[ @"111", @"222" ]; expect(receivedValues).to(equal(expectedValues)); expect(receivedError).to(beNil()); expect(@(hasCompleted)).to(beFalsy()); [c sendNext:@3]; [c sendNext:@4]; [c sendNext:@5]; [c sendError:RACSignalTestError]; // a: [===......] // b: [====C....] // c: [=====E...] expectedValues = @[ @"111", @"222", @"333" ]; expect(receivedValues).to(equal(expectedValues)); expect(receivedError).to(equal(RACSignalTestError)); expect(@(hasCompleted)).to(beFalsy()); [a sendNext:@4]; [a sendNext:@5]; [a sendNext:@6]; [a sendNext:@7]; // a: [=======..] // b: [====C....] // c: [=====E...] expectedValues = @[ @"111", @"222", @"333" ]; expect(receivedValues).to(equal(expectedValues)); expect(receivedError).to(equal(RACSignalTestError)); expect(@(hasCompleted)).to(beFalsy()); }); qck_it(@"should handle multiples of the same side-effecting signal", ^{ __block NSUInteger counter = 0; RACSignal *sideEffectingSignal = [RACSignal createSignal:^ RACDisposable * (id subscriber) { ++counter; [subscriber sendNext:@1]; [subscriber sendCompleted]; return nil; }]; RACSignal *combined = [RACSignal zip:@[ sideEffectingSignal, sideEffectingSignal ] reduce:^ NSString * (id x, id y) { return [NSString stringWithFormat:@"%@%@", x, y]; }]; NSMutableArray *receivedValues = NSMutableArray.array; expect(@(counter)).to(equal(@0)); [combined subscribeNext:^(id x) { [receivedValues addObject:x]; }]; expect(@(counter)).to(equal(@2)); expect(receivedValues).to(equal(@[ @"11" ])); }); }); qck_describe(@"-sample:", ^{ qck_it(@"should send the latest value when the sampler signal fires", ^{ RACSubject *subject = [RACSubject subject]; RACSubject *sampleSubject = [RACSubject subject]; RACSignal *sampled = [subject sample:sampleSubject]; NSMutableArray *values = [NSMutableArray array]; [sampled subscribeNext:^(id x) { [values addObject:x]; }]; [sampleSubject sendNext:RACUnit.defaultUnit]; expect(values).to(equal(@[])); [subject sendNext:@1]; [subject sendNext:@2]; expect(values).to(equal(@[])); [sampleSubject sendNext:RACUnit.defaultUnit]; NSArray *expected = @[ @2 ]; expect(values).to(equal(expected)); [subject sendNext:@3]; expect(values).to(equal(expected)); [sampleSubject sendNext:RACUnit.defaultUnit]; expected = @[ @2, @3 ]; expect(values).to(equal(expected)); [sampleSubject sendNext:RACUnit.defaultUnit]; expected = @[ @2, @3, @3 ]; expect(values).to(equal(expected)); }); }); qck_describe(@"-collect", ^{ __block RACSubject *subject; __block RACSignal *collected; __block id value; __block BOOL hasCompleted; qck_beforeEach(^{ subject = [RACSubject subject]; collected = [subject collect]; value = nil; hasCompleted = NO; [collected subscribeNext:^(id x) { value = x; } completed:^{ hasCompleted = YES; }]; }); qck_it(@"should send a single array when the original signal completes", ^{ NSArray *expected = @[ @1, @2, @3 ]; [subject sendNext:@1]; [subject sendNext:@2]; [subject sendNext:@3]; expect(value).to(beNil()); [subject sendCompleted]; expect(value).to(equal(expected)); expect(@(hasCompleted)).to(beTruthy()); }); qck_it(@"should add NSNull to an array for nil values", ^{ NSArray *expected = @[ NSNull.null, @1, NSNull.null ]; [subject sendNext:nil]; [subject sendNext:@1]; [subject sendNext:nil]; expect(value).to(beNil()); [subject sendCompleted]; expect(value).to(equal(expected)); expect(@(hasCompleted)).to(beTruthy()); }); }); qck_describe(@"-bufferWithTime:onScheduler:", ^{ __block RACTestScheduler *scheduler; __block RACSubject *input; __block RACSignal *bufferedInput; __block RACTuple *latestValue; qck_beforeEach(^{ scheduler = [[RACTestScheduler alloc] init]; input = [RACSubject subject]; bufferedInput = [input bufferWithTime:1 onScheduler:scheduler]; latestValue = nil; [bufferedInput subscribeNext:^(RACTuple *x) { latestValue = x; }]; }); qck_it(@"should buffer nexts", ^{ [input sendNext:@1]; [input sendNext:@2]; [scheduler stepAll]; expect(latestValue).to(equal(RACTuplePack(@1, @2))); [input sendNext:@3]; [input sendNext:@4]; [scheduler stepAll]; expect(latestValue).to(equal(RACTuplePack(@3, @4))); }); qck_it(@"should not perform buffering until a value is sent", ^{ [input sendNext:@1]; [input sendNext:@2]; [scheduler stepAll]; expect(latestValue).to(equal(RACTuplePack(@1, @2))); [scheduler stepAll]; expect(latestValue).to(equal(RACTuplePack(@1, @2))); [input sendNext:@3]; [input sendNext:@4]; [scheduler stepAll]; expect(latestValue).to(equal(RACTuplePack(@3, @4))); }); qck_it(@"should flush any buffered nexts upon completion", ^{ [input sendNext:@1]; [input sendCompleted]; [scheduler stepAll]; expect(latestValue).to(equal(RACTuplePack(@1))); }); qck_it(@"should support NSNull values", ^{ [input sendNext:NSNull.null]; [scheduler stepAll]; expect(latestValue).to(equal(RACTuplePack(NSNull.null))); }); qck_it(@"should buffer nil values", ^{ [input sendNext:nil]; [scheduler stepAll]; expect(latestValue).to(equal(RACTuplePack(nil))); }); }); qck_describe(@"-concat", ^{ __block RACSubject *subject; __block RACSignal *oneSignal; __block RACSignal *twoSignal; __block RACSignal *threeSignal; __block RACSignal *errorSignal; __block RACSignal *completedSignal; qck_beforeEach(^{ subject = [RACReplaySubject subject]; oneSignal = [RACSignal return:@1]; twoSignal = [RACSignal return:@2]; threeSignal = [RACSignal return:@3]; errorSignal = [RACSignal error:RACSignalTestError]; completedSignal = RACSignal.empty; }); qck_it(@"should concatenate the values of inner signals", ^{ [subject sendNext:oneSignal]; [subject sendNext:twoSignal]; [subject sendNext:completedSignal]; [subject sendNext:threeSignal]; NSMutableArray *values = [NSMutableArray array]; [[subject concat] subscribeNext:^(id x) { [values addObject:x]; }]; NSArray *expected = @[ @1, @2, @3 ]; expect(values).to(equal(expected)); }); qck_it(@"should complete only after all signals complete", ^{ RACReplaySubject *valuesSubject = [RACReplaySubject subject]; [subject sendNext:valuesSubject]; [subject sendCompleted]; [valuesSubject sendNext:@1]; [valuesSubject sendNext:@2]; [valuesSubject sendCompleted]; NSArray *expected = @[ @1, @2 ]; expect([[subject concat] toArray]).to(equal(expected)); }); qck_it(@"should pass through errors", ^{ [subject sendNext:errorSignal]; NSError *error = nil; [[subject concat] firstOrDefault:nil success:NULL error:&error]; expect(error).to(equal(RACSignalTestError)); }); qck_it(@"should concat signals sent later", ^{ [subject sendNext:oneSignal]; NSMutableArray *values = [NSMutableArray array]; [[subject concat] subscribeNext:^(id x) { [values addObject:x]; }]; NSArray *expected = @[ @1 ]; expect(values).to(equal(expected)); [subject sendNext:[twoSignal delay:0]]; expected = @[ @1, @2 ]; expect(values).toEventually(equal(expected)); [subject sendNext:threeSignal]; expected = @[ @1, @2, @3 ]; expect(values).to(equal(expected)); }); qck_it(@"should dispose the current signal", ^{ __block BOOL disposed = NO; __block id innerSubscriber = nil; RACSignal *innerSignal = [RACSignal createSignal:^(id subscriber) { // Keep the subscriber alive so it doesn't trigger disposal on dealloc innerSubscriber = subscriber; return [RACDisposable disposableWithBlock:^{ disposed = YES; }]; }]; RACDisposable *concatDisposable = [[subject concat] subscribeCompleted:^{}]; [subject sendNext:innerSignal]; expect(@(disposed)).notTo(beTruthy()); [concatDisposable dispose]; expect(@(disposed)).to(beTruthy()); }); qck_it(@"should dispose later signals", ^{ __block BOOL disposed = NO; __block id laterSubscriber = nil; RACSignal *laterSignal = [RACSignal createSignal:^(id subscriber) { // Keep the subscriber alive so it doesn't trigger disposal on dealloc laterSubscriber = subscriber; return [RACDisposable disposableWithBlock:^{ disposed = YES; }]; }]; RACSubject *firstSignal = [RACSubject subject]; RACSignal *outerSignal = [RACSignal createSignal:^ id (id subscriber) { [subscriber sendNext:firstSignal]; [subscriber sendNext:laterSignal]; return nil; }]; RACDisposable *concatDisposable = [[outerSignal concat] subscribeCompleted:^{}]; [firstSignal sendCompleted]; expect(@(disposed)).notTo(beTruthy()); [concatDisposable dispose]; expect(@(disposed)).to(beTruthy()); }); }); qck_describe(@"-initially:", ^{ __block RACSubject *subject; __block NSUInteger initiallyInvokedCount; __block RACSignal *signal; qck_beforeEach(^{ subject = [RACSubject subject]; initiallyInvokedCount = 0; signal = [subject initially:^{ ++initiallyInvokedCount; }]; }); qck_it(@"should not run without a subscription", ^{ [subject sendCompleted]; expect(@(initiallyInvokedCount)).to(equal(@0)); }); qck_it(@"should run on subscription", ^{ [signal subscribe:[RACSubscriber new]]; expect(@(initiallyInvokedCount)).to(equal(@1)); }); qck_it(@"should re-run for each subscription", ^{ [signal subscribe:[RACSubscriber new]]; [signal subscribe:[RACSubscriber new]]; expect(@(initiallyInvokedCount)).to(equal(@2)); }); }); qck_describe(@"-finally:", ^{ __block RACSubject *subject; __block BOOL finallyInvoked; __block RACSignal *signal; qck_beforeEach(^{ subject = [RACSubject subject]; finallyInvoked = NO; signal = [subject finally:^{ finallyInvoked = YES; }]; }); qck_it(@"should not run finally without a subscription", ^{ [subject sendCompleted]; expect(@(finallyInvoked)).to(beFalsy()); }); qck_describe(@"with a subscription", ^{ __block RACDisposable *disposable; qck_beforeEach(^{ disposable = [signal subscribeCompleted:^{}]; }); qck_afterEach(^{ [disposable dispose]; }); qck_it(@"should not run finally upon next", ^{ [subject sendNext:RACUnit.defaultUnit]; expect(@(finallyInvoked)).to(beFalsy()); }); qck_it(@"should run finally upon completed", ^{ [subject sendCompleted]; expect(@(finallyInvoked)).to(beTruthy()); }); qck_it(@"should run finally upon error", ^{ [subject sendError:nil]; expect(@(finallyInvoked)).to(beTruthy()); }); }); }); qck_describe(@"-ignoreValues", ^{ __block RACSubject *subject; __block BOOL gotNext; __block BOOL gotCompleted; __block NSError *receivedError; qck_beforeEach(^{ subject = [RACSubject subject]; gotNext = NO; gotCompleted = NO; receivedError = nil; [[subject ignoreValues] subscribeNext:^(id _) { gotNext = YES; } error:^(NSError *error) { receivedError = error; } completed:^{ gotCompleted = YES; }]; }); qck_it(@"should skip nexts and pass through completed", ^{ [subject sendNext:RACUnit.defaultUnit]; [subject sendCompleted]; expect(@(gotNext)).to(beFalsy()); expect(@(gotCompleted)).to(beTruthy()); expect(receivedError).to(beNil()); }); qck_it(@"should skip nexts and pass through errors", ^{ [subject sendNext:RACUnit.defaultUnit]; [subject sendError:RACSignalTestError]; expect(@(gotNext)).to(beFalsy()); expect(@(gotCompleted)).to(beFalsy()); expect(receivedError).to(equal(RACSignalTestError)); }); }); qck_describe(@"-materialize", ^{ qck_it(@"should convert nexts and completed into RACEvents", ^{ NSArray *events = [[[RACSignal return:RACUnit.defaultUnit] materialize] toArray]; NSArray *expected = @[ [RACEvent eventWithValue:RACUnit.defaultUnit], RACEvent.completedEvent ]; expect(events).to(equal(expected)); }); qck_it(@"should convert errors into RACEvents and complete", ^{ NSArray *events = [[[RACSignal error:RACSignalTestError] materialize] toArray]; NSArray *expected = @[ [RACEvent eventWithError:RACSignalTestError] ]; expect(events).to(equal(expected)); }); }); qck_describe(@"-dematerialize", ^{ qck_it(@"should convert nexts from RACEvents", ^{ RACSignal *events = [RACSignal createSignal:^ id (id subscriber) { [subscriber sendNext:[RACEvent eventWithValue:@1]]; [subscriber sendNext:[RACEvent eventWithValue:@2]]; [subscriber sendCompleted]; return nil; }]; NSArray *expected = @[ @1, @2 ]; expect([[events dematerialize] toArray]).to(equal(expected)); }); qck_it(@"should convert completed from a RACEvent", ^{ RACSignal *events = [RACSignal createSignal:^ id (id subscriber) { [subscriber sendNext:[RACEvent eventWithValue:@1]]; [subscriber sendNext:RACEvent.completedEvent]; [subscriber sendNext:[RACEvent eventWithValue:@2]]; [subscriber sendCompleted]; return nil; }]; NSArray *expected = @[ @1 ]; expect([[events dematerialize] toArray]).to(equal(expected)); }); qck_it(@"should convert error from a RACEvent", ^{ RACSignal *events = [RACSignal createSignal:^ id (id subscriber) { [subscriber sendNext:[RACEvent eventWithError:RACSignalTestError]]; [subscriber sendNext:[RACEvent eventWithValue:@1]]; [subscriber sendCompleted]; return nil; }]; __block NSError *error = nil; expect([[events dematerialize] firstOrDefault:nil success:NULL error:&error]).to(beNil()); expect(error).to(equal(RACSignalTestError)); }); }); qck_describe(@"-not", ^{ qck_it(@"should invert every BOOL sent", ^{ RACSubject *subject = [RACReplaySubject subject]; [subject sendNext:@NO]; [subject sendNext:@YES]; [subject sendCompleted]; NSArray *results = [[subject not] toArray]; NSArray *expected = @[ @YES, @NO ]; expect(results).to(equal(expected)); }); }); qck_describe(@"-and", ^{ qck_it(@"should return YES if all YES values are sent", ^{ RACSubject *subject = [RACReplaySubject subject]; [subject sendNext:RACTuplePack(@YES, @NO, @YES)]; [subject sendNext:RACTuplePack(@NO, @NO, @NO)]; [subject sendNext:RACTuplePack(@YES, @YES, @YES)]; [subject sendCompleted]; NSArray *results = [[subject and] toArray]; NSArray *expected = @[ @NO, @NO, @YES ]; expect(results).to(equal(expected)); }); }); qck_describe(@"-or", ^{ qck_it(@"should return YES for any YES values sent", ^{ RACSubject *subject = [RACReplaySubject subject]; [subject sendNext:RACTuplePack(@YES, @NO, @YES)]; [subject sendNext:RACTuplePack(@NO, @NO, @NO)]; [subject sendCompleted]; NSArray *results = [[subject or] toArray]; NSArray *expected = @[ @YES, @NO ]; expect(results).to(equal(expected)); }); }); qck_describe(@"-groupBy:", ^{ qck_it(@"should send completed to all grouped signals.", ^{ RACSubject *subject = [RACReplaySubject subject]; __block NSUInteger groupedSignalCount = 0; __block NSUInteger completedGroupedSignalCount = 0; [[subject groupBy:^(NSNumber *number) { return @(floorf(number.floatValue)); }] subscribeNext:^(RACGroupedSignal *groupedSignal) { ++groupedSignalCount; [groupedSignal subscribeCompleted:^{ ++completedGroupedSignalCount; }]; }]; [subject sendNext:@1]; [subject sendNext:@2]; [subject sendCompleted]; expect(@(completedGroupedSignalCount)).to(equal(@(groupedSignalCount))); }); qck_it(@"should send error to all grouped signals.", ^{ RACSubject *subject = [RACReplaySubject subject]; __block NSUInteger groupedSignalCount = 0; __block NSUInteger erroneousGroupedSignalCount = 0; [[subject groupBy:^(NSNumber *number) { return @(floorf(number.floatValue)); }] subscribeNext:^(RACGroupedSignal *groupedSignal) { ++groupedSignalCount; [groupedSignal subscribeError:^(NSError *error) { ++erroneousGroupedSignalCount; expect(error.domain).to(equal(@"TestDomain")); expect(@(error.code)).to(equal(@123)); }]; }]; [subject sendNext:@1]; [subject sendNext:@2]; [subject sendError:[NSError errorWithDomain:@"TestDomain" code:123 userInfo:nil]]; expect(@(erroneousGroupedSignalCount)).to(equal(@(groupedSignalCount))); }); qck_it(@"should send completed in the order grouped signals were created.", ^{ RACSubject *subject = [RACReplaySubject subject]; NSMutableArray *startedSignals = [NSMutableArray array]; NSMutableArray *completedSignals = [NSMutableArray array]; [[subject groupBy:^(NSNumber *number) { return @(number.integerValue % 4); }] subscribeNext:^(RACGroupedSignal *groupedSignal) { [startedSignals addObject:groupedSignal]; [groupedSignal subscribeCompleted:^{ [completedSignals addObject:groupedSignal]; }]; }]; for (NSInteger i = 0; i < 20; i++) { [subject sendNext:@(i)]; } [subject sendCompleted]; expect(completedSignals).to(equal(startedSignals)); }); }); qck_describe(@"starting signals", ^{ qck_describe(@"+startLazilyWithScheduler:block:", ^{ __block NSUInteger invokedCount = 0; __block void (^subscribe)(void); qck_beforeEach(^{ invokedCount = 0; RACSignal *signal = [RACSignal startLazilyWithScheduler:RACScheduler.immediateScheduler block:^(id subscriber) { invokedCount++; [subscriber sendNext:@42]; [subscriber sendCompleted]; }]; subscribe = [^{ [signal subscribe:[RACSubscriber subscriberWithNext:nil error:nil completed:nil]]; } copy]; }); qck_it(@"should only invoke the block on subscription", ^{ expect(@(invokedCount)).to(equal(@0)); subscribe(); expect(@(invokedCount)).to(equal(@1)); }); qck_it(@"should only invoke the block once", ^{ expect(@(invokedCount)).to(equal(@0)); subscribe(); expect(@(invokedCount)).to(equal(@1)); subscribe(); expect(@(invokedCount)).to(equal(@1)); subscribe(); expect(@(invokedCount)).to(equal(@1)); }); qck_it(@"should invoke the block on the given scheduler", ^{ RACScheduler *scheduler = [RACScheduler scheduler]; __block RACScheduler *currentScheduler; [[[RACSignal startLazilyWithScheduler:scheduler block:^(id subscriber) { currentScheduler = RACScheduler.currentScheduler; }] publish] connect]; expect(currentScheduler).toEventually(equal(scheduler)); }); }); qck_describe(@"+startEagerlyWithScheduler:block:", ^{ qck_it(@"should immediately invoke the block", ^{ __block BOOL blockInvoked = NO; [RACSignal startEagerlyWithScheduler:[RACScheduler scheduler] block:^(id subscriber) { blockInvoked = YES; }]; expect(@(blockInvoked)).toEventually(beTruthy()); }); qck_it(@"should only invoke the block once", ^{ __block NSUInteger invokedCount = 0; RACSignal *signal = [RACSignal startEagerlyWithScheduler:RACScheduler.immediateScheduler block:^(id subscriber) { invokedCount++; }]; expect(@(invokedCount)).to(equal(@1)); [[signal publish] connect]; expect(@(invokedCount)).to(equal(@1)); [[signal publish] connect]; expect(@(invokedCount)).to(equal(@1)); }); qck_it(@"should invoke the block on the given scheduler", ^{ RACScheduler *scheduler = [RACScheduler scheduler]; __block RACScheduler *currentScheduler; [RACSignal startEagerlyWithScheduler:scheduler block:^(id subscriber) { currentScheduler = RACScheduler.currentScheduler; }]; expect(currentScheduler).toEventually(equal(scheduler)); }); }); }); qck_describe(@"-toArray", ^{ __block RACSubject *subject; qck_beforeEach(^{ subject = [RACReplaySubject subject]; }); qck_it(@"should return an array which contains NSNulls for nil values", ^{ NSArray *expected = @[ NSNull.null, @1, NSNull.null ]; [subject sendNext:nil]; [subject sendNext:@1]; [subject sendNext:nil]; [subject sendCompleted]; expect([subject toArray]).to(equal(expected)); }); qck_it(@"should return nil upon error", ^{ [subject sendError:nil]; expect([subject toArray]).to(beNil()); }); qck_it(@"should return nil upon error even if some nexts were sent", ^{ [subject sendNext:@1]; [subject sendNext:@2]; [subject sendError:nil]; expect([subject toArray]).to(beNil()); }); }); qck_describe(@"-ignore:", ^{ qck_it(@"should ignore nil", ^{ RACSignal *signal = [[RACSignal createSignal:^ id (id subscriber) { [subscriber sendNext:@1]; [subscriber sendNext:nil]; [subscriber sendNext:@3]; [subscriber sendNext:@4]; [subscriber sendNext:nil]; [subscriber sendCompleted]; return nil; }] ignore:nil]; NSArray *expected = @[ @1, @3, @4 ]; expect([signal toArray]).to(equal(expected)); }); }); qck_describe(@"-replayLazily", ^{ __block NSUInteger subscriptionCount; __block BOOL disposed; __block RACSignal *signal; __block RACSubject *disposeSubject; __block RACSignal *replayedSignal; qck_beforeEach(^{ subscriptionCount = 0; disposed = NO; signal = [RACSignal createSignal:^ RACDisposable * (id subscriber) { subscriptionCount++; [subscriber sendNext:RACUnit.defaultUnit]; RACDisposable *schedulingDisposable = [RACScheduler.mainThreadScheduler schedule:^{ [subscriber sendNext:RACUnit.defaultUnit]; [subscriber sendCompleted]; }]; return [RACDisposable disposableWithBlock:^{ [schedulingDisposable dispose]; disposed = YES; }]; }]; disposeSubject = [RACSubject subject]; replayedSignal = [[signal takeUntil:disposeSubject] replayLazily]; }); qck_it(@"should forward the input signal upon subscription", ^{ expect(@(subscriptionCount)).to(equal(@0)); expect(@([replayedSignal asynchronouslyWaitUntilCompleted:NULL])).to(beTruthy()); expect(@(subscriptionCount)).to(equal(@1)); }); qck_it(@"should replay the input signal for future subscriptions", ^{ NSArray *events = [[[replayedSignal materialize] collect] asynchronousFirstOrDefault:nil success:NULL error:NULL]; expect(events).notTo(beNil()); expect([[[replayedSignal materialize] collect] asynchronousFirstOrDefault:nil success:NULL error:NULL]).to(equal(events)); expect(@(subscriptionCount)).to(equal(@1)); }); qck_it(@"should replay even after disposal", ^{ __block NSUInteger valueCount = 0; [replayedSignal subscribeNext:^(id x) { valueCount++; }]; [disposeSubject sendCompleted]; expect(@(valueCount)).to(equal(@1)); expect(@([[replayedSignal toArray] count])).to(equal(@(valueCount))); }); }); qck_describe(@"-reduceApply", ^{ qck_it(@"should apply a block to the rest of a tuple", ^{ RACSubject *subject = [RACReplaySubject subject]; id sum = ^(NSNumber *a, NSNumber *b) { return @(a.intValue + b.intValue); }; id madd = ^(NSNumber *a, NSNumber *b, NSNumber *c) { return @(a.intValue * b.intValue + c.intValue); }; [subject sendNext:RACTuplePack(sum, @1, @2)]; [subject sendNext:RACTuplePack(madd, @2, @3, @1)]; [subject sendCompleted]; NSArray *results = [[subject reduceApply] toArray]; NSArray *expected = @[ @3, @7 ]; expect(results).to(equal(expected)); }); }); describe(@"-deliverOnMainThread", ^{ void (^dispatchSyncInBackground)(dispatch_block_t) = ^(dispatch_block_t block) { dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), block); dispatch_group_wait(group, DISPATCH_TIME_FOREVER); }; beforeEach(^{ expect(@(NSThread.isMainThread)).to(beTruthy()); }); it(@"should deliver events immediately when on the main thread", ^{ RACSubject *subject = [RACSubject subject]; NSMutableArray *values = [NSMutableArray array]; [[subject deliverOnMainThread] subscribeNext:^(id value) { [values addObject:value]; }]; [subject sendNext:@0]; expect(values).to(equal(@[ @0 ])); [subject sendNext:@1]; [subject sendNext:@2]; expect(values).to(equal(@[ @0, @1, @2 ])); }); it(@"should enqueue events sent from the background", ^{ RACSubject *subject = [RACSubject subject]; NSMutableArray *values = [NSMutableArray array]; [[subject deliverOnMainThread] subscribeNext:^(id value) { [values addObject:value]; }]; dispatchSyncInBackground(^{ [subject sendNext:@0]; }); expect(values).to(equal(@[])); expect(values).toEventually(equal(@[ @0 ])); dispatchSyncInBackground(^{ [subject sendNext:@1]; [subject sendNext:@2]; }); expect(values).to(equal(@[ @0 ])); expect(values).toEventually(equal(@[ @0, @1, @2 ])); }); it(@"should enqueue events sent from the main thread after events from the background", ^{ RACSubject *subject = [RACSubject subject]; NSMutableArray *values = [NSMutableArray array]; [[subject deliverOnMainThread] subscribeNext:^(id value) { [values addObject:value]; }]; dispatchSyncInBackground(^{ [subject sendNext:@0]; }); [subject sendNext:@1]; [subject sendNext:@2]; expect(values).to(equal(@[])); expect(values).toEventually(equal(@[ @0, @1, @2 ])); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACStreamExamples.h ================================================ // // RACStreamExamples.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-11-01. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // // The name of the shared examples for a RACStream subclass. extern NSString * const RACStreamExamples; // The RACStream subclass to test. extern NSString * const RACStreamExamplesClass; // An infinite RACStream to test, making sure that certain operations // terminate. // // The stream should contain infinite RACUnit values. extern NSString * const RACStreamExamplesInfiniteStream; // A block with the signature: // // void (^)(RACStream *stream, NSArray *expectedValues) // // … used to verify that a stream contains the expected values. extern NSString * const RACStreamExamplesVerifyValuesBlock; ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACStreamExamples.m ================================================ // // RACStreamExamples.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-11-01. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACStreamExamples.h" #import "RACStream.h" #import "RACUnit.h" #import "RACTuple.h" NSString * const RACStreamExamples = @"RACStreamExamples"; NSString * const RACStreamExamplesClass = @"RACStreamExamplesClass"; NSString * const RACStreamExamplesInfiniteStream = @"RACStreamExamplesInfiniteStream"; NSString * const RACStreamExamplesVerifyValuesBlock = @"RACStreamExamplesVerifyValuesBlock"; QuickConfigurationBegin(RACStreamExampleGroups) + (void)configure:(Configuration *)configuration { sharedExamples(RACStreamExamples, ^(QCKDSLSharedExampleContext exampleContext) { __block Class streamClass; __block void (^verifyValues)(RACStream *, NSArray *); __block RACStream *infiniteStream; __block RACStream *(^streamWithValues)(NSArray *); qck_beforeEach(^{ streamClass = exampleContext()[RACStreamExamplesClass]; verifyValues = exampleContext()[RACStreamExamplesVerifyValuesBlock]; infiniteStream = exampleContext()[RACStreamExamplesInfiniteStream]; streamWithValues = [^(NSArray *values) { RACStream *stream = [streamClass empty]; for (id value in values) { stream = [stream concat:[streamClass return:value]]; } return stream; } copy]; }); qck_it(@"should return an empty stream", ^{ RACStream *stream = [streamClass empty]; verifyValues(stream, @[]); }); qck_it(@"should lift a value into a stream", ^{ RACStream *stream = [streamClass return:RACUnit.defaultUnit]; verifyValues(stream, @[ RACUnit.defaultUnit ]); }); qck_describe(@"-concat:", ^{ qck_it(@"should concatenate two streams", ^{ RACStream *stream = [[streamClass return:@0] concat:[streamClass return:@1]]; verifyValues(stream, @[ @0, @1 ]); }); qck_it(@"should concatenate three streams", ^{ RACStream *stream = [[[streamClass return:@0] concat:[streamClass return:@1]] concat:[streamClass return:@2]]; verifyValues(stream, @[ @0, @1, @2 ]); }); qck_it(@"should concatenate around an empty stream", ^{ RACStream *stream = [[[streamClass return:@0] concat:[streamClass empty]] concat:[streamClass return:@2]]; verifyValues(stream, @[ @0, @2 ]); }); }); qck_it(@"should flatten", ^{ RACStream *stream = [[streamClass return:[streamClass return:RACUnit.defaultUnit]] flatten]; verifyValues(stream, @[ RACUnit.defaultUnit ]); }); qck_describe(@"-bind:", ^{ qck_it(@"should return the result of binding a single value", ^{ RACStream *stream = [[streamClass return:@0] bind:^{ return ^(NSNumber *value, BOOL *stop) { NSNumber *newValue = @(value.integerValue + 1); return [streamClass return:newValue]; }; }]; verifyValues(stream, @[ @1 ]); }); qck_it(@"should concatenate the result of binding multiple values", ^{ RACStream *baseStream = streamWithValues(@[ @0, @1 ]); RACStream *stream = [baseStream bind:^{ return ^(NSNumber *value, BOOL *stop) { NSNumber *newValue = @(value.integerValue + 1); return [streamClass return:newValue]; }; }]; verifyValues(stream, @[ @1, @2 ]); }); qck_it(@"should concatenate with an empty result from binding a value", ^{ RACStream *baseStream = streamWithValues(@[ @0, @1, @2 ]); RACStream *stream = [baseStream bind:^{ return ^(NSNumber *value, BOOL *stop) { if (value.integerValue == 1) return [streamClass empty]; NSNumber *newValue = @(value.integerValue + 1); return [streamClass return:newValue]; }; }]; verifyValues(stream, @[ @1, @3 ]); }); qck_it(@"should terminate immediately when returning nil", ^{ RACStream *stream = [infiniteStream bind:^{ return ^ id (id _, BOOL *stop) { return nil; }; }]; verifyValues(stream, @[]); }); qck_it(@"should terminate after one value when setting 'stop'", ^{ RACStream *stream = [infiniteStream bind:^{ return ^ id (id value, BOOL *stop) { *stop = YES; return [streamClass return:value]; }; }]; verifyValues(stream, @[ RACUnit.defaultUnit ]); }); qck_it(@"should terminate immediately when returning nil and setting 'stop'", ^{ RACStream *stream = [infiniteStream bind:^{ return ^ id (id _, BOOL *stop) { *stop = YES; return nil; }; }]; verifyValues(stream, @[]); }); qck_it(@"should be restartable even with block state", ^{ NSArray *values = @[ @0, @1, @2 ]; RACStream *baseStream = streamWithValues(values); RACStream *countingStream = [baseStream bind:^{ __block NSUInteger counter = 0; return ^(id x, BOOL *stop) { return [streamClass return:@(counter++)]; }; }]; verifyValues(countingStream, @[ @0, @1, @2 ]); verifyValues(countingStream, @[ @0, @1, @2 ]); }); qck_it(@"should be interleavable even with block state", ^{ NSArray *values = @[ @0, @1, @2 ]; RACStream *baseStream = streamWithValues(values); RACStream *countingStream = [baseStream bind:^{ __block NSUInteger counter = 0; return ^(id x, BOOL *stop) { return [streamClass return:@(counter++)]; }; }]; // Just so +zip:reduce: thinks this is a unique stream. RACStream *anotherStream = [[streamClass empty] concat:countingStream]; RACStream *zipped = [streamClass zip:@[ countingStream, anotherStream ] reduce:^(NSNumber *v1, NSNumber *v2) { return @(v1.integerValue + v2.integerValue); }]; verifyValues(zipped, @[ @0, @2, @4 ]); }); }); qck_describe(@"-flattenMap:", ^{ qck_it(@"should return a single mapped result", ^{ RACStream *stream = [[streamClass return:@0] flattenMap:^(NSNumber *value) { NSNumber *newValue = @(value.integerValue + 1); return [streamClass return:newValue]; }]; verifyValues(stream, @[ @1 ]); }); qck_it(@"should concatenate the results of mapping multiple values", ^{ RACStream *baseStream = streamWithValues(@[ @0, @1 ]); RACStream *stream = [baseStream flattenMap:^(NSNumber *value) { NSNumber *newValue = @(value.integerValue + 1); return [streamClass return:newValue]; }]; verifyValues(stream, @[ @1, @2 ]); }); qck_it(@"should concatenate with an empty result from mapping a value", ^{ RACStream *baseStream = streamWithValues(@[ @0, @1, @2 ]); RACStream *stream = [baseStream flattenMap:^(NSNumber *value) { if (value.integerValue == 1) return [streamClass empty]; NSNumber *newValue = @(value.integerValue + 1); return [streamClass return:newValue]; }]; verifyValues(stream, @[ @1, @3 ]); }); qck_it(@"should treat nil streams like empty streams", ^{ RACStream *baseStream = streamWithValues(@[ @0, @1, @2 ]); RACStream *stream = [baseStream flattenMap:^ RACStream * (NSNumber *value) { if (value.integerValue == 1) return nil; NSNumber *newValue = @(value.integerValue + 1); return [streamClass return:newValue]; }]; verifyValues(stream, @[ @1, @3 ]); }); }); qck_it(@"should map", ^{ RACStream *baseStream = streamWithValues(@[ @0, @1, @2 ]); RACStream *stream = [baseStream map:^(NSNumber *value) { return @(value.integerValue + 1); }]; verifyValues(stream, @[ @1, @2, @3 ]); }); qck_it(@"should map and replace", ^{ RACStream *baseStream = streamWithValues(@[ @0, @1, @2 ]); RACStream *stream = [baseStream mapReplace:RACUnit.defaultUnit]; verifyValues(stream, @[ RACUnit.defaultUnit, RACUnit.defaultUnit, RACUnit.defaultUnit ]); }); qck_it(@"should filter", ^{ RACStream *baseStream = streamWithValues(@[ @0, @1, @2, @3, @4, @5, @6 ]); RACStream *stream = [baseStream filter:^ BOOL (NSNumber *value) { return value.integerValue % 2 == 0; }]; verifyValues(stream, @[ @0, @2, @4, @6 ]); }); qck_describe(@"-ignore:", ^{ qck_it(@"should ignore a value", ^{ RACStream *baseStream = streamWithValues(@[ @0, @1, @2, @3, @4, @5, @6 ]); RACStream *stream = [baseStream ignore:@1]; verifyValues(stream, @[ @0, @2, @3, @4, @5, @6 ]); }); qck_it(@"should ignore based on object equality", ^{ RACStream *baseStream = streamWithValues(@[ @"0", @"1", @"2", @"3", @"4", @"5", @"6" ]); NSMutableString *valueToIgnore = [[NSMutableString alloc] init]; [valueToIgnore appendString:@"1"]; RACStream *stream = [baseStream ignore:valueToIgnore]; verifyValues(stream, @[ @"0", @"2", @"3", @"4", @"5", @"6" ]); }); }); qck_it(@"should start with a value", ^{ RACStream *stream = [[streamClass return:@1] startWith:@0]; verifyValues(stream, @[ @0, @1 ]); }); qck_describe(@"-skip:", ^{ __block NSArray *values; __block RACStream *stream; qck_beforeEach(^{ values = @[ @0, @1, @2 ]; stream = streamWithValues(values); }); qck_it(@"should skip any valid number of values", ^{ for (NSUInteger i = 0; i < values.count; i++) { verifyValues([stream skip:i], [values subarrayWithRange:NSMakeRange(i, values.count - i)]); } }); qck_it(@"should return an empty stream when skipping too many values", ^{ verifyValues([stream skip:4], @[]); }); }); qck_describe(@"-take:", ^{ qck_describe(@"with three values", ^{ __block NSArray *values; __block RACStream *stream; qck_beforeEach(^{ values = @[ @0, @1, @2 ]; stream = streamWithValues(values); }); qck_it(@"should take any valid number of values", ^{ for (NSUInteger i = 0; i < values.count; i++) { verifyValues([stream take:i], [values subarrayWithRange:NSMakeRange(0, i)]); } }); qck_it(@"should return the same stream when taking too many values", ^{ verifyValues([stream take:4], values); }); }); qck_it(@"should take and terminate from an infinite stream", ^{ verifyValues([infiniteStream take:0], @[]); verifyValues([infiniteStream take:1], @[ RACUnit.defaultUnit ]); verifyValues([infiniteStream take:2], @[ RACUnit.defaultUnit, RACUnit.defaultUnit ]); }); qck_it(@"should take and terminate from a single-item stream", ^{ NSArray *values = @[ RACUnit.defaultUnit ]; RACStream *stream = streamWithValues(values); verifyValues([stream take:1], values); }); }); qck_describe(@"zip stream creation methods", ^{ __block NSArray *valuesOne; __block RACStream *streamOne; __block RACStream *streamTwo; __block RACStream *streamThree; __block NSArray *threeStreams; __block NSArray *oneStreamTuples; __block NSArray *twoStreamTuples; __block NSArray *threeStreamTuples; qck_beforeEach(^{ valuesOne = @[ @"Ada", @"Bob", @"Dea" ]; NSArray *valuesTwo = @[ @"eats", @"cooks", @"jumps" ]; NSArray *valuesThree = @[ @"fish", @"bear", @"rock" ]; streamOne = streamWithValues(valuesOne); streamTwo = streamWithValues(valuesTwo); streamThree = streamWithValues(valuesThree); threeStreams = @[ streamOne, streamTwo, streamThree ]; oneStreamTuples = @[ RACTuplePack(valuesOne[0]), RACTuplePack(valuesOne[1]), RACTuplePack(valuesOne[2]), ]; twoStreamTuples = @[ RACTuplePack(valuesOne[0], valuesTwo[0]), RACTuplePack(valuesOne[1], valuesTwo[1]), RACTuplePack(valuesOne[2], valuesTwo[2]), ]; threeStreamTuples = @[ RACTuplePack(valuesOne[0], valuesTwo[0], valuesThree[0]), RACTuplePack(valuesOne[1], valuesTwo[1], valuesThree[1]), RACTuplePack(valuesOne[2], valuesTwo[2], valuesThree[2]), ]; }); qck_describe(@"-zipWith:", ^{ qck_it(@"should make a stream of tuples", ^{ RACStream *stream = [streamOne zipWith:streamTwo]; verifyValues(stream, twoStreamTuples); }); qck_it(@"should truncate streams", ^{ RACStream *shortStream = streamWithValues(@[ @"now", @"later" ]); RACStream *stream = [streamOne zipWith:shortStream]; verifyValues(stream, @[ RACTuplePack(valuesOne[0], @"now"), RACTuplePack(valuesOne[1], @"later") ]); }); qck_it(@"should work on infinite streams", ^{ RACStream *stream = [streamOne zipWith:infiniteStream]; verifyValues(stream, @[ RACTuplePack(valuesOne[0], RACUnit.defaultUnit), RACTuplePack(valuesOne[1], RACUnit.defaultUnit), RACTuplePack(valuesOne[2], RACUnit.defaultUnit) ]); }); qck_it(@"should handle multiples of the same stream", ^{ RACStream *stream = [streamOne zipWith:streamOne]; verifyValues(stream, @[ RACTuplePack(valuesOne[0], valuesOne[0]), RACTuplePack(valuesOne[1], valuesOne[1]), RACTuplePack(valuesOne[2], valuesOne[2]), ]); }); }); qck_describe(@"+zip:reduce:", ^{ qck_it(@"should reduce values", ^{ RACStream *stream = [streamClass zip:threeStreams reduce:^ NSString * (id x, id y, id z) { return [NSString stringWithFormat:@"%@ %@ %@", x, y, z]; }]; verifyValues(stream, @[ @"Ada eats fish", @"Bob cooks bear", @"Dea jumps rock" ]); }); qck_it(@"should truncate streams", ^{ RACStream *shortStream = streamWithValues(@[ @"now", @"later" ]); NSArray *streams = [threeStreams arrayByAddingObject:shortStream]; RACStream *stream = [streamClass zip:streams reduce:^ NSString * (id w, id x, id y, id z) { return [NSString stringWithFormat:@"%@ %@ %@ %@", w, x, y, z]; }]; verifyValues(stream, @[ @"Ada eats fish now", @"Bob cooks bear later" ]); }); qck_it(@"should work on infinite streams", ^{ NSArray *streams = [threeStreams arrayByAddingObject:infiniteStream]; RACStream *stream = [streamClass zip:streams reduce:^ NSString * (id w, id x, id y, id z) { return [NSString stringWithFormat:@"%@ %@ %@", w, x, y]; }]; verifyValues(stream, @[ @"Ada eats fish", @"Bob cooks bear", @"Dea jumps rock" ]); }); qck_it(@"should handle multiples of the same stream", ^{ NSArray *streams = @[ streamOne, streamOne, streamTwo, streamThree, streamTwo, streamThree ]; RACStream *stream = [streamClass zip:streams reduce:^ NSString * (id x1, id x2, id y1, id z1, id y2, id z2) { return [NSString stringWithFormat:@"%@ %@ %@ %@ %@ %@", x1, x2, y1, z1, y2, z2]; }]; verifyValues(stream, @[ @"Ada Ada eats fish eats fish", @"Bob Bob cooks bear cooks bear", @"Dea Dea jumps rock jumps rock" ]); }); }); qck_describe(@"+zip:", ^{ qck_it(@"should make a stream of tuples out of single value", ^{ RACStream *stream = [streamClass zip:@[ streamOne ]]; verifyValues(stream, oneStreamTuples); }); qck_it(@"should make a stream of tuples out of an array of streams", ^{ RACStream *stream = [streamClass zip:threeStreams]; verifyValues(stream, threeStreamTuples); }); qck_it(@"should make an empty stream if given an empty array", ^{ RACStream *stream = [streamClass zip:@[]]; verifyValues(stream, @[]); }); qck_it(@"should make a stream of tuples out of an enumerator of streams", ^{ RACStream *stream = [streamClass zip:threeStreams.objectEnumerator]; verifyValues(stream, threeStreamTuples); }); qck_it(@"should make an empty stream if given an empty enumerator", ^{ RACStream *stream = [streamClass zip:@[].objectEnumerator]; verifyValues(stream, @[]); }); }); }); qck_describe(@"+concat:", ^{ __block NSArray *streams = nil; __block NSArray *result = nil; qck_beforeEach(^{ RACStream *a = [streamClass return:@0]; RACStream *b = [streamClass empty]; RACStream *c = streamWithValues(@[ @1, @2, @3 ]); RACStream *d = [streamClass return:@4]; RACStream *e = [streamClass return:@5]; RACStream *f = [streamClass empty]; RACStream *g = [streamClass empty]; RACStream *h = streamWithValues(@[ @6, @7 ]); streams = @[ a, b, c, d, e, f, g, h ]; result = @[ @0, @1, @2, @3, @4, @5, @6, @7 ]; }); qck_it(@"should concatenate an array of streams", ^{ RACStream *stream = [streamClass concat:streams]; verifyValues(stream, result); }); qck_it(@"should concatenate an enumerator of streams", ^{ RACStream *stream = [streamClass concat:streams.objectEnumerator]; verifyValues(stream, result); }); }); qck_describe(@"scanning", ^{ NSArray *values = @[ @1, @2, @3, @4 ]; __block RACStream *stream; qck_beforeEach(^{ stream = streamWithValues(values); }); qck_it(@"should scan", ^{ RACStream *scanned = [stream scanWithStart:@0 reduce:^(NSNumber *running, NSNumber *next) { return @(running.integerValue + next.integerValue); }]; verifyValues(scanned, @[ @1, @3, @6, @10 ]); }); qck_it(@"should scan with index", ^{ RACStream *scanned = [stream scanWithStart:@0 reduceWithIndex:^(NSNumber *running, NSNumber *next, NSUInteger index) { return @(running.integerValue + next.integerValue + (NSInteger)index); }]; verifyValues(scanned, @[ @1, @4, @9, @16 ]); }); }); qck_describe(@"taking with a predicate", ^{ NSArray *values = @[ @0, @1, @2, @3, @0, @2, @4 ]; __block RACStream *stream; qck_beforeEach(^{ stream = streamWithValues(values); }); qck_it(@"should take until a predicate is true", ^{ RACStream *taken = [stream takeUntilBlock:^ BOOL (NSNumber *x) { return x.integerValue >= 3; }]; verifyValues(taken, @[ @0, @1, @2 ]); }); qck_it(@"should take while a predicate is true", ^{ RACStream *taken = [stream takeWhileBlock:^ BOOL (NSNumber *x) { return x.integerValue <= 1; }]; verifyValues(taken, @[ @0, @1 ]); }); qck_it(@"should take a full stream", ^{ RACStream *taken = [stream takeWhileBlock:^ BOOL (NSNumber *x) { return x.integerValue <= 10; }]; verifyValues(taken, values); }); qck_it(@"should return an empty stream", ^{ RACStream *taken = [stream takeWhileBlock:^ BOOL (NSNumber *x) { return x.integerValue < 0; }]; verifyValues(taken, @[]); }); qck_it(@"should terminate an infinite stream", ^{ RACStream *infiniteCounter = [infiniteStream scanWithStart:@0 reduce:^(NSNumber *running, id _) { return @(running.unsignedIntegerValue + 1); }]; RACStream *taken = [infiniteCounter takeWhileBlock:^ BOOL (NSNumber *x) { return x.integerValue <= 5; }]; verifyValues(taken, @[ @1, @2, @3, @4, @5 ]); }); }); qck_describe(@"skipping with a predicate", ^{ NSArray *values = @[ @0, @1, @2, @3, @0, @2, @4 ]; __block RACStream *stream; qck_beforeEach(^{ stream = streamWithValues(values); }); qck_it(@"should skip until a predicate is true", ^{ RACStream *taken = [stream skipUntilBlock:^ BOOL (NSNumber *x) { return x.integerValue >= 3; }]; verifyValues(taken, @[ @3, @0, @2, @4 ]); }); qck_it(@"should skip while a predicate is true", ^{ RACStream *taken = [stream skipWhileBlock:^ BOOL (NSNumber *x) { return x.integerValue <= 1; }]; verifyValues(taken, @[ @2, @3, @0, @2, @4 ]); }); qck_it(@"should skip a full stream", ^{ RACStream *taken = [stream skipWhileBlock:^ BOOL (NSNumber *x) { return x.integerValue <= 10; }]; verifyValues(taken, @[]); }); qck_it(@"should finish skipping immediately", ^{ RACStream *taken = [stream skipWhileBlock:^ BOOL (NSNumber *x) { return x.integerValue < 0; }]; verifyValues(taken, values); }); }); qck_describe(@"-combinePreviousWithStart:reduce:", ^{ NSArray *values = @[ @1, @2, @3 ]; __block RACStream *stream; qck_beforeEach(^{ stream = streamWithValues(values); }); qck_it(@"should pass the previous next into the reduce block", ^{ NSMutableArray *previouses = [NSMutableArray array]; RACStream *mapped = [stream combinePreviousWithStart:nil reduce:^(id previous, id next) { [previouses addObject:previous ?: RACTupleNil.tupleNil]; return next; }]; verifyValues(mapped, @[ @1, @2, @3 ]); NSArray *expected = @[ RACTupleNil.tupleNil, @1, @2 ]; expect(previouses).to(equal(expected)); }); qck_it(@"should send the combined value", ^{ RACStream *mapped = [stream combinePreviousWithStart:@1 reduce:^(NSNumber *previous, NSNumber *next) { return [NSString stringWithFormat:@"%lu - %lu", (unsigned long)previous.unsignedIntegerValue, (unsigned long)next.unsignedIntegerValue]; }]; verifyValues(mapped, @[ @"1 - 1", @"1 - 2", @"2 - 3" ]); }); }); qck_it(@"should reduce tuples", ^{ RACStream *stream = streamWithValues(@[ RACTuplePack(@"foo", @"bar"), RACTuplePack(@"buzz", @"baz"), RACTuplePack(@"", @"_") ]); RACStream *reduced = [stream reduceEach:^(NSString *a, NSString *b) { return [a stringByAppendingString:b]; }]; verifyValues(reduced, @[ @"foobar", @"buzzbaz", @"_" ]); }); }); } QuickConfigurationEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACSubclassObject.h ================================================ // // RACSubclassObject.h // ReactiveCocoa // // Created by Josh Abernathy on 3/18/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "RACTestObject.h" @interface RACSubclassObject : RACTestObject // Set whenever -forwardInvocation: is invoked on the receiver. @property (nonatomic, assign) SEL forwardedSelector; // Invokes the superclass implementation with `objectValue` concatenated to // "SUBCLASS". - (NSString *)combineObjectValue:(id)objectValue andIntegerValue:(NSInteger)integerValue; // Asynchronously invokes the superclass implementation on the current scheduler. - (void)setObjectValue:(id)objectValue andSecondObjectValue:(id)secondObjectValue; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACSubclassObject.m ================================================ // // RACSubclassObject.m // ReactiveCocoa // // Created by Josh Abernathy on 3/18/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACSubclassObject.h" #import "RACScheduler.h" @implementation RACSubclassObject - (void)forwardInvocation:(NSInvocation *)invocation { self.forwardedSelector = invocation.selector; } - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { NSParameterAssert(selector != NULL); NSMethodSignature *signature = [super methodSignatureForSelector:selector]; if (signature != nil) return signature; return [super methodSignatureForSelector:@selector(description)]; } - (NSString *)combineObjectValue:(id)objectValue andIntegerValue:(NSInteger)integerValue { NSString *appended = [[objectValue description] stringByAppendingString:@"SUBCLASS"]; return [super combineObjectValue:appended andIntegerValue:integerValue]; } - (void)setObjectValue:(id)objectValue andSecondObjectValue:(id)secondObjectValue { [RACScheduler.currentScheduler schedule:^{ [super setObjectValue:objectValue andSecondObjectValue:secondObjectValue]; }]; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACSubjectSpec.m ================================================ // // RACSubjectSpec.m // ReactiveCocoa // // Created by Josh Abernathy on 6/24/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACSubscriberExamples.h" #import #import #import "RACBehaviorSubject.h" #import "RACDisposable.h" #import "RACReplaySubject.h" #import "RACScheduler.h" #import "RACSignal+Operations.h" #import "RACSubject.h" #import "RACUnit.h" QuickSpecBegin(RACSubjectSpec) qck_describe(@"RACSubject", ^{ __block RACSubject *subject; __block NSMutableArray *values; __block BOOL success; __block NSError *error; qck_beforeEach(^{ values = [NSMutableArray array]; subject = [RACSubject subject]; success = YES; error = nil; [subject subscribeNext:^(id value) { [values addObject:value]; } error:^(NSError *e) { error = e; success = NO; } completed:^{ success = YES; }]; }); qck_itBehavesLike(RACSubscriberExamples, ^{ return @{ RACSubscriberExampleSubscriber: subject, RACSubscriberExampleValuesReceivedBlock: [^{ return [values copy]; } copy], RACSubscriberExampleErrorReceivedBlock: [^{ return error; } copy], RACSubscriberExampleSuccessBlock: [^{ return success; } copy] }; }); }); qck_describe(@"RACReplaySubject", ^{ __block RACReplaySubject *subject = nil; qck_describe(@"with a capacity of 1", ^{ qck_beforeEach(^{ subject = [RACReplaySubject replaySubjectWithCapacity:1]; }); qck_it(@"should send the last value", ^{ id firstValue = @"blah"; id secondValue = @"more blah"; [subject sendNext:firstValue]; [subject sendNext:secondValue]; __block id valueReceived = nil; [subject subscribeNext:^(id x) { valueReceived = x; }]; expect(valueReceived).to(equal(secondValue)); }); qck_it(@"should send the last value to new subscribers after completion", ^{ id firstValue = @"blah"; id secondValue = @"more blah"; __block id valueReceived = nil; __block NSUInteger nextsReceived = 0; [subject sendNext:firstValue]; [subject sendNext:secondValue]; expect(@(nextsReceived)).to(equal(@0)); expect(valueReceived).to(beNil()); [subject sendCompleted]; [subject subscribeNext:^(id x) { valueReceived = x; nextsReceived++; }]; expect(@(nextsReceived)).to(equal(@1)); expect(valueReceived).to(equal(secondValue)); }); qck_it(@"should not send any values to new subscribers if none were sent originally", ^{ [subject sendCompleted]; __block BOOL nextInvoked = NO; [subject subscribeNext:^(id x) { nextInvoked = YES; }]; expect(@(nextInvoked)).to(beFalsy()); }); qck_it(@"should resend errors", ^{ NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:0 userInfo:nil]; [subject sendError:error]; __block BOOL errorSent = NO; [subject subscribeError:^(NSError *sentError) { expect(sentError).to(equal(error)); errorSent = YES; }]; expect(@(errorSent)).to(beTruthy()); }); qck_it(@"should resend nil errors", ^{ [subject sendError:nil]; __block BOOL errorSent = NO; [subject subscribeError:^(NSError *sentError) { expect(sentError).to(beNil()); errorSent = YES; }]; expect(@(errorSent)).to(beTruthy()); }); }); qck_describe(@"with an unlimited capacity", ^{ qck_beforeEach(^{ subject = [RACReplaySubject subject]; }); qck_itBehavesLike(RACSubscriberExamples, ^{ return @{ RACSubscriberExampleSubscriber: subject, RACSubscriberExampleValuesReceivedBlock: [^{ NSMutableArray *values = [NSMutableArray array]; // This subscription should synchronously dump all values already // received into 'values'. [subject subscribeNext:^(id value) { [values addObject:value]; }]; return values; } copy], RACSubscriberExampleErrorReceivedBlock: [^{ __block NSError *error = nil; [subject subscribeError:^(NSError *x) { error = x; }]; return error; } copy], RACSubscriberExampleSuccessBlock: [^{ __block BOOL success = YES; [subject subscribeError:^(NSError *x) { success = NO; }]; return success; } copy] }; }); qck_it(@"should send both values to new subscribers after completion", ^{ id firstValue = @"blah"; id secondValue = @"more blah"; [subject sendNext:firstValue]; [subject sendNext:secondValue]; [subject sendCompleted]; __block BOOL completed = NO; NSMutableArray *valuesReceived = [NSMutableArray array]; [subject subscribeNext:^(id x) { [valuesReceived addObject:x]; } completed:^{ completed = YES; }]; expect(valuesReceived).to(haveCount(@2)); NSArray *expected = [NSArray arrayWithObjects:firstValue, secondValue, nil]; expect(valuesReceived).to(equal(expected)); expect(@(completed)).to(beTruthy()); }); qck_it(@"should send values in the same order live as when replaying", ^{ NSUInteger count = 49317; // Just leak it, ain't no thang. __unsafe_unretained volatile id *values = (__unsafe_unretained id *)calloc(count, sizeof(*values)); __block volatile int32_t nextIndex = 0; [subject subscribeNext:^(NSNumber *value) { int32_t indexPlusOne = OSAtomicIncrement32(&nextIndex); values[indexPlusOne - 1] = value; }]; dispatch_queue_t queue = dispatch_queue_create("org.reactivecocoa.ReactiveCocoa.RACSubjectSpec", DISPATCH_QUEUE_CONCURRENT); dispatch_suspend(queue); for (NSUInteger i = 0; i < count; i++) { dispatch_async(queue, ^{ [subject sendNext:@(i)]; }); } dispatch_resume(queue); dispatch_barrier_sync(queue, ^{ [subject sendCompleted]; }); OSMemoryBarrier(); NSArray *liveValues = [NSArray arrayWithObjects:(id *)values count:(NSUInteger)nextIndex]; expect(liveValues).to(haveCount(@(count))); NSArray *replayedValues = subject.toArray; expect(replayedValues).to(haveCount(@(count))); // It should return the same ordering for multiple invocations too. expect(replayedValues).to(equal(subject.toArray)); [replayedValues enumerateObjectsUsingBlock:^(id value, NSUInteger index, BOOL *stop) { expect(liveValues[index]).to(equal(value)); }]; }); qck_it(@"should have a current scheduler when replaying", ^{ [subject sendNext:RACUnit.defaultUnit]; __block RACScheduler *currentScheduler; [subject subscribeNext:^(id x) { currentScheduler = RACScheduler.currentScheduler; }]; expect(currentScheduler).notTo(beNil()); currentScheduler = nil; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [subject subscribeNext:^(id x) { currentScheduler = RACScheduler.currentScheduler; }]; }); expect(currentScheduler).toEventuallyNot(beNil()); }); qck_it(@"should stop replaying when the subscription is disposed", ^{ NSMutableArray *values = [NSMutableArray array]; [subject sendNext:@0]; [subject sendNext:@1]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ __block RACDisposable *disposable = [subject subscribeNext:^(id x) { expect(disposable).notTo(beNil()); [values addObject:x]; [disposable dispose]; }]; }); expect(values).toEventually(equal(@[ @0 ])); }); qck_it(@"should finish replaying before completing", ^{ [subject sendNext:@1]; __block id received; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [subject subscribeNext:^(id x) { received = x; }]; [subject sendCompleted]; }); expect(received).toEventually(equal(@1)); }); qck_it(@"should finish replaying before erroring", ^{ [subject sendNext:@1]; __block id received; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [subject subscribeNext:^(id x) { received = x; }]; [subject sendError:[NSError errorWithDomain:@"blah" code:-99 userInfo:nil]]; }); expect(received).toEventually(equal(@1)); }); qck_it(@"should finish replaying before sending new values", ^{ [subject sendNext:@1]; NSMutableArray *received = [NSMutableArray array]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [subject subscribeNext:^(id x) { [received addObject:x]; }]; [subject sendNext:@2]; }); NSArray *expected = @[ @1, @2 ]; expect(received).toEventually(equal(expected)); }); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACSubscriberExamples.h ================================================ // // RACSubscriberExamples.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-11-27. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // // The name of the shared examples for implementors of . extern NSString * const RACSubscriberExamples; // id extern NSString * const RACSubscriberExampleSubscriber; // A block which returns an NSArray of the values received so far. extern NSString * const RACSubscriberExampleValuesReceivedBlock; // A block which returns any NSError received so far. extern NSString * const RACSubscriberExampleErrorReceivedBlock; // A block which returns a BOOL indicating whether the subscriber is successful // so far. extern NSString * const RACSubscriberExampleSuccessBlock; ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACSubscriberExamples.m ================================================ // // RACSubscriberExamples.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-11-27. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACSubscriberExamples.h" #import "NSObject+RACDeallocating.h" #import "RACCompoundDisposable.h" #import "RACDisposable.h" #import "RACSubject.h" #import "RACSubscriber.h" NSString * const RACSubscriberExamples = @"RACSubscriberExamples"; NSString * const RACSubscriberExampleSubscriber = @"RACSubscriberExampleSubscriber"; NSString * const RACSubscriberExampleValuesReceivedBlock = @"RACSubscriberExampleValuesReceivedBlock"; NSString * const RACSubscriberExampleErrorReceivedBlock = @"RACSubscriberExampleErrorReceivedBlock"; NSString * const RACSubscriberExampleSuccessBlock = @"RACSubscriberExampleSuccessBlock"; QuickConfigurationBegin(RACSubscriberExampleGroups) + (void)configure:(Configuration *)configuration { sharedExamples(RACSubscriberExamples, ^(QCKDSLSharedExampleContext exampleContext) { __block NSArray * (^valuesReceived)(void); __block NSError * (^errorReceived)(void); __block BOOL (^success)(void); __block id subscriber; qck_beforeEach(^{ valuesReceived = exampleContext()[RACSubscriberExampleValuesReceivedBlock]; errorReceived = exampleContext()[RACSubscriberExampleErrorReceivedBlock]; success = exampleContext()[RACSubscriberExampleSuccessBlock]; subscriber = exampleContext()[RACSubscriberExampleSubscriber]; expect(subscriber).notTo(beNil()); }); qck_it(@"should accept a nil error", ^{ [subscriber sendError:nil]; expect(@(success())).to(beFalsy()); expect(errorReceived()).to(beNil()); expect(valuesReceived()).to(equal(@[])); }); qck_describe(@"with values", ^{ __block NSSet *values; qck_beforeEach(^{ NSMutableSet *mutableValues = [NSMutableSet set]; for (NSUInteger i = 0; i < 20; i++) { [mutableValues addObject:@(i)]; } values = [mutableValues copy]; }); qck_it(@"should send nexts serially, even when delivered from multiple threads", ^{ NSArray *allValues = values.allObjects; dispatch_apply(allValues.count, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), [^(size_t index) { [subscriber sendNext:allValues[index]]; } copy]); expect(@(success())).to(beTruthy()); expect(errorReceived()).to(beNil()); NSSet *valuesReceivedSet = [NSSet setWithArray:valuesReceived()]; expect(valuesReceivedSet).to(equal(values)); }); }); qck_describe(@"multiple subscriptions", ^{ __block RACSubject *first; __block RACSubject *second; qck_beforeEach(^{ first = [RACSubject subject]; [first subscribe:subscriber]; second = [RACSubject subject]; [second subscribe:subscriber]; }); qck_it(@"should send values from all subscriptions", ^{ [first sendNext:@"foo"]; [second sendNext:@"bar"]; [first sendNext:@"buzz"]; [second sendNext:@"baz"]; expect(@(success())).to(beTruthy()); expect(errorReceived()).to(beNil()); NSArray *expected = @[ @"foo", @"bar", @"buzz", @"baz" ]; expect(valuesReceived()).to(equal(expected)); }); qck_it(@"should terminate after the first error from any subscription", ^{ NSError *error = [NSError errorWithDomain:@"" code:-1 userInfo:nil]; [first sendNext:@"foo"]; [second sendError:error]; [first sendNext:@"buzz"]; expect(@(success())).to(beFalsy()); expect(errorReceived()).to(equal(error)); NSArray *expected = @[ @"foo" ]; expect(valuesReceived()).to(equal(expected)); }); qck_it(@"should terminate after the first completed from any subscription", ^{ [first sendNext:@"foo"]; [second sendNext:@"bar"]; [first sendCompleted]; [second sendNext:@"baz"]; expect(@(success())).to(beTruthy()); expect(errorReceived()).to(beNil()); NSArray *expected = @[ @"foo", @"bar" ]; expect(valuesReceived()).to(equal(expected)); }); qck_it(@"should dispose of all current subscriptions upon termination", ^{ __block BOOL firstDisposed = NO; RACSignal *firstDisposableSignal = [RACSignal createSignal:^(id subscriber) { return [RACDisposable disposableWithBlock:^{ firstDisposed = YES; }]; }]; __block BOOL secondDisposed = NO; RACSignal *secondDisposableSignal = [RACSignal createSignal:^(id subscriber) { return [RACDisposable disposableWithBlock:^{ secondDisposed = YES; }]; }]; [firstDisposableSignal subscribe:subscriber]; [secondDisposableSignal subscribe:subscriber]; expect(@(firstDisposed)).to(beFalsy()); expect(@(secondDisposed)).to(beFalsy()); [first sendCompleted]; expect(@(firstDisposed)).to(beTruthy()); expect(@(secondDisposed)).to(beTruthy()); }); qck_it(@"should dispose of future subscriptions upon termination", ^{ __block BOOL disposed = NO; RACSignal *disposableSignal = [RACSignal createSignal:^(id subscriber) { return [RACDisposable disposableWithBlock:^{ disposed = YES; }]; }]; [first sendCompleted]; expect(@(disposed)).to(beFalsy()); [disposableSignal subscribe:subscriber]; expect(@(disposed)).to(beTruthy()); }); }); qck_describe(@"memory management", ^{ qck_it(@"should not retain disposed disposables", ^{ __block BOOL disposableDeallocd = NO; @autoreleasepool { RACCompoundDisposable *disposable __attribute__((objc_precise_lifetime)) = [RACCompoundDisposable disposableWithBlock:^{}]; [disposable.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{ disposableDeallocd = YES; }]]; [subscriber didSubscribeWithDisposable:disposable]; [disposable dispose]; } expect(@(disposableDeallocd)).to(beTruthy()); }); }); }); } QuickConfigurationEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACSubscriberSpec.m ================================================ // // RACSubscriberSpec.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-11-27. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACSubscriberExamples.h" #import "RACSubscriber.h" #import "RACSubscriber+Private.h" #import QuickSpecBegin(RACSubscriberSpec) __block RACSubscriber *subscriber; __block NSMutableArray *values; __block volatile BOOL finished; __block volatile int32_t nextsAfterFinished; __block BOOL success; __block NSError *error; qck_beforeEach(^{ values = [NSMutableArray array]; finished = NO; nextsAfterFinished = 0; success = YES; error = nil; subscriber = [RACSubscriber subscriberWithNext:^(id value) { if (finished) OSAtomicIncrement32Barrier(&nextsAfterFinished); [values addObject:value]; } error:^(NSError *e) { error = e; success = NO; } completed:^{ success = YES; }]; }); qck_itBehavesLike(RACSubscriberExamples, ^{ return @{ RACSubscriberExampleSubscriber: subscriber, RACSubscriberExampleValuesReceivedBlock: [^{ return [values copy]; } copy], RACSubscriberExampleErrorReceivedBlock: [^{ return error; } copy], RACSubscriberExampleSuccessBlock: [^{ return success; } copy] }; }); qck_describe(@"finishing", ^{ __block void (^sendValues)(void); __block BOOL expectedSuccess; __block dispatch_group_t dispatchGroup; __block dispatch_queue_t concurrentQueue; qck_beforeEach(^{ dispatchGroup = dispatch_group_create(); expect(dispatchGroup).notTo(beNil()); concurrentQueue = dispatch_queue_create("org.reactivecocoa.ReactiveCocoa.RACSubscriberSpec", DISPATCH_QUEUE_CONCURRENT); expect(concurrentQueue).notTo(beNil()); dispatch_suspend(concurrentQueue); sendValues = [^{ for (NSUInteger i = 0; i < 15; i++) { dispatch_group_async(dispatchGroup, concurrentQueue, ^{ [subscriber sendNext:@(i)]; }); } } copy]; sendValues(); }); qck_afterEach(^{ sendValues(); dispatch_resume(concurrentQueue); // Time out after one second. dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)); expect(@(dispatch_group_wait(dispatchGroup, time))).to(equal(@0)); dispatchGroup = NULL; concurrentQueue = NULL; expect(@(nextsAfterFinished)).to(equal(@0)); if (expectedSuccess) { expect(@(success)).to(beTruthy()); expect(error).to(beNil()); } else { expect(@(success)).to(beFalsy()); } }); qck_it(@"should never invoke next after sending completed", ^{ expectedSuccess = YES; dispatch_group_async(dispatchGroup, concurrentQueue, ^{ [subscriber sendCompleted]; finished = YES; OSMemoryBarrier(); }); }); qck_it(@"should never invoke next after sending error", ^{ expectedSuccess = NO; dispatch_group_async(dispatchGroup, concurrentQueue, ^{ [subscriber sendError:nil]; finished = YES; OSMemoryBarrier(); }); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACSubscriptingAssignmentTrampolineSpec.m ================================================ // // RACSubscriptingAssignmentTrampolineSpec.m // ReactiveCocoa // // Created by Josh Abernathy on 9/24/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACSubscriptingAssignmentTrampoline.h" #import "RACPropertySignalExamples.h" #import "RACTestObject.h" #import "RACSubject.h" QuickSpecBegin(RACSubscriptingAssignmentTrampolineSpec) id setupBlock = ^(RACTestObject *testObject, NSString *keyPath, id nilValue, RACSignal *signal) { [[RACSubscriptingAssignmentTrampoline alloc] initWithTarget:testObject nilValue:nilValue][keyPath] = signal; }; qck_itBehavesLike(RACPropertySignalExamples, ^{ return @{ RACPropertySignalExamplesSetupBlock: setupBlock }; }); qck_it(@"should expand the RAC macro properly", ^{ RACSubject *subject = [RACSubject subject]; RACTestObject *testObject = [[RACTestObject alloc] init]; RAC(testObject, objectValue) = subject; [subject sendNext:@1]; expect(testObject.objectValue).to(equal(@1)); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACTargetQueueSchedulerSpec.m ================================================ // // RACTargetQueueSchedulerSpec.m // ReactiveCocoa // // Created by Josh Abernathy on 6/7/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "RACTargetQueueScheduler.h" #import QuickSpecBegin(RACTargetQueueSchedulerSpec) qck_it(@"should have a valid current scheduler", ^{ dispatch_queue_t queue = dispatch_queue_create("test-queue", DISPATCH_QUEUE_SERIAL); RACScheduler *scheduler = [[RACTargetQueueScheduler alloc] initWithName:@"test-scheduler" targetQueue:queue]; __block RACScheduler *currentScheduler; [scheduler schedule:^{ currentScheduler = RACScheduler.currentScheduler; }]; expect(currentScheduler).toEventually(equal(scheduler)); }); qck_it(@"should schedule blocks FIFO even when given a concurrent queue", ^{ dispatch_queue_t queue = dispatch_queue_create("test-queue", DISPATCH_QUEUE_CONCURRENT); RACScheduler *scheduler = [[RACTargetQueueScheduler alloc] initWithName:@"test-scheduler" targetQueue:queue]; __block volatile int32_t startedCount = 0; __block volatile uint32_t waitInFirst = 1; [scheduler schedule:^{ OSAtomicIncrement32Barrier(&startedCount); while (waitInFirst == 1) ; }]; [scheduler schedule:^{ OSAtomicIncrement32Barrier(&startedCount); }]; expect(@(startedCount)).toEventually(equal(@1)); OSAtomicAnd32Barrier(0, &waitInFirst); expect(@(startedCount)).toEventually(equal(@2)); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACTestExampleScheduler.h ================================================ // // RACTestExampleScheduler.h // ReactiveCocoa // // Created by Josh Abernathy on 6/7/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import @interface RACTestExampleScheduler : RACQueueScheduler - (id)initWithQueue:(dispatch_queue_t)queue; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACTestExampleScheduler.m ================================================ // // RACTestExampleScheduler.m // ReactiveCocoa // // Created by Josh Abernathy on 6/7/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACTestExampleScheduler.h" #import "RACQueueScheduler+Subclass.h" @implementation RACTestExampleScheduler #pragma mark Lifecycle - (id)initWithQueue:(dispatch_queue_t)queue { return [super initWithName:nil queue:queue]; } #pragma mark RACScheduler - (RACDisposable *)schedule:(void (^)(void))block { dispatch_async(self.queue, ^{ [self performAsCurrentScheduler:block]; }); return nil; } - (RACDisposable *)after:(NSDate *)date schedule:(void (^)(void))block { dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)([date timeIntervalSinceNow] * NSEC_PER_SEC)); dispatch_after(when, self.queue, ^{ [self performAsCurrentScheduler:block]; }); return nil; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACTestObject.h ================================================ // // RACTestObject.h // ReactiveCocoa // // Created by Josh Abernathy on 9/18/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import typedef struct { long long integerField; double doubleField; } RACTestStruct; @protocol RACTestProtocol @optional - (void)optionalProtocolMethodWithObjectValue:(id)objectValue; @end @interface RACTestObject : NSObject @property (nonatomic, strong) id objectValue; @property (nonatomic, strong) id secondObjectValue; @property (nonatomic, strong) RACTestObject *strongTestObjectValue; @property (nonatomic, weak) RACTestObject *weakTestObjectValue; @property (nonatomic, weak) id weakObjectWithProtocol; @property (nonatomic, assign) NSInteger integerValue; // Holds a copy of the string. @property (nonatomic, assign) char *charPointerValue; // Holds a copy of the string. @property (nonatomic, assign) const char *constCharPointerValue; @property (nonatomic, assign) CGRect rectValue; @property (nonatomic, assign) CGSize sizeValue; @property (nonatomic, assign) CGPoint pointValue; @property (nonatomic, assign) NSRange rangeValue; @property (nonatomic, assign) RACTestStruct structValue; @property (nonatomic, assign) _Bool c99BoolValue; @property (nonatomic, copy) NSString *stringValue; @property (nonatomic, copy) NSArray *arrayValue; @property (nonatomic, copy) NSSet *setValue; @property (nonatomic, copy) NSOrderedSet *orderedSetValue; @property (nonatomic, strong) id slowObjectValue; // Returns a new object each time, with the integerValue set to 42. @property (nonatomic, copy, readonly) RACTestObject *dynamicObjectProperty; // Returns a new object each time, with the integerValue set to 42. - (RACTestObject *)dynamicObjectMethod; // Whether to allow -setNilValueForKey: to be invoked without throwing an // exception. @property (nonatomic, assign) BOOL catchSetNilValueForKey; // Has -setObjectValue:andIntegerValue: been called? @property (nonatomic, assign) BOOL hasInvokedSetObjectValueAndIntegerValue; // Has -setObjectValue:andSecondObjectValue: been called? @property (nonatomic, assign) BOOL hasInvokedSetObjectValueAndSecondObjectValue; - (void)setObjectValue:(id)objectValue andIntegerValue:(NSInteger)integerValue; - (void)setObjectValue:(id)objectValue andSecondObjectValue:(id)secondObjectValue; // Returns a string of the form "objectValue: integerValue". - (NSString *)combineObjectValue:(id)objectValue andIntegerValue:(NSInteger)integerValue; - (NSString *)combineObjectValue:(id)objectValue andSecondObjectValue:(id)secondObjectValue; - (void)lifeIsGood:(id)sender; + (void)lifeIsGood:(id)sender; - (NSRange)returnRangeValueWithObjectValue:(id)objectValue andIntegerValue:(NSInteger)integerValue; // Writes 5 to the int pointed to by intPointer. - (void)write5ToIntPointer:(int *)intPointer; - (NSInteger)doubleInteger:(NSInteger)integer; - (char *)doubleString:(char *)string; - (const char *)doubleConstString:(const char *)string; - (RACTestStruct)doubleStruct:(RACTestStruct)testStruct; - (dispatch_block_t)wrapBlock:(dispatch_block_t)block; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACTestObject.m ================================================ // // RACTestObject.m // ReactiveCocoa // // Created by Josh Abernathy on 9/18/12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import "RACTestObject.h" @implementation RACTestObject - (void)dealloc { free(_charPointerValue); free((void *)_constCharPointerValue); } - (void)setNilValueForKey:(NSString *)key { if (!self.catchSetNilValueForKey) [super setNilValueForKey:key]; } - (void)setCharPointerValue:(char *)charPointerValue { if (charPointerValue == _charPointerValue) return; free(_charPointerValue); _charPointerValue = strdup(charPointerValue); } - (void)setConstCharPointerValue:(const char *)constCharPointerValue { if (constCharPointerValue == _constCharPointerValue) return; free((void *)_constCharPointerValue); _constCharPointerValue = strdup(constCharPointerValue); } - (void)setObjectValue:(id)objectValue andIntegerValue:(NSInteger)integerValue { self.hasInvokedSetObjectValueAndIntegerValue = YES; self.objectValue = objectValue; self.integerValue = integerValue; } - (void)setObjectValue:(id)objectValue andSecondObjectValue:(id)secondObjectValue { self.hasInvokedSetObjectValueAndSecondObjectValue = YES; self.objectValue = objectValue; self.secondObjectValue = secondObjectValue; } - (void)setSlowObjectValue:(id)value { [NSThread sleepForTimeInterval:0.02]; _slowObjectValue = value; } - (NSString *)combineObjectValue:(id)objectValue andIntegerValue:(NSInteger)integerValue { return [NSString stringWithFormat:@"%@: %ld", objectValue, (long)integerValue]; } - (NSString *)combineObjectValue:(id)objectValue andSecondObjectValue:(id)secondObjectValue { return [NSString stringWithFormat:@"%@: %@", objectValue, secondObjectValue]; } - (void)lifeIsGood:(id)sender { } + (void)lifeIsGood:(id)sender { } - (NSRange)returnRangeValueWithObjectValue:(id)objectValue andIntegerValue:(NSInteger)integerValue { return NSMakeRange((NSUInteger)[objectValue integerValue], (NSUInteger)integerValue); } - (RACTestObject *)dynamicObjectProperty { return [self dynamicObjectMethod]; } - (RACTestObject *)dynamicObjectMethod { RACTestObject *testObject = [[RACTestObject alloc] init]; testObject.integerValue = 42; return testObject; } - (void)write5ToIntPointer:(int *)intPointer { NSCParameterAssert(intPointer != NULL); *intPointer = 5; } - (NSInteger)doubleInteger:(NSInteger)integer { return integer * 2; } - (char *)doubleString:(char *)string { size_t doubledSize = strlen(string) * 2 + 1; char *doubledString = malloc(sizeof(char) * doubledSize); doubledString[0] = '\0'; strlcat(doubledString, string, doubledSize); strlcat(doubledString, string, doubledSize); dispatch_async(dispatch_get_main_queue(), ^{ free(doubledString); }); return doubledString; } - (const char *)doubleConstString:(const char *)string { return [self doubleString:(char *)string]; } - (RACTestStruct)doubleStruct:(RACTestStruct)testStruct { testStruct.integerField *= 2; testStruct.doubleField *= 2; return testStruct; } - (dispatch_block_t)wrapBlock:(dispatch_block_t)block { return ^{ block(); }; } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACTestSchedulerSpec.m ================================================ // // RACTestSchedulerSpec.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-07-06. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "RACTestScheduler.h" QuickSpecBegin(RACTestSchedulerSpec) __block RACTestScheduler *scheduler; qck_beforeEach(^{ scheduler = [[RACTestScheduler alloc] init]; expect(scheduler).notTo(beNil()); }); qck_it(@"should do nothing when stepping while empty", ^{ [scheduler step]; [scheduler step:5]; [scheduler stepAll]; }); qck_it(@"should execute the earliest enqueued block when stepping", ^{ __block BOOL firstExecuted = NO; [scheduler schedule:^{ firstExecuted = YES; }]; __block BOOL secondExecuted = NO; [scheduler schedule:^{ secondExecuted = YES; }]; expect(@(firstExecuted)).to(beFalsy()); expect(@(secondExecuted)).to(beFalsy()); [scheduler step]; expect(@(firstExecuted)).to(beTruthy()); expect(@(secondExecuted)).to(beFalsy()); [scheduler step]; expect(@(secondExecuted)).to(beTruthy()); }); qck_it(@"should step multiple times", ^{ __block BOOL firstExecuted = NO; [scheduler schedule:^{ firstExecuted = YES; }]; __block BOOL secondExecuted = NO; [scheduler schedule:^{ secondExecuted = YES; }]; __block BOOL thirdExecuted = NO; [scheduler schedule:^{ thirdExecuted = YES; }]; expect(@(firstExecuted)).to(beFalsy()); expect(@(secondExecuted)).to(beFalsy()); expect(@(thirdExecuted)).to(beFalsy()); [scheduler step:2]; expect(@(firstExecuted)).to(beTruthy()); expect(@(secondExecuted)).to(beTruthy()); expect(@(thirdExecuted)).to(beFalsy()); [scheduler step:1]; expect(@(thirdExecuted)).to(beTruthy()); }); qck_it(@"should step through all scheduled blocks", ^{ __block NSUInteger executions = 0; for (NSUInteger i = 0; i < 10; i++) { [scheduler schedule:^{ executions++; }]; } expect(@(executions)).to(equal(@0)); [scheduler stepAll]; expect(@(executions)).to(equal(@10)); }); qck_it(@"should execute blocks in date order when stepping", ^{ __block BOOL laterExecuted = NO; [scheduler after:[NSDate distantFuture] schedule:^{ laterExecuted = YES; }]; __block BOOL earlierExecuted = NO; [scheduler after:[NSDate dateWithTimeIntervalSinceNow:20] schedule:^{ earlierExecuted = YES; }]; expect(@(earlierExecuted)).to(beFalsy()); expect(@(laterExecuted)).to(beFalsy()); [scheduler step]; expect(@(earlierExecuted)).to(beTruthy()); expect(@(laterExecuted)).to(beFalsy()); [scheduler step]; expect(@(laterExecuted)).to(beTruthy()); }); qck_it(@"should execute delayed blocks in date order when stepping", ^{ __block BOOL laterExecuted = NO; [scheduler afterDelay:100 schedule:^{ laterExecuted = YES; }]; __block BOOL earlierExecuted = NO; [scheduler afterDelay:50 schedule:^{ earlierExecuted = YES; }]; expect(@(earlierExecuted)).to(beFalsy()); expect(@(laterExecuted)).to(beFalsy()); [scheduler step]; expect(@(earlierExecuted)).to(beTruthy()); expect(@(laterExecuted)).to(beFalsy()); [scheduler step]; expect(@(laterExecuted)).to(beTruthy()); }); qck_it(@"should execute a repeating blocks in date order", ^{ __block NSUInteger firstExecutions = 0; [scheduler after:[NSDate dateWithTimeIntervalSinceNow:20] repeatingEvery:5 withLeeway:0 schedule:^{ firstExecutions++; }]; __block NSUInteger secondExecutions = 0; [scheduler after:[NSDate dateWithTimeIntervalSinceNow:22] repeatingEvery:10 withLeeway:0 schedule:^{ secondExecutions++; }]; expect(@(firstExecutions)).to(equal(@0)); expect(@(secondExecutions)).to(equal(@0)); // 20 ticks [scheduler step]; expect(@(firstExecutions)).to(equal(@1)); expect(@(secondExecutions)).to(equal(@0)); // 22 ticks [scheduler step]; expect(@(firstExecutions)).to(equal(@1)); expect(@(secondExecutions)).to(equal(@1)); // 25 ticks [scheduler step]; expect(@(firstExecutions)).to(equal(@2)); expect(@(secondExecutions)).to(equal(@1)); // 30 ticks [scheduler step]; expect(@(firstExecutions)).to(equal(@3)); expect(@(secondExecutions)).to(equal(@1)); // 32 ticks [scheduler step]; expect(@(firstExecutions)).to(equal(@3)); expect(@(secondExecutions)).to(equal(@2)); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACTestUIButton.h ================================================ // // RACTestUIButton.h // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-06-15. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import // Enables use of -sendActionsForControlEvents: in unit tests. @interface RACTestUIButton : UIButton + (instancetype)button; @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACTestUIButton.m ================================================ // // RACTestUIButton.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2013-06-15. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import "RACTestUIButton.h" @implementation RACTestUIButton + (instancetype)button { RACTestUIButton *button = [self buttonWithType:UIButtonTypeCustom]; return button; } // Required for unit testing – controls don't work normally // outside of normal apps. -(void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [target performSelector:action withObject:self]; #pragma clang diagnostic pop } @end ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/RACTupleSpec.m ================================================ // // RACTupleSpec.m // ReactiveCocoa // // Created by Justin Spahr-Summers on 2012-12-12. // Copyright (c) 2012 GitHub, Inc. All rights reserved. // #import #import #import "RACTuple.h" #import "RACUnit.h" QuickSpecBegin(RACTupleSpec) qck_describe(@"RACTupleUnpack", ^{ qck_it(@"should unpack a single value", ^{ RACTupleUnpack(RACUnit *value) = [RACTuple tupleWithObjects:RACUnit.defaultUnit, nil]; expect(value).to(equal(RACUnit.defaultUnit)); }); qck_it(@"should translate RACTupleNil", ^{ RACTupleUnpack(id value) = [RACTuple tupleWithObjects:RACTupleNil.tupleNil, nil]; expect(value).to(beNil()); }); qck_it(@"should unpack multiple values", ^{ RACTupleUnpack(NSString *str, NSNumber *num) = [RACTuple tupleWithObjects:@"foobar", @5, nil]; expect(str).to(equal(@"foobar")); expect(num).to(equal(@5)); }); qck_it(@"should fill in missing values with nil", ^{ RACTupleUnpack(NSString *str, NSNumber *num) = [RACTuple tupleWithObjects:@"foobar", nil]; expect(str).to(equal(@"foobar")); expect(num).to(beNil()); }); qck_it(@"should skip any values not assigned to", ^{ RACTupleUnpack(NSString *str, NSNumber *num) = [RACTuple tupleWithObjects:@"foobar", @5, RACUnit.defaultUnit, nil]; expect(str).to(equal(@"foobar")); expect(num).to(equal(@5)); }); qck_it(@"should keep an unpacked value alive when captured in a block", ^{ __weak id weakPtr = nil; id (^block)(void) = nil; @autoreleasepool { RACTupleUnpack(NSString *str) = [RACTuple tupleWithObjects:[[NSMutableString alloc] init], nil]; weakPtr = str; expect(weakPtr).notTo(beNil()); block = [^{ return str; } copy]; } expect(weakPtr).notTo(beNil()); expect(block()).to(equal(weakPtr)); }); }); qck_describe(@"RACTuplePack", ^{ qck_it(@"should pack a single value", ^{ RACTuple *tuple = [RACTuple tupleWithObjects:RACUnit.defaultUnit, nil]; expect(RACTuplePack(RACUnit.defaultUnit)).to(equal(tuple)); }); qck_it(@"should translate nil", ^{ RACTuple *tuple = [RACTuple tupleWithObjects:RACTupleNil.tupleNil, nil]; expect(RACTuplePack(nil)).to(equal(tuple)); }); qck_it(@"should pack multiple values", ^{ NSString *string = @"foobar"; NSNumber *number = @5; RACTuple *tuple = [RACTuple tupleWithObjects:string, number, nil]; expect(RACTuplePack(string, number)).to(equal(tuple)); }); }); qck_describe(@"-tupleByAddingObject:", ^{ __block RACTuple *tuple; qck_beforeEach(^{ tuple = RACTuplePack(@"foo", nil, @"bar"); }); qck_it(@"should add a non-nil object", ^{ RACTuple *newTuple = [tuple tupleByAddingObject:@"buzz"]; expect(@(newTuple.count)).to(equal(@4)); expect(newTuple[0]).to(equal(@"foo")); expect(newTuple[1]).to(beNil()); expect(newTuple[2]).to(equal(@"bar")); expect(newTuple[3]).to(equal(@"buzz")); }); qck_it(@"should add nil", ^{ RACTuple *newTuple = [tuple tupleByAddingObject:nil]; expect(@(newTuple.count)).to(equal(@4)); expect(newTuple[0]).to(equal(@"foo")); expect(newTuple[1]).to(beNil()); expect(newTuple[2]).to(equal(@"bar")); expect(newTuple[3]).to(beNil()); }); qck_it(@"should add NSNull", ^{ RACTuple *newTuple = [tuple tupleByAddingObject:NSNull.null]; expect(@(newTuple.count)).to(equal(@4)); expect(newTuple[0]).to(equal(@"foo")); expect(newTuple[1]).to(beNil()); expect(newTuple[2]).to(equal(@"bar")); expect(newTuple[3]).to(equal(NSNull.null)); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/UIActionSheetRACSupportSpec.m ================================================ // // UIActionSheetRACSupportSpec.m // ReactiveCocoa // // Created by Dave Lee on 2013-06-22. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "RACSignal.h" #import "RACSignal+Operations.h" #import "UIActionSheet+RACSignalSupport.h" QuickSpecBegin(UIActionSheetRACSupportSpec) qck_describe(@"-rac_buttonClickedSignal", ^{ __block UIActionSheet *actionSheet; qck_beforeEach(^{ actionSheet = [[UIActionSheet alloc] init]; [actionSheet addButtonWithTitle:@"Button 0"]; [actionSheet addButtonWithTitle:@"Button 1"]; expect(actionSheet).notTo(beNil()); }); qck_it(@"should send the index of the clicked button", ^{ __block NSNumber *index = nil; [actionSheet.rac_buttonClickedSignal subscribeNext:^(NSNumber *i) { index = i; }]; [actionSheet.delegate actionSheet:actionSheet clickedButtonAtIndex:1]; expect(index).to(equal(@1)); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/UIAlertViewRACSupportSpec.m ================================================ // // UIAlertViewRACSupportSpec.m // ReactiveCocoa // // Created by Henrik Hodne on 6/16/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import #import "RACSignal.h" #import "UIAlertView+RACSignalSupport.h" QuickSpecBegin(UIAlertViewRACSupportSpec) qck_describe(@"UIAlertView", ^{ __block UIAlertView *alertView; qck_beforeEach(^{ alertView = [[UIAlertView alloc] initWithFrame:CGRectZero]; expect(alertView).notTo(beNil()); }); qck_it(@"sends the index of the clicked button to the buttonClickedSignal when a button is clicked", ^{ __block NSInteger index = -1; [alertView.rac_buttonClickedSignal subscribeNext:^(NSNumber *sentIndex) { index = sentIndex.integerValue; }]; [alertView.delegate alertView:alertView clickedButtonAtIndex:2]; expect(@(index)).to(equal(@2)); }); qck_it(@"sends the index of the appropriate button to the willDismissSignal when dismissed programatically", ^{ __block NSInteger index = -1; [alertView.rac_willDismissSignal subscribeNext:^(NSNumber *sentIndex) { index = sentIndex.integerValue; }]; [alertView.delegate alertView:alertView willDismissWithButtonIndex:2]; expect(@(index)).to(equal(@2)); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/UIBarButtonItemRACSupportSpec.m ================================================ // // UIBarButtonItemRACSupportSpec.m // ReactiveCocoa // // Created by Kyle LeNeau on 4/13/13. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "RACControlCommandExamples.h" #import "UIBarButtonItem+RACCommandSupport.h" #import "RACCommand.h" #import "RACDisposable.h" QuickSpecBegin(UIBarButtonItemRACSupportSpec) qck_describe(@"UIBarButtonItem", ^{ __block UIBarButtonItem *button; qck_beforeEach(^{ button = [[UIBarButtonItem alloc] init]; expect(button).notTo(beNil()); }); qck_itBehavesLike(RACControlCommandExamples, ^{ return @{ RACControlCommandExampleControl: button, RACControlCommandExampleActivateBlock: ^(UIBarButtonItem *button) { NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[button.target methodSignatureForSelector:button.action]]; invocation.selector = button.action; id target = button.target; [invocation setArgument:&target atIndex:2]; [invocation invokeWithTarget:target]; } }; }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/UIButtonRACSupportSpec.m ================================================ // // UIButtonRACSupportSpec.m // ReactiveCocoa // // Created by Ash Furrow on 2013-06-06. // Copyright (c) 2013 GitHub, Inc. All rights reserved. // #import #import #import "RACControlCommandExamples.h" #import "RACTestUIButton.h" #import "UIButton+RACCommandSupport.h" #import "RACCommand.h" #import "RACDisposable.h" QuickSpecBegin(UIButtonRACSupportSpec) qck_describe(@"UIButton", ^{ __block UIButton *button; qck_beforeEach(^{ button = [RACTestUIButton button]; expect(button).notTo(beNil()); }); qck_itBehavesLike(RACControlCommandExamples, ^{ return @{ RACControlCommandExampleControl: button, RACControlCommandExampleActivateBlock: ^(UIButton *button) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [button sendActionsForControlEvents:UIControlEventTouchUpInside]; #pragma clang diagnostic pop } }; }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Objective-C/UIImagePickerControllerRACSupportSpec.m ================================================ // // UIImagePickerControllerRACSupportSpec.m // ReactiveCocoa // // Created by Timur Kuchkarov on 17.04.14. // Copyright (c) 2014 GitHub, Inc. All rights reserved. // #import #import #import "UIImagePickerController+RACSignalSupport.h" #import "RACSignal.h" QuickSpecBegin(UIImagePickerControllerRACSupportSpec) qck_describe(@"UIImagePickerController", ^{ __block UIImagePickerController *imagePicker; qck_beforeEach(^{ imagePicker = [[UIImagePickerController alloc] init]; expect(imagePicker).notTo(beNil()); }); qck_it(@"sends the user info dictionary after confirmation", ^{ __block NSDictionary *selectedImageUserInfo = nil; [imagePicker.rac_imageSelectedSignal subscribeNext:^(NSDictionary *userInfo) { selectedImageUserInfo = userInfo; }]; NSDictionary *info = @{ UIImagePickerControllerMediaType: @"public.image", UIImagePickerControllerMediaMetadata: @{} }; [imagePicker.delegate imagePickerController:imagePicker didFinishPickingMediaWithInfo:info]; expect(selectedImageUserInfo).to(equal(info)); }); qck_it(@"cancels image picking process", ^{ __block BOOL didSend = NO; __block BOOL didComplete = NO; [imagePicker.rac_imageSelectedSignal subscribeNext:^(NSDictionary *userInfo) { didSend = YES; } completed:^{ didComplete = YES; }]; [imagePicker.delegate imagePickerControllerDidCancel:imagePicker]; expect(@(didSend)).to(beFalsy()); expect(@(didComplete)).to(beTruthy()); }); }); QuickSpecEnd ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Swift/ActionSpec.swift ================================================ // // ActionSpec.swift // ReactiveCocoa // // Created by Justin Spahr-Summers on 2014-12-11. // Copyright (c) 2014 GitHub. All rights reserved. // import Result import Nimble import Quick import ReactiveCocoa class ActionSpec: QuickSpec { override func spec() { describe("Action") { var action: Action! var enabled: MutableProperty! var executionCount = 0 var values: [String] = [] var errors: [NSError] = [] var scheduler: TestScheduler! let testError = NSError(domain: "ActionSpec", code: 1, userInfo: nil) beforeEach { executionCount = 0 values = [] errors = [] enabled = MutableProperty(false) scheduler = TestScheduler() action = Action(enabledIf: enabled) { number in return SignalProducer { observer, disposable in executionCount++ if number % 2 == 0 { observer.sendNext("\(number)") observer.sendNext("\(number)\(number)") scheduler.schedule { observer.sendCompleted() } } else { scheduler.schedule { observer.sendFailed(testError) } } } } action.values.observeNext { values.append($0) } action.errors.observeNext { errors.append($0) } } it("should be disabled and not executing after initialization") { expect(action.enabled.value) == false expect(action.executing.value) == false } it("should error if executed while disabled") { var receivedError: ActionError? action.apply(0).startWithFailed { receivedError = $0 } expect(receivedError).notTo(beNil()) if let error = receivedError { let expectedError = ActionError.NotEnabled expect(error == expectedError) == true } } it("should enable and disable based on the given property") { enabled.value = true expect(action.enabled.value) == true expect(action.executing.value) == false enabled.value = false expect(action.enabled.value) == false expect(action.executing.value) == false } describe("execution") { beforeEach { enabled.value = true } it("should execute successfully") { var receivedValue: String? action.apply(0).startWithNext { receivedValue = $0 } expect(executionCount) == 1 expect(action.executing.value) == true expect(action.enabled.value) == false expect(receivedValue) == "00" expect(values) == [ "0", "00" ] expect(errors) == [] scheduler.run() expect(action.executing.value) == false expect(action.enabled.value) == true expect(values) == [ "0", "00" ] expect(errors) == [] } it("should execute with an error") { var receivedError: ActionError? action.apply(1).startWithFailed { receivedError = $0 } expect(executionCount) == 1 expect(action.executing.value) == true expect(action.enabled.value) == false scheduler.run() expect(action.executing.value) == false expect(action.enabled.value) == true expect(receivedError).notTo(beNil()) if let error = receivedError { let expectedError = ActionError.ProducerError(testError) expect(error == expectedError) == true } expect(values) == [] expect(errors) == [ testError ] } } } describe("CocoaAction") { var action: Action! beforeEach { action = Action { value in SignalProducer(value: value + 1) } expect(action.enabled.value) == true expect(action.unsafeCocoaAction.enabled).toEventually(beTruthy()) } #if os(OSX) it("should be compatible with AppKit") { let control = NSControl(frame: NSZeroRect) control.target = action.unsafeCocoaAction control.action = CocoaAction.selector control.performClick(nil) } #elseif os(iOS) it("should be compatible with UIKit") { let control = UIControl(frame: CGRectZero) control.addTarget(action.unsafeCocoaAction, action: CocoaAction.selector, forControlEvents: UIControlEvents.TouchDown) control.sendActionsForControlEvents(UIControlEvents.TouchDown) } #endif it("should generate KVO notifications for enabled") { var values: [Bool] = [] action.unsafeCocoaAction .rac_valuesForKeyPath("enabled", observer: nil) .toSignalProducer() .map { $0! as! Bool } .start(Observer(next: { values.append($0) })) expect(values) == [ true ] let result = action.apply(0).first() expect(result?.value) == 1 expect(values).toEventually(equal([ true, false, true ])) } it("should generate KVO notifications for executing") { var values: [Bool] = [] action.unsafeCocoaAction .rac_valuesForKeyPath("executing", observer: nil) .toSignalProducer() .map { $0! as! Bool } .start(Observer(next: { values.append($0) })) expect(values) == [ false ] let result = action.apply(0).first() expect(result?.value) == 1 expect(values).toEventually(equal([ false, true, false ])) } } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Swift/AtomicSpec.swift ================================================ // // AtomicSpec.swift // ReactiveCocoa // // Created by Justin Spahr-Summers on 2014-07-13. // Copyright (c) 2014 GitHub. All rights reserved. // import Nimble import Quick import ReactiveCocoa class AtomicSpec: QuickSpec { override func spec() { var atomic: Atomic! beforeEach { atomic = Atomic(1) } it("should read and write the value directly") { expect(atomic.value) == 1 atomic.value = 2 expect(atomic.value) == 2 } it("should swap the value atomically") { expect(atomic.swap(2)) == 1 expect(atomic.value) == 2 } it("should modify the value atomically") { expect(atomic.modify({ $0 + 1 })) == 1 expect(atomic.value) == 2 } it("should perform an action with the value") { let result: Bool = atomic.withValue { $0 == 1 } expect(result) == true expect(atomic.value) == 1 } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Swift/BagSpec.swift ================================================ // // BagSpec.swift // ReactiveCocoa // // Created by Justin Spahr-Summers on 2014-07-13. // Copyright (c) 2014 GitHub. All rights reserved. // import Nimble import Quick import ReactiveCocoa class BagSpec: QuickSpec { override func spec() { var bag = Bag() beforeEach { bag = Bag() } it("should insert values") { bag.insert("foo") bag.insert("bar") bag.insert("buzz") expect(bag).to(contain("foo")) expect(bag).to(contain("bar")) expect(bag).to(contain("buzz")) expect(bag).toNot(contain("fuzz")) expect(bag).toNot(contain("foobar")) } it("should remove values given the token from insertion") { let a = bag.insert("foo") let b = bag.insert("bar") let c = bag.insert("buzz") bag.removeValueForToken(b) expect(bag).to(contain("foo")) expect(bag).toNot(contain("bar")) expect(bag).to(contain("buzz")) bag.removeValueForToken(a) expect(bag).toNot(contain("foo")) expect(bag).toNot(contain("bar")) expect(bag).to(contain("buzz")) bag.removeValueForToken(c) expect(bag).toNot(contain("foo")) expect(bag).toNot(contain("bar")) expect(bag).toNot(contain("buzz")) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Swift/DisposableSpec.swift ================================================ // // DisposableSpec.swift // ReactiveCocoa // // Created by Justin Spahr-Summers on 2014-07-13. // Copyright (c) 2014 GitHub. All rights reserved. // import Nimble import Quick import ReactiveCocoa class DisposableSpec: QuickSpec { override func spec() { describe("SimpleDisposable") { it("should set disposed to true") { let disposable = SimpleDisposable() expect(disposable.disposed) == false disposable.dispose() expect(disposable.disposed) == true } } describe("ActionDisposable") { it("should run the given action upon disposal") { var didDispose = false let disposable = ActionDisposable { didDispose = true } expect(didDispose) == false expect(disposable.disposed) == false disposable.dispose() expect(didDispose) == true expect(disposable.disposed) == true } } describe("CompositeDisposable") { var disposable = CompositeDisposable() beforeEach { disposable = CompositeDisposable() } it("should ignore the addition of nil") { disposable.addDisposable(nil) return } it("should dispose of added disposables") { let simpleDisposable = SimpleDisposable() disposable.addDisposable(simpleDisposable) var didDispose = false disposable.addDisposable { didDispose = true } expect(simpleDisposable.disposed) == false expect(didDispose) == false expect(disposable.disposed) == false disposable.dispose() expect(simpleDisposable.disposed) == true expect(didDispose) == true expect(disposable.disposed) == true } it("should not dispose of removed disposables") { let simpleDisposable = SimpleDisposable() let handle = disposable += simpleDisposable // We should be allowed to call this any number of times. handle.remove() handle.remove() expect(simpleDisposable.disposed) == false disposable.dispose() expect(simpleDisposable.disposed) == false } } describe("ScopedDisposable") { it("should dispose of the inner disposable upon deinitialization") { let simpleDisposable = SimpleDisposable() func runScoped() { let scopedDisposable = ScopedDisposable(simpleDisposable) expect(simpleDisposable.disposed) == false expect(scopedDisposable.disposed) == false } expect(simpleDisposable.disposed) == false runScoped() expect(simpleDisposable.disposed) == true } } describe("SerialDisposable") { var disposable: SerialDisposable! beforeEach { disposable = SerialDisposable() } it("should dispose of the inner disposable") { let simpleDisposable = SimpleDisposable() disposable.innerDisposable = simpleDisposable expect(disposable.innerDisposable).notTo(beNil()) expect(simpleDisposable.disposed) == false expect(disposable.disposed) == false disposable.dispose() expect(disposable.innerDisposable).to(beNil()) expect(simpleDisposable.disposed) == true expect(disposable.disposed) == true } it("should dispose of the previous disposable when swapping innerDisposable") { let oldDisposable = SimpleDisposable() let newDisposable = SimpleDisposable() disposable.innerDisposable = oldDisposable expect(oldDisposable.disposed) == false expect(newDisposable.disposed) == false disposable.innerDisposable = newDisposable expect(oldDisposable.disposed) == true expect(newDisposable.disposed) == false expect(disposable.disposed) == false disposable.innerDisposable = nil expect(newDisposable.disposed) == true expect(disposable.disposed) == false } } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Swift/FlattenSpec.swift ================================================ // // FlattenSpec.swift // ReactiveCocoa // // Created by Oleg Shnitko on 1/22/16. // Copyright © 2016 GitHub. All rights reserved. // import Result import Nimble import Quick import ReactiveCocoa private extension SignalType { typealias Pipe = (signal: Signal, observer: Observer) } private typealias Pipe = Signal, TestError>.Pipe class FlattenSpec: QuickSpec { override func spec() { func describeSignalFlattenDisposal(flattenStrategy: FlattenStrategy, name: String) { describe(name) { var pipe: Pipe! var disposable: Disposable? beforeEach { pipe = Signal.pipe() disposable = pipe.signal .flatten(flattenStrategy) .observe { _ in } } afterEach { disposable?.dispose() } context("disposal") { var disposed = false beforeEach { disposed = false pipe.observer.sendNext(SignalProducer { _, disposable in disposable += ActionDisposable { disposed = true } }) } it("should dispose inner signals when outer signal interrupted") { pipe.observer.sendInterrupted() expect(disposed) == true } it("should dispose inner signals when outer signal failed") { pipe.observer.sendFailed(.Default) expect(disposed) == true } it("should not dispose inner signals when outer signal completed") { pipe.observer.sendCompleted() expect(disposed) == false } } } } context("Signal") { describeSignalFlattenDisposal(.Latest, name: "switchToLatest") describeSignalFlattenDisposal(.Merge, name: "merge") describeSignalFlattenDisposal(.Concat, name: "concat") } func describeSignalProducerFlattenDisposal(flattenStrategy: FlattenStrategy, name: String) { describe(name) { it("disposes original signal when result signal interrupted") { var disposed = false let disposable = SignalProducer, NoError> { _, disposable in disposable += ActionDisposable { disposed = true } } .flatten(flattenStrategy) .start() disposable.dispose() expect(disposed) == true } } } context("SignalProducer") { describeSignalProducerFlattenDisposal(.Latest, name: "switchToLatest") describeSignalProducerFlattenDisposal(.Merge, name: "merge") describeSignalProducerFlattenDisposal(.Concat, name: "concat") } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Swift/FoundationExtensionsSpec.swift ================================================ // // FoundationExtensionsSpec.swift // ReactiveCocoa // // Created by Neil Pankey on 5/22/15. // Copyright (c) 2015 GitHub. All rights reserved. // import Result import Nimble import Quick import ReactiveCocoa class FoundationExtensionsSpec: QuickSpec { override func spec() { describe("NSNotificationCenter.rac_notifications") { it("should send notifications on the producer") { let center = NSNotificationCenter.defaultCenter() let producer = center.rac_notifications("rac_notifications_test") var notif: NSNotification? = nil let disposable = producer.startWithNext { notif = $0 } center.postNotificationName("some_other_notification", object: nil) expect(notif).to(beNil()) center.postNotificationName("rac_notifications_test", object: nil) expect(notif?.name) == "rac_notifications_test" notif = nil disposable.dispose() center.postNotificationName("rac_notifications_test", object: nil) expect(notif).to(beNil()) } } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Swift/ObjectiveCBridgingSpec.swift ================================================ // // ObjectiveCBridgingSpec.swift // ReactiveCocoa // // Created by Justin Spahr-Summers on 2015-01-23. // Copyright (c) 2015 GitHub. All rights reserved. // import Result import Nimble import Quick import ReactiveCocoa import XCTest class ObjectiveCBridgingSpec: QuickSpec { override func spec() { describe("RACScheduler") { var originalScheduler: RACTestScheduler! var scheduler: DateSchedulerType! beforeEach { originalScheduler = RACTestScheduler() scheduler = originalScheduler as DateSchedulerType } it("gives current date") { expect(scheduler.currentDate).to(beCloseTo(NSDate())) } it("schedules actions") { var actionRan: Bool = false scheduler.schedule { actionRan = true } expect(actionRan) == false originalScheduler.step() expect(actionRan) == true } it("does not invoke action if disposed") { var actionRan: Bool = false let disposable: Disposable? = scheduler.schedule { actionRan = true } expect(actionRan) == false disposable!.dispose() originalScheduler.step() expect(actionRan) == false } } describe("RACSignal.toSignalProducer") { it("should subscribe once per start()") { var subscriptions = 0 let racSignal = RACSignal.createSignal { subscriber in subscriber.sendNext(subscriptions++) subscriber.sendCompleted() return nil } let producer = racSignal.toSignalProducer().map { $0 as! Int } expect((producer.single())?.value) == 0 expect((producer.single())?.value) == 1 expect((producer.single())?.value) == 2 } it("should forward errors") { let error = TestError.Default as NSError let racSignal = RACSignal.error(error) let producer = racSignal.toSignalProducer() let result = producer.last() expect(result?.error) == error } } describe("toRACSignal") { let key = "TestKey" let userInfo: [String: String] = [key: "TestValue"] let testNSError = NSError(domain: "TestDomain", code: 1, userInfo: userInfo) describe("on a Signal") { it("should forward events") { let (signal, observer) = Signal.pipe() let racSignal = signal.toRACSignal() var lastValue: NSNumber? var didComplete = false racSignal.subscribeNext({ number in lastValue = number as? NSNumber }, completed: { didComplete = true }) expect(lastValue).to(beNil()) for number in [1, 2, 3] { observer.sendNext(number) expect(lastValue) == number } expect(didComplete) == false observer.sendCompleted() expect(didComplete) == true } it("should convert errors to NSError") { let (signal, observer) = Signal.pipe() let racSignal = signal.toRACSignal() let expectedError = TestError.Error2 var error: NSError? racSignal.subscribeError { error = $0 return } observer.sendFailed(expectedError) expect(error) == expectedError as NSError } it("should maintain userInfo on NSError") { let (signal, observer) = Signal.pipe() let racSignal = signal.toRACSignal() var error: NSError? racSignal.subscribeError { error = $0 return } observer.sendFailed(testNSError) let userInfoValue = error?.userInfo[key] as? String expect(userInfoValue) == userInfo[key] } } describe("on a SignalProducer") { it("should start once per subscription") { var subscriptions = 0 let producer = SignalProducer.attempt { return .Success(subscriptions++) } let racSignal = producer.toRACSignal() expect(racSignal.first() as? NSNumber) == 0 expect(racSignal.first() as? NSNumber) == 1 expect(racSignal.first() as? NSNumber) == 2 } it("should convert errors to NSError") { let producer = SignalProducer(error: .Error1) let racSignal = producer.toRACSignal().materialize() let event = racSignal.first() as? RACEvent expect(event?.error) == TestError.Error1 as NSError } it("should maintain userInfo on NSError") { let producer = SignalProducer(error: testNSError) let racSignal = producer.toRACSignal().materialize() let event = racSignal.first() as? RACEvent let userInfoValue = event?.error.userInfo[key] as? String expect(userInfoValue) == userInfo[key] } } } describe("RACCommand.toAction") { var command: RACCommand! var results: [Int] = [] var enabledSubject: RACSubject! var enabled = false var action: Action! beforeEach { enabledSubject = RACSubject() results = [] command = RACCommand(enabled: enabledSubject) { (input: AnyObject?) -> RACSignal! in let inputNumber = input as! Int return RACSignal.`return`(inputNumber + 1) } expect(command).notTo(beNil()) command.enabled.subscribeNext { enabled = $0 as! Bool } expect(enabled) == true command.executionSignals.flatten().subscribeNext { results.append($0 as! Int) } expect(results) == [] action = command.toAction() } it("should reflect the enabledness of the command") { expect(action.enabled.value) == true enabledSubject.sendNext(false) expect(enabled).toEventually(beFalsy()) expect(action.enabled.value) == false } it("should execute the command once per start()") { let producer = action.apply(0) expect(results) == [] producer.start() expect(results).toEventually(equal([ 1 ])) producer.start() expect(results).toEventually(equal([ 1, 1 ])) let otherProducer = action.apply(2) expect(results) == [ 1, 1 ] otherProducer.start() expect(results).toEventually(equal([ 1, 1, 3 ])) producer.start() expect(results).toEventually(equal([ 1, 1, 3, 1 ])) } } describe("toRACCommand") { var action: Action! var results: [NSString] = [] var enabledProperty: MutableProperty! var command: RACCommand! var enabled = false beforeEach { results = [] enabledProperty = MutableProperty(true) action = Action(enabledIf: enabledProperty) { input in let inputNumber = input as! Int return SignalProducer(value: "\(inputNumber + 1)") } expect(action.enabled.value) == true action.values.observeNext { results.append($0) } command = toRACCommand(action) expect(command).notTo(beNil()) command.enabled.subscribeNext { enabled = $0 as! Bool } expect(enabled) == true } it("should reflect the enabledness of the action") { enabledProperty.value = false expect(enabled).toEventually(beFalsy()) enabledProperty.value = true expect(enabled).toEventually(beTruthy()) } it("should apply and start a signal once per execution") { let signal = command.execute(0) do { try signal.asynchronouslyWaitUntilCompleted() expect(results) == [ "1" ] try signal.asynchronouslyWaitUntilCompleted() expect(results) == [ "1" ] try command.execute(2).asynchronouslyWaitUntilCompleted() expect(results) == [ "1", "3" ] } catch { XCTFail("Failed to wait for completion") } } } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Swift/PropertySpec.swift ================================================ // // PropertySpec.swift // ReactiveCocoa // // Created by Justin Spahr-Summers on 2015-01-23. // Copyright (c) 2015 GitHub. All rights reserved. // import Result import Nimble import Quick import ReactiveCocoa private let initialPropertyValue = "InitialValue" private let subsequentPropertyValue = "SubsequentValue" private let finalPropertyValue = "FinalValue" class PropertySpec: QuickSpec { override func spec() { describe("ConstantProperty") { it("should have the value given at initialization") { let constantProperty = ConstantProperty(initialPropertyValue) expect(constantProperty.value) == initialPropertyValue } it("should yield a signal that interrupts observers without emitting any value.") { let constantProperty = ConstantProperty(initialPropertyValue) var signalInterrupted = false var hasUnexpectedEventsEmitted = false constantProperty.signal.observe { event in switch event { case .Interrupted: signalInterrupted = true case .Next, .Failed, .Completed: hasUnexpectedEventsEmitted = true } } expect(signalInterrupted) == true expect(hasUnexpectedEventsEmitted) == false } it("should yield a producer that sends the current value then completes") { let constantProperty = ConstantProperty(initialPropertyValue) var sentValue: String? var signalCompleted = false constantProperty.producer.start { event in switch event { case let .Next(value): sentValue = value case .Completed: signalCompleted = true default: break } } expect(sentValue) == initialPropertyValue expect(signalCompleted) == true } } describe("MutableProperty") { it("should have the value given at initialization") { let mutableProperty = MutableProperty(initialPropertyValue) expect(mutableProperty.value) == initialPropertyValue } it("should yield a producer that sends the current value then all changes") { let mutableProperty = MutableProperty(initialPropertyValue) var sentValue: String? mutableProperty.producer.startWithNext { sentValue = $0 } expect(sentValue) == initialPropertyValue mutableProperty.value = subsequentPropertyValue expect(sentValue) == subsequentPropertyValue mutableProperty.value = finalPropertyValue expect(sentValue) == finalPropertyValue } it("should yield a producer that sends the current value then all changes, even if the value actually remains unchanged") { let mutableProperty = MutableProperty(initialPropertyValue) var count = 0 mutableProperty.producer.startWithNext { _ in count = count + 1 } expect(count) == 1 mutableProperty.value = initialPropertyValue expect(count) == 2 mutableProperty.value = initialPropertyValue expect(count) == 3 } it("should yield a signal that emits subsequent changes to the value") { let mutableProperty = MutableProperty(initialPropertyValue) var sentValue: String? mutableProperty.signal.observeNext { sentValue = $0 } expect(sentValue).to(beNil()) mutableProperty.value = subsequentPropertyValue expect(sentValue) == subsequentPropertyValue mutableProperty.value = finalPropertyValue expect(sentValue) == finalPropertyValue } it("should yield a signal that emits subsequent changes to the value, even if the value actually remains unchanged") { let mutableProperty = MutableProperty(initialPropertyValue) var count = 0 mutableProperty.signal.observeNext { _ in count = count + 1 } expect(count) == 0 mutableProperty.value = initialPropertyValue expect(count) == 1 mutableProperty.value = initialPropertyValue expect(count) == 2 } it("should complete its producer when deallocated") { var mutableProperty: MutableProperty? = MutableProperty(initialPropertyValue) var producerCompleted = false mutableProperty!.producer.startWithCompleted { producerCompleted = true } mutableProperty = nil expect(producerCompleted) == true } it("should complete its signal when deallocated") { var mutableProperty: MutableProperty? = MutableProperty(initialPropertyValue) var signalCompleted = false mutableProperty!.signal.observeCompleted { signalCompleted = true } mutableProperty = nil expect(signalCompleted) == true } it("should modify the value atomically") { let property = MutableProperty(initialPropertyValue) expect(property.modify({ _ in subsequentPropertyValue })) == initialPropertyValue expect(property.value) == subsequentPropertyValue } it("should modify the value atomically and subsquently send out a Next event with the new value") { let property = MutableProperty(initialPropertyValue) var value: String? property.producer.startWithNext { value = $0 } expect(value) == initialPropertyValue expect(property.modify({ _ in subsequentPropertyValue })) == initialPropertyValue expect(property.value) == subsequentPropertyValue expect(value) == subsequentPropertyValue } it("should swap the value atomically") { let property = MutableProperty(initialPropertyValue) expect(property.swap(subsequentPropertyValue)) == initialPropertyValue expect(property.value) == subsequentPropertyValue } it("should swap the value atomically and subsquently send out a Next event with the new value") { let property = MutableProperty(initialPropertyValue) var value: String? property.producer.startWithNext { value = $0 } expect(value) == initialPropertyValue expect(property.swap(subsequentPropertyValue)) == initialPropertyValue expect(property.value) == subsequentPropertyValue expect(value) == subsequentPropertyValue } it("should perform an action with the value") { let property = MutableProperty(initialPropertyValue) let result: Bool = property.withValue { $0.isEmpty } expect(result) == false expect(property.value) == initialPropertyValue } it("should not deadlock on recursive value access") { let (producer, observer) = SignalProducer.buffer(1) let property = MutableProperty(0) var value: Int? property <~ producer property.producer.startWithNext { _ in value = property.value } observer.sendNext(10) expect(value) == 10 } it("should not deadlock on recursive value access with a closure") { let (producer, observer) = SignalProducer.buffer(1) let property = MutableProperty(0) var value: Int? property <~ producer property.producer.startWithNext { _ in value = property.withValue { $0 + 1 } } observer.sendNext(10) expect(value) == 11 } it("should not deadlock on recursive observation") { let property = MutableProperty(0) var value: Int? property.producer.startWithNext { _ in property.producer.startWithNext { x in value = x } } expect(value) == 0 property.value = 1 expect(value) == 1 } } describe("AnyProperty") { describe("from a PropertyType") { it("should pass through behaviors of the input property") { let constantProperty = ConstantProperty(initialPropertyValue) let property = AnyProperty(constantProperty) var sentValue: String? var signalSentValue: String? var producerCompleted = false var signalInterrupted = false property.producer.start { event in switch event { case let .Next(value): sentValue = value case .Completed: producerCompleted = true default: break } } property.signal.observe { event in switch event { case let .Next(value): signalSentValue = value case .Interrupted: signalInterrupted = true default: break } } expect(sentValue) == initialPropertyValue expect(signalSentValue).to(beNil()) expect(producerCompleted) == true expect(signalInterrupted) == true } } describe("from a value and SignalProducer") { it("should initially take on the supplied value") { let property = AnyProperty( initialValue: initialPropertyValue, producer: SignalProducer.never) expect(property.value) == initialPropertyValue } it("should take on each value sent on the producer") { let property = AnyProperty( initialValue: initialPropertyValue, producer: SignalProducer(value: subsequentPropertyValue)) expect(property.value) == subsequentPropertyValue } } describe("from a value and Signal") { it("should initially take on the supplied value, then values sent on the signal") { let (signal, observer) = Signal.pipe() let property = AnyProperty( initialValue: initialPropertyValue, signal: signal) expect(property.value) == initialPropertyValue observer.sendNext(subsequentPropertyValue) expect(property.value) == subsequentPropertyValue } } } describe("DynamicProperty") { var object: ObservableObject! var property: DynamicProperty! let propertyValue: () -> Int? = { if let value: AnyObject = property?.value { return value as? Int } else { return nil } } beforeEach { object = ObservableObject() expect(object.rac_value) == 0 property = DynamicProperty(object: object, keyPath: "rac_value") } afterEach { object = nil } it("should read the underlying object") { expect(propertyValue()) == 0 object.rac_value = 1 expect(propertyValue()) == 1 } it("should write the underlying object") { property.value = 1 expect(object.rac_value) == 1 expect(propertyValue()) == 1 } it("should yield a producer that sends the current value and then the changes for the key path of the underlying object") { var values: [Int] = [] property.producer.startWithNext { value in expect(value).notTo(beNil()) values.append(value as! Int) } expect(values) == [ 0 ] property.value = 1 expect(values) == [ 0, 1 ] object.rac_value = 2 expect(values) == [ 0, 1, 2 ] } it("should yield a producer that sends the current value and then the changes for the key path of the underlying object, even if the value actually remains unchanged") { var values: [Int] = [] property.producer.startWithNext { value in expect(value).notTo(beNil()) values.append(value as! Int) } expect(values) == [ 0 ] property.value = 0 expect(values) == [ 0, 0 ] object.rac_value = 0 expect(values) == [ 0, 0, 0 ] } it("should yield a signal that emits subsequent values for the key path of the underlying object") { var values: [Int] = [] property.signal.observeNext { value in expect(value).notTo(beNil()) values.append(value as! Int) } expect(values) == [] property.value = 1 expect(values) == [ 1 ] object.rac_value = 2 expect(values) == [ 1, 2 ] } it("should yield a signal that emits subsequent values for the key path of the underlying object, even if the value actually remains unchanged") { var values: [Int] = [] property.signal.observeNext { value in expect(value).notTo(beNil()) values.append(value as! Int) } expect(values) == [] property.value = 0 expect(values) == [ 0 ] object.rac_value = 0 expect(values) == [ 0, 0 ] } it("should have a completed producer when the underlying object deallocates") { var completed = false property = { // Use a closure so this object has a shorter lifetime. let object = ObservableObject() let property = DynamicProperty(object: object, keyPath: "rac_value") property.producer.startWithCompleted { completed = true } expect(completed) == false expect(property.value).notTo(beNil()) return property }() expect(completed).toEventually(beTruthy()) expect(property.value).to(beNil()) } it("should have a completed signal when the underlying object deallocates") { var completed = false property = { // Use a closure so this object has a shorter lifetime. let object = ObservableObject() let property = DynamicProperty(object: object, keyPath: "rac_value") property.signal.observeCompleted { completed = true } expect(completed) == false expect(property.value).notTo(beNil()) return property }() expect(completed).toEventually(beTruthy()) expect(property.value).to(beNil()) } it("should retain property while DynamicProperty's underlying object is retained"){ weak var dynamicProperty: DynamicProperty? = property property = nil expect(dynamicProperty).toNot(beNil()) object = nil expect(dynamicProperty).to(beNil()) } } describe("binding") { describe("from a Signal") { it("should update the property with values sent from the signal") { let (signal, observer) = Signal.pipe() let mutableProperty = MutableProperty(initialPropertyValue) mutableProperty <~ signal // Verify that the binding hasn't changed the property value: expect(mutableProperty.value) == initialPropertyValue observer.sendNext(subsequentPropertyValue) expect(mutableProperty.value) == subsequentPropertyValue } it("should tear down the binding when disposed") { let (signal, observer) = Signal.pipe() let mutableProperty = MutableProperty(initialPropertyValue) let bindingDisposable = mutableProperty <~ signal bindingDisposable.dispose() observer.sendNext(subsequentPropertyValue) expect(mutableProperty.value) == initialPropertyValue } it("should tear down the binding when bound signal is completed") { let (signal, observer) = Signal.pipe() let mutableProperty = MutableProperty(initialPropertyValue) let bindingDisposable = mutableProperty <~ signal expect(bindingDisposable.disposed) == false observer.sendCompleted() expect(bindingDisposable.disposed) == true } it("should tear down the binding when the property deallocates") { let (signal, _) = Signal.pipe() var mutableProperty: MutableProperty? = MutableProperty(initialPropertyValue) let bindingDisposable = mutableProperty! <~ signal mutableProperty = nil expect(bindingDisposable.disposed) == true } } describe("from a SignalProducer") { it("should start a signal and update the property with its values") { let signalValues = [initialPropertyValue, subsequentPropertyValue] let signalProducer = SignalProducer(values: signalValues) let mutableProperty = MutableProperty(initialPropertyValue) mutableProperty <~ signalProducer expect(mutableProperty.value) == signalValues.last! } it("should tear down the binding when disposed") { let signalValues = [initialPropertyValue, subsequentPropertyValue] let signalProducer = SignalProducer(values: signalValues) let mutableProperty = MutableProperty(initialPropertyValue) let disposable = mutableProperty <~ signalProducer disposable.dispose() // TODO: Assert binding was torn down? } it("should tear down the binding when bound signal is completed") { let (signalProducer, observer) = SignalProducer.buffer(1) let mutableProperty = MutableProperty(initialPropertyValue) mutableProperty <~ signalProducer observer.sendCompleted() // TODO: Assert binding was torn down? } it("should tear down the binding when the property deallocates") { let signalValues = [initialPropertyValue, subsequentPropertyValue] let signalProducer = SignalProducer(values: signalValues) var mutableProperty: MutableProperty? = MutableProperty(initialPropertyValue) let disposable = mutableProperty! <~ signalProducer mutableProperty = nil expect(disposable.disposed) == true } } describe("from another property") { it("should take the source property's current value") { let sourceProperty = ConstantProperty(initialPropertyValue) let destinationProperty = MutableProperty("") destinationProperty <~ sourceProperty.producer expect(destinationProperty.value) == initialPropertyValue } it("should update with changes to the source property's value") { let sourceProperty = MutableProperty(initialPropertyValue) let destinationProperty = MutableProperty("") destinationProperty <~ sourceProperty.producer sourceProperty.value = subsequentPropertyValue expect(destinationProperty.value) == subsequentPropertyValue } it("should tear down the binding when disposed") { let sourceProperty = MutableProperty(initialPropertyValue) let destinationProperty = MutableProperty("") let bindingDisposable = destinationProperty <~ sourceProperty.producer bindingDisposable.dispose() sourceProperty.value = subsequentPropertyValue expect(destinationProperty.value) == initialPropertyValue } it("should tear down the binding when the source property deallocates") { var sourceProperty: MutableProperty? = MutableProperty(initialPropertyValue) let destinationProperty = MutableProperty("") destinationProperty <~ sourceProperty!.producer sourceProperty = nil // TODO: Assert binding was torn down? } it("should tear down the binding when the destination property deallocates") { let sourceProperty = MutableProperty(initialPropertyValue) var destinationProperty: MutableProperty? = MutableProperty("") let bindingDisposable = destinationProperty! <~ sourceProperty.producer destinationProperty = nil expect(bindingDisposable.disposed) == true } } } } } private class ObservableObject: NSObject { dynamic var rac_value: Int = 0 } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Swift/SchedulerSpec.swift ================================================ // // SchedulerSpec.swift // ReactiveCocoa // // Created by Justin Spahr-Summers on 2014-07-13. // Copyright (c) 2014 GitHub. All rights reserved. // import Foundation import Nimble import Quick @testable import ReactiveCocoa class SchedulerSpec: QuickSpec { override func spec() { describe("ImmediateScheduler") { it("should run enqueued actions immediately") { var didRun = false ImmediateScheduler().schedule { didRun = true } expect(didRun) == true } } describe("UIScheduler") { func dispatchSyncInBackground(action: () -> ()) { let group = dispatch_group_create() dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), action) dispatch_group_wait(group, DISPATCH_TIME_FOREVER) } it("should run actions immediately when on the main thread") { let scheduler = UIScheduler() var values: [Int] = [] expect(NSThread.isMainThread()) == true scheduler.schedule { values.append(0) } expect(values) == [ 0 ] scheduler.schedule { values.append(1) } scheduler.schedule { values.append(2) } expect(values) == [ 0, 1, 2 ] } it("should enqueue actions scheduled from the background") { let scheduler = UIScheduler() var values: [Int] = [] dispatchSyncInBackground { scheduler.schedule { expect(NSThread.isMainThread()) == true values.append(0) } return } expect(values) == [] expect(values).toEventually(equal([ 0 ])) dispatchSyncInBackground { scheduler.schedule { expect(NSThread.isMainThread()) == true values.append(1) } scheduler.schedule { expect(NSThread.isMainThread()) == true values.append(2) } return } expect(values) == [ 0 ] expect(values).toEventually(equal([ 0, 1, 2 ])) } it("should run actions enqueued from the main thread after those from the background") { let scheduler = UIScheduler() var values: [Int] = [] dispatchSyncInBackground { scheduler.schedule { expect(NSThread.isMainThread()) == true values.append(0) } return } scheduler.schedule { expect(NSThread.isMainThread()) == true values.append(1) } scheduler.schedule { expect(NSThread.isMainThread()) == true values.append(2) } expect(values) == [] expect(values).toEventually(equal([ 0, 1, 2 ])) } } describe("QueueScheduler") { it("should run enqueued actions on a global queue") { var didRun = false let scheduler: QueueScheduler if #available(OSX 10.10, *) { scheduler = QueueScheduler(qos: QOS_CLASS_DEFAULT) } else { scheduler = QueueScheduler(queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) } scheduler.schedule { didRun = true expect(NSThread.isMainThread()) == false } expect{didRun}.toEventually(beTruthy()) } describe("on a given queue") { var scheduler: QueueScheduler! beforeEach { if #available(OSX 10.10, *) { scheduler = QueueScheduler(qos: QOS_CLASS_DEFAULT) } else { scheduler = QueueScheduler(queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) } dispatch_suspend(scheduler.queue) } it("should run enqueued actions serially on the given queue") { var value = 0 for _ in 0..<5 { scheduler.schedule { expect(NSThread.isMainThread()) == false value++ } } expect(value) == 0 dispatch_resume(scheduler.queue) expect{value}.toEventually(equal(5)) } it("should run enqueued actions after a given date") { var didRun = false scheduler.scheduleAfter(NSDate()) { didRun = true expect(NSThread.isMainThread()) == false } expect(didRun) == false dispatch_resume(scheduler.queue) expect{didRun}.toEventually(beTruthy()) } it("should repeatedly run actions after a given date") { let disposable = SerialDisposable() var count = 0 let timesToRun = 3 disposable.innerDisposable = scheduler.scheduleAfter(NSDate(), repeatingEvery: 0.01, withLeeway: 0) { expect(NSThread.isMainThread()) == false if ++count == timesToRun { disposable.dispose() } } expect(count) == 0 dispatch_resume(scheduler.queue) expect{count}.toEventually(equal(timesToRun)) } } } describe("TestScheduler") { var scheduler: TestScheduler! var startDate: NSDate! // How much dates are allowed to differ when they should be "equal." let dateComparisonDelta = 0.00001 beforeEach { startDate = NSDate() scheduler = TestScheduler(startDate: startDate) expect(scheduler.currentDate) == startDate } it("should run immediately enqueued actions upon advancement") { var string = "" scheduler.schedule { string += "foo" expect(NSThread.isMainThread()) == true } scheduler.schedule { string += "bar" expect(NSThread.isMainThread()) == true } expect(string) == "" scheduler.advance() expect(scheduler.currentDate).to(beCloseTo(startDate)) expect(string) == "foobar" } it("should run actions when advanced past the target date") { var string = "" scheduler.scheduleAfter(15) { string += "bar" expect(NSThread.isMainThread()) == true } scheduler.scheduleAfter(5) { string += "foo" expect(NSThread.isMainThread()) == true } expect(string) == "" scheduler.advanceByInterval(10) expect(scheduler.currentDate).to(beCloseTo(startDate.dateByAddingTimeInterval(10), within: dateComparisonDelta)) expect(string) == "foo" scheduler.advanceByInterval(10) expect(scheduler.currentDate).to(beCloseTo(startDate.dateByAddingTimeInterval(20), within: dateComparisonDelta)) expect(string) == "foobar" } it("should run all remaining actions in order") { var string = "" scheduler.scheduleAfter(15) { string += "bar" expect(NSThread.isMainThread()) == true } scheduler.scheduleAfter(5) { string += "foo" expect(NSThread.isMainThread()) == true } scheduler.schedule { string += "fuzzbuzz" expect(NSThread.isMainThread()) == true } expect(string) == "" scheduler.run() expect(scheduler.currentDate) == NSDate.distantFuture() expect(string) == "fuzzbuzzfoobar" } } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Swift/SignalLifetimeSpec.swift ================================================ // // SignalLifetimeSpec.swift // ReactiveCocoa // // Created by Vadim Yelagin on 2015-12-13. // Copyright (c) 2015 GitHub. All rights reserved. // import Result import Nimble import Quick import ReactiveCocoa class SignalLifetimeSpec: QuickSpec { override func spec() { describe("init") { var testScheduler: TestScheduler! beforeEach { testScheduler = TestScheduler() } it("should deallocate") { weak var signal: Signal? = Signal { _ in nil } expect(signal).to(beNil()) } it("should deallocate even if it has an observer") { weak var signal: Signal? = { let signal: Signal = Signal { _ in nil } return signal }() expect(signal).to(beNil()) } it("should deallocate even if it has an observer with retained disposable") { var disposable: Disposable? = nil weak var signal: Signal? = { let signal: Signal = Signal { _ in nil } disposable = signal.observe(Observer()) return signal }() expect(signal).to(beNil()) disposable?.dispose() expect(signal).to(beNil()) } it("should deallocate after erroring") { weak var signal: Signal? = Signal { observer in testScheduler.schedule { observer.sendFailed(TestError.Default) } return nil } var errored = false signal?.observeFailed { _ in errored = true } expect(errored) == false expect(signal).toNot(beNil()) testScheduler.run() expect(errored) == true expect(signal).to(beNil()) } it("should deallocate after completing") { weak var signal: Signal? = Signal { observer in testScheduler.schedule { observer.sendCompleted() } return nil } var completed = false signal?.observeCompleted { completed = true } expect(completed) == false expect(signal).toNot(beNil()) testScheduler.run() expect(completed) == true expect(signal).to(beNil()) } it("should deallocate after interrupting") { weak var signal: Signal? = Signal { observer in testScheduler.schedule { observer.sendInterrupted() } return nil } var interrupted = false signal?.observeInterrupted { interrupted = true } expect(interrupted) == false expect(signal).toNot(beNil()) testScheduler.run() expect(interrupted) == true expect(signal).to(beNil()) } } describe("Signal.pipe") { it("should deallocate") { weak var signal = Signal<(), NoError>.pipe().0 expect(signal).to(beNil()) } it("should deallocate after erroring") { let testScheduler = TestScheduler() weak var weakSignal: Signal<(), TestError>? // Use an inner closure to help ARC deallocate things as we // expect. let test: () -> () = { let (signal, observer) = Signal<(), TestError>.pipe() weakSignal = signal testScheduler.schedule { observer.sendFailed(TestError.Default) } } test() expect(weakSignal).toNot(beNil()) testScheduler.run() expect(weakSignal).to(beNil()) } it("should deallocate after completing") { let testScheduler = TestScheduler() weak var weakSignal: Signal<(), TestError>? // Use an inner closure to help ARC deallocate things as we // expect. let test: () -> () = { let (signal, observer) = Signal<(), TestError>.pipe() weakSignal = signal testScheduler.schedule { observer.sendCompleted() } } test() expect(weakSignal).toNot(beNil()) testScheduler.run() expect(weakSignal).to(beNil()) } it("should deallocate after interrupting") { let testScheduler = TestScheduler() weak var weakSignal: Signal<(), NoError>? let test: () -> () = { let (signal, observer) = Signal<(), NoError>.pipe() weakSignal = signal testScheduler.schedule { observer.sendInterrupted() } } test() expect(weakSignal).toNot(beNil()) testScheduler.run() expect(weakSignal).to(beNil()) } } describe("testTransform") { it("should deallocate") { weak var signal: Signal? = Signal { _ in nil }.testTransform() expect(signal).to(beNil()) } it("should deallocate even if it has an observer") { weak var signal: Signal? = { let signal: Signal = Signal { _ in nil }.testTransform() signal.observe(Observer()) return signal }() expect(signal).to(beNil()) } it("should deallocate even if it has an observer with retained disposable") { var disposable: Disposable? = nil weak var signal: Signal? = { let signal: Signal = Signal { _ in nil }.testTransform() disposable = signal.observe(Observer()) return signal }() expect(signal).to(beNil()) disposable?.dispose() expect(signal).to(beNil()) } } } } private extension SignalType { func testTransform() -> Signal { return Signal { observer in return self.observe(observer.action) } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Swift/SignalProducerLiftingSpec.swift ================================================ // // SignalProducerLiftingSpec.swift // ReactiveCocoa // // Created by Neil Pankey on 6/14/15. // Copyright © 2015 GitHub. All rights reserved. // import Result import Nimble import Quick import ReactiveCocoa class SignalProducerLiftingSpec: QuickSpec { override func spec() { describe("map") { it("should transform the values of the signal") { let (producer, observer) = SignalProducer.buffer(1) let mappedProducer = producer.map { String($0 + 1) } var lastValue: String? mappedProducer.startWithNext { lastValue = $0 return } expect(lastValue).to(beNil()) observer.sendNext(0) expect(lastValue) == "1" observer.sendNext(1) expect(lastValue) == "2" } } describe("mapError") { it("should transform the errors of the signal") { let (producer, observer) = SignalProducer.buffer(1) let producerError = NSError(domain: "com.reactivecocoa.errordomain", code: 100, userInfo: nil) var error: NSError? producer .mapError { _ in producerError } .startWithFailed { error = $0 } expect(error).to(beNil()) observer.sendFailed(TestError.Default) expect(error) == producerError } } describe("filter") { it("should omit values from the producer") { let (producer, observer) = SignalProducer.buffer(1) let mappedProducer = producer.filter { $0 % 2 == 0 } var lastValue: Int? mappedProducer.startWithNext { lastValue = $0 } expect(lastValue).to(beNil()) observer.sendNext(0) expect(lastValue) == 0 observer.sendNext(1) expect(lastValue) == 0 observer.sendNext(2) expect(lastValue) == 2 } } describe("ignoreNil") { it("should forward only non-nil values") { let (producer, observer) = SignalProducer.buffer(1) let mappedProducer = producer.ignoreNil() var lastValue: Int? mappedProducer.startWithNext { lastValue = $0 } expect(lastValue).to(beNil()) observer.sendNext(nil) expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue) == 1 observer.sendNext(nil) expect(lastValue) == 1 observer.sendNext(2) expect(lastValue) == 2 } } describe("scan") { it("should incrementally accumulate a value") { let (baseProducer, observer) = SignalProducer.buffer(1) let producer = baseProducer.scan("", +) var lastValue: String? producer.startWithNext { lastValue = $0 } expect(lastValue).to(beNil()) observer.sendNext("a") expect(lastValue) == "a" observer.sendNext("bb") expect(lastValue) == "abb" } } describe("reduce") { it("should accumulate one value") { let (baseProducer, observer) = SignalProducer.buffer(1) let producer = baseProducer.reduce(1, +) var lastValue: Int? var completed = false producer.start { event in switch event { case let .Next(value): lastValue = value case .Completed: completed = true default: break } } expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue).to(beNil()) observer.sendNext(2) expect(lastValue).to(beNil()) expect(completed) == false observer.sendCompleted() expect(completed) == true expect(lastValue) == 4 } it("should send the initial value if none are received") { let (baseProducer, observer) = SignalProducer.buffer(1) let producer = baseProducer.reduce(1, +) var lastValue: Int? var completed = false producer.start { event in switch event { case let .Next(value): lastValue = value case .Completed: completed = true default: break } } expect(lastValue).to(beNil()) expect(completed) == false observer.sendCompleted() expect(lastValue) == 1 expect(completed) == true } } describe("skip") { it("should skip initial values") { let (baseProducer, observer) = SignalProducer.buffer(1) let producer = baseProducer.skip(1) var lastValue: Int? producer.startWithNext { lastValue = $0 } expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue).to(beNil()) observer.sendNext(2) expect(lastValue) == 2 } it("should not skip any values when 0") { let (baseProducer, observer) = SignalProducer.buffer(1) let producer = baseProducer.skip(0) var lastValue: Int? producer.startWithNext { lastValue = $0 } expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue) == 1 observer.sendNext(2) expect(lastValue) == 2 } } describe("skipRepeats") { it("should skip duplicate Equatable values") { let (baseProducer, observer) = SignalProducer.buffer(1) let producer = baseProducer.skipRepeats() var values: [Bool] = [] producer.startWithNext { values.append($0) } expect(values) == [] observer.sendNext(true) expect(values) == [ true ] observer.sendNext(true) expect(values) == [ true ] observer.sendNext(false) expect(values) == [ true, false ] observer.sendNext(true) expect(values) == [ true, false, true ] } it("should skip values according to a predicate") { let (baseProducer, observer) = SignalProducer.buffer(1) let producer = baseProducer.skipRepeats { $0.characters.count == $1.characters.count } var values: [String] = [] producer.startWithNext { values.append($0) } expect(values) == [] observer.sendNext("a") expect(values) == [ "a" ] observer.sendNext("b") expect(values) == [ "a" ] observer.sendNext("cc") expect(values) == [ "a", "cc" ] observer.sendNext("d") expect(values) == [ "a", "cc", "d" ] } } describe("skipWhile") { var producer: SignalProducer! var observer: Signal.Observer! var lastValue: Int? beforeEach { let (baseProducer, incomingObserver) = SignalProducer.buffer(1) producer = baseProducer.skipWhile { $0 < 2 } observer = incomingObserver lastValue = nil producer.startWithNext { lastValue = $0 } } it("should skip while the predicate is true") { expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue).to(beNil()) observer.sendNext(2) expect(lastValue) == 2 observer.sendNext(0) expect(lastValue) == 0 } it("should not skip any values when the predicate starts false") { expect(lastValue).to(beNil()) observer.sendNext(3) expect(lastValue) == 3 observer.sendNext(1) expect(lastValue) == 1 } } describe("skipUntil") { var producer: SignalProducer! var observer: Signal.Observer! var triggerObserver: Signal<(), NoError>.Observer! var lastValue: Int? = nil beforeEach { let (baseProducer, baseIncomingObserver) = SignalProducer.buffer(1) let (triggerSignal, incomingTriggerObserver) = SignalProducer<(), NoError>.buffer(1) producer = baseProducer.skipUntil(triggerSignal) observer = baseIncomingObserver triggerObserver = incomingTriggerObserver lastValue = nil producer.start { event in switch event { case let .Next(value): lastValue = value default: break } } } it("should skip values until the trigger fires") { expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue).to(beNil()) observer.sendNext(2) expect(lastValue).to(beNil()) triggerObserver.sendNext(()) observer.sendNext(0) expect(lastValue) == 0 } it("should skip values until the trigger completes") { expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue).to(beNil()) observer.sendNext(2) expect(lastValue).to(beNil()) triggerObserver.sendCompleted() observer.sendNext(0) expect(lastValue) == 0 } } describe("take") { it("should take initial values") { let (baseProducer, observer) = SignalProducer.buffer(1) let producer = baseProducer.take(2) var lastValue: Int? var completed = false producer.start { event in switch event { case let .Next(value): lastValue = value case .Completed: completed = true default: break } } expect(lastValue).to(beNil()) expect(completed) == false observer.sendNext(1) expect(lastValue) == 1 expect(completed) == false observer.sendNext(2) expect(lastValue) == 2 expect(completed) == true } it("should complete immediately after taking given number of values") { let numbers = [ 1, 2, 4, 4, 5 ] let testScheduler = TestScheduler() let producer: SignalProducer = SignalProducer { observer, _ in // workaround `Class declaration cannot close over value 'observer' defined in outer scope` let observer = observer testScheduler.schedule { for number in numbers { observer.sendNext(number) } } } var completed = false producer .take(numbers.count) .startWithCompleted { completed = true } expect(completed) == false testScheduler.run() expect(completed) == true } it("should interrupt when 0") { let numbers = [ 1, 2, 4, 4, 5 ] let testScheduler = TestScheduler() let producer: SignalProducer = SignalProducer { observer, _ in // workaround `Class declaration cannot close over value 'observer' defined in outer scope` let observer = observer testScheduler.schedule { for number in numbers { observer.sendNext(number) } } } var result: [Int] = [] var interrupted = false producer .take(0) .start { event in switch event { case let .Next(number): result.append(number) case .Interrupted: interrupted = true default: break } } expect(interrupted) == true testScheduler.run() expect(result).to(beEmpty()) } } describe("collect") { it("should collect all values") { let (original, observer) = SignalProducer.buffer(1) let producer = original.collect() let expectedResult = [ 1, 2, 3 ] var result: [Int]? producer.startWithNext { value in expect(result).to(beNil()) result = value } for number in expectedResult { observer.sendNext(number) } expect(result).to(beNil()) observer.sendCompleted() expect(result) == expectedResult } it("should complete with an empty array if there are no values") { let (original, observer) = SignalProducer.buffer(1) let producer = original.collect() var result: [Int]? producer.startWithNext { result = $0 } expect(result).to(beNil()) observer.sendCompleted() expect(result) == [] } it("should forward errors") { let (original, observer) = SignalProducer.buffer(1) let producer = original.collect() var error: TestError? producer.startWithFailed { error = $0 } expect(error).to(beNil()) observer.sendFailed(.Default) expect(error) == TestError.Default } } describe("takeUntil") { var producer: SignalProducer! var observer: Signal.Observer! var triggerObserver: Signal<(), NoError>.Observer! var lastValue: Int? = nil var completed: Bool = false beforeEach { let (baseProducer, baseIncomingObserver) = SignalProducer.buffer(1) let (triggerSignal, incomingTriggerObserver) = SignalProducer<(), NoError>.buffer(1) producer = baseProducer.takeUntil(triggerSignal) observer = baseIncomingObserver triggerObserver = incomingTriggerObserver lastValue = nil completed = false producer.start { event in switch event { case let .Next(value): lastValue = value case .Completed: completed = true default: break } } } it("should take values until the trigger fires") { expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue) == 1 observer.sendNext(2) expect(lastValue) == 2 expect(completed) == false triggerObserver.sendNext(()) expect(completed) == true } it("should take values until the trigger completes") { expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue) == 1 observer.sendNext(2) expect(lastValue) == 2 expect(completed) == false triggerObserver.sendCompleted() expect(completed) == true } it("should complete if the trigger fires immediately") { expect(lastValue).to(beNil()) expect(completed) == false triggerObserver.sendNext(()) expect(completed) == true expect(lastValue).to(beNil()) } } describe("takeUntilReplacement") { var producer: SignalProducer! var observer: Signal.Observer! var replacementObserver: Signal.Observer! var lastValue: Int? = nil var completed: Bool = false beforeEach { let (baseProducer, incomingObserver) = SignalProducer.buffer(1) let (replacementSignal, incomingReplacementObserver) = SignalProducer.buffer(1) producer = baseProducer.takeUntilReplacement(replacementSignal) observer = incomingObserver replacementObserver = incomingReplacementObserver lastValue = nil completed = false producer.start { event in switch event { case let .Next(value): lastValue = value case .Completed: completed = true default: break } } } it("should take values from the original then the replacement") { expect(lastValue).to(beNil()) expect(completed) == false observer.sendNext(1) expect(lastValue) == 1 observer.sendNext(2) expect(lastValue) == 2 replacementObserver.sendNext(3) expect(lastValue) == 3 expect(completed) == false observer.sendNext(4) expect(lastValue) == 3 expect(completed) == false replacementObserver.sendNext(5) expect(lastValue) == 5 expect(completed) == false replacementObserver.sendCompleted() expect(completed) == true } } describe("takeWhile") { var producer: SignalProducer! var observer: Signal.Observer! beforeEach { let (baseProducer, incomingObserver) = SignalProducer.buffer(1) producer = baseProducer.takeWhile { $0 <= 4 } observer = incomingObserver } it("should take while the predicate is true") { var latestValue: Int! var completed = false producer.start { event in switch event { case let .Next(value): latestValue = value case .Completed: completed = true default: break } } for value in -1...4 { observer.sendNext(value) expect(latestValue) == value expect(completed) == false } observer.sendNext(5) expect(latestValue) == 4 expect(completed) == true } it("should complete if the predicate starts false") { var latestValue: Int? var completed = false producer.start { event in switch event { case let .Next(value): latestValue = value case .Completed: completed = true default: break } } observer.sendNext(5) expect(latestValue).to(beNil()) expect(completed) == true } } describe("observeOn") { it("should send events on the given scheduler") { let testScheduler = TestScheduler() let (producer, observer) = SignalProducer.buffer(1) var result: [Int] = [] producer .observeOn(testScheduler) .startWithNext { result.append($0) } observer.sendNext(1) observer.sendNext(2) expect(result).to(beEmpty()) testScheduler.run() expect(result) == [ 1, 2 ] } } describe("delay") { it("should send events on the given scheduler after the interval") { let testScheduler = TestScheduler() let producer: SignalProducer = SignalProducer { observer, _ in testScheduler.schedule { observer.sendNext(1) } testScheduler.scheduleAfter(5, action: { observer.sendNext(2) observer.sendCompleted() }) } var result: [Int] = [] var completed = false producer .delay(10, onScheduler: testScheduler) .start { event in switch event { case let .Next(number): result.append(number) case .Completed: completed = true default: break } } testScheduler.advanceByInterval(4) // send initial value expect(result).to(beEmpty()) testScheduler.advanceByInterval(10) // send second value and receive first expect(result) == [ 1 ] expect(completed) == false testScheduler.advanceByInterval(10) // send second value and receive first expect(result) == [ 1, 2 ] expect(completed) == true } it("should schedule errors immediately") { let testScheduler = TestScheduler() let producer: SignalProducer = SignalProducer { observer, _ in // workaround `Class declaration cannot close over value 'observer' defined in outer scope` let observer = observer testScheduler.schedule { observer.sendFailed(TestError.Default) } } var errored = false producer .delay(10, onScheduler: testScheduler) .startWithFailed { _ in errored = true } testScheduler.advance() expect(errored) == true } } describe("throttle") { var scheduler: TestScheduler! var observer: Signal.Observer! var producer: SignalProducer! beforeEach { scheduler = TestScheduler() let (baseProducer, baseObserver) = SignalProducer.buffer(1) observer = baseObserver producer = baseProducer.throttle(1, onScheduler: scheduler) } it("should send values on the given scheduler at no less than the interval") { var values: [Int] = [] producer.startWithNext { value in values.append(value) } expect(values) == [] observer.sendNext(0) expect(values) == [] scheduler.advance() expect(values) == [ 0 ] observer.sendNext(1) observer.sendNext(2) expect(values) == [ 0 ] scheduler.advanceByInterval(1.5) expect(values) == [ 0, 2 ] scheduler.advanceByInterval(3) expect(values) == [ 0, 2 ] observer.sendNext(3) expect(values) == [ 0, 2 ] scheduler.advance() expect(values) == [ 0, 2, 3 ] observer.sendNext(4) observer.sendNext(5) scheduler.advance() expect(values) == [ 0, 2, 3 ] scheduler.run() expect(values) == [ 0, 2, 3, 5 ] } it("should schedule completion immediately") { var values: [Int] = [] var completed = false producer.start { event in switch event { case let .Next(value): values.append(value) case .Completed: completed = true default: break } } observer.sendNext(0) scheduler.advance() expect(values) == [ 0 ] observer.sendNext(1) observer.sendCompleted() expect(completed) == false scheduler.run() expect(values) == [ 0 ] expect(completed) == true } } describe("sampleOn") { var sampledProducer: SignalProducer! var observer: Signal.Observer! var samplerObserver: Signal<(), NoError>.Observer! beforeEach { let (producer, incomingObserver) = SignalProducer.buffer(1) let (sampler, incomingSamplerObserver) = SignalProducer<(), NoError>.buffer(1) sampledProducer = producer.sampleOn(sampler) observer = incomingObserver samplerObserver = incomingSamplerObserver } it("should forward the latest value when the sampler fires") { var result: [Int] = [] sampledProducer.startWithNext { result.append($0) } observer.sendNext(1) observer.sendNext(2) samplerObserver.sendNext(()) expect(result) == [ 2 ] } it("should do nothing if sampler fires before signal receives value") { var result: [Int] = [] sampledProducer.startWithNext { result.append($0) } samplerObserver.sendNext(()) expect(result).to(beEmpty()) } it("should send lates value multiple times when sampler fires multiple times") { var result: [Int] = [] sampledProducer.startWithNext { result.append($0) } observer.sendNext(1) samplerObserver.sendNext(()) samplerObserver.sendNext(()) expect(result) == [ 1, 1 ] } it("should complete when both inputs have completed") { var completed = false sampledProducer.startWithCompleted { completed = true } observer.sendCompleted() expect(completed) == false samplerObserver.sendCompleted() expect(completed) == true } it("should emit an initial value if the sampler is a synchronous SignalProducer") { let producer = SignalProducer(values: [1]) let sampler = SignalProducer<(), NoError>(value: ()) let result = producer.sampleOn(sampler) var valueReceived: Int? result.startWithNext { valueReceived = $0 } expect(valueReceived) == 1 } } describe("combineLatestWith") { var combinedProducer: SignalProducer<(Int, Double), NoError>! var observer: Signal.Observer! var otherObserver: Signal.Observer! beforeEach { let (producer, incomingObserver) = SignalProducer.buffer(1) let (otherSignal, incomingOtherObserver) = SignalProducer.buffer(1) combinedProducer = producer.combineLatestWith(otherSignal) observer = incomingObserver otherObserver = incomingOtherObserver } it("should forward the latest values from both inputs") { var latest: (Int, Double)? combinedProducer.startWithNext { latest = $0 } observer.sendNext(1) expect(latest).to(beNil()) // is there a better way to test tuples? otherObserver.sendNext(1.5) expect(latest?.0) == 1 expect(latest?.1) == 1.5 observer.sendNext(2) expect(latest?.0) == 2 expect(latest?.1) == 1.5 } it("should complete when both inputs have completed") { var completed = false combinedProducer.startWithCompleted { completed = true } observer.sendCompleted() expect(completed) == false otherObserver.sendCompleted() expect(completed) == true } } describe("zipWith") { var leftObserver: Signal.Observer! var rightObserver: Signal.Observer! var zipped: SignalProducer<(Int, String), NoError>! beforeEach { let (leftProducer, incomingLeftObserver) = SignalProducer.buffer(1) let (rightProducer, incomingRightObserver) = SignalProducer.buffer(1) leftObserver = incomingLeftObserver rightObserver = incomingRightObserver zipped = leftProducer.zipWith(rightProducer) } it("should combine pairs") { var result: [String] = [] zipped.startWithNext { (left, right) in result.append("\(left)\(right)") } leftObserver.sendNext(1) leftObserver.sendNext(2) expect(result) == [] rightObserver.sendNext("foo") expect(result) == [ "1foo" ] leftObserver.sendNext(3) rightObserver.sendNext("bar") expect(result) == [ "1foo", "2bar" ] rightObserver.sendNext("buzz") expect(result) == [ "1foo", "2bar", "3buzz" ] rightObserver.sendNext("fuzz") expect(result) == [ "1foo", "2bar", "3buzz" ] leftObserver.sendNext(4) expect(result) == [ "1foo", "2bar", "3buzz", "4fuzz" ] } it("should complete when the shorter signal has completed") { var result: [String] = [] var completed = false zipped.start { event in switch event { case let .Next(left, right): result.append("\(left)\(right)") case .Completed: completed = true default: break } } expect(completed) == false leftObserver.sendNext(0) leftObserver.sendCompleted() expect(completed) == false expect(result) == [] rightObserver.sendNext("foo") expect(completed) == true expect(result) == [ "0foo" ] } } describe("materialize") { it("should reify events from the signal") { let (producer, observer) = SignalProducer.buffer(1) var latestEvent: Event? producer .materialize() .startWithNext { latestEvent = $0 } observer.sendNext(2) expect(latestEvent).toNot(beNil()) if let latestEvent = latestEvent { switch latestEvent { case let .Next(value): expect(value) == 2 default: fail() } } observer.sendFailed(TestError.Default) if let latestEvent = latestEvent { switch latestEvent { case .Failed(_): () default: fail() } } } } describe("dematerialize") { typealias IntEvent = Event var observer: Signal.Observer! var dematerialized: SignalProducer! beforeEach { let (producer, incomingObserver) = SignalProducer.buffer(1) observer = incomingObserver dematerialized = producer.dematerialize() } it("should send values for Next events") { var result: [Int] = [] dematerialized.startWithNext { result.append($0) } expect(result).to(beEmpty()) observer.sendNext(.Next(2)) expect(result) == [ 2 ] observer.sendNext(.Next(4)) expect(result) == [ 2, 4 ] } it("should error out for Error events") { var errored = false dematerialized.startWithFailed { _ in errored = true } expect(errored) == false observer.sendNext(.Failed(TestError.Default)) expect(errored) == true } it("should complete early for Completed events") { var completed = false dematerialized.startWithCompleted { completed = true } expect(completed) == false observer.sendNext(IntEvent.Completed) expect(completed) == true } } describe("takeLast") { var observer: Signal.Observer! var lastThree: SignalProducer! beforeEach { let (producer, incomingObserver) = SignalProducer.buffer(1) observer = incomingObserver lastThree = producer.takeLast(3) } it("should send the last N values upon completion") { var result: [Int] = [] lastThree.startWithNext { result.append($0) } observer.sendNext(1) observer.sendNext(2) observer.sendNext(3) observer.sendNext(4) expect(result).to(beEmpty()) observer.sendCompleted() expect(result) == [ 2, 3, 4 ] } it("should send less than N values if not enough were received") { var result: [Int] = [] lastThree.startWithNext { result.append($0) } observer.sendNext(1) observer.sendNext(2) observer.sendCompleted() expect(result) == [ 1, 2 ] } it("should send nothing when errors") { var result: [Int] = [] var errored = false lastThree.start { event in switch event { case let .Next(value): result.append(value) case .Failed(_): errored = true default: break } } observer.sendNext(1) observer.sendNext(2) observer.sendNext(3) expect(errored) == false observer.sendFailed(TestError.Default) expect(errored) == true expect(result).to(beEmpty()) } } describe("timeoutWithError") { var testScheduler: TestScheduler! var producer: SignalProducer! var observer: Signal.Observer! beforeEach { testScheduler = TestScheduler() let (baseProducer, incomingObserver) = SignalProducer.buffer(1) producer = baseProducer.timeoutWithError(TestError.Default, afterInterval: 2, onScheduler: testScheduler) observer = incomingObserver } it("should complete if within the interval") { var completed = false var errored = false producer.start { event in switch event { case .Completed: completed = true case .Failed(_): errored = true default: break } } testScheduler.scheduleAfter(1) { observer.sendCompleted() } expect(completed) == false expect(errored) == false testScheduler.run() expect(completed) == true expect(errored) == false } it("should error if not completed before the interval has elapsed") { var completed = false var errored = false producer.start { event in switch event { case .Completed: completed = true case .Failed(_): errored = true default: break } } testScheduler.scheduleAfter(3) { observer.sendCompleted() } expect(completed) == false expect(errored) == false testScheduler.run() expect(completed) == false expect(errored) == true } } describe("attempt") { it("should forward original values upon success") { let (baseProducer, observer) = SignalProducer.buffer(1) let producer = baseProducer.attempt { _ in return .Success() } var current: Int? producer.startWithNext { value in current = value } for value in 1...5 { observer.sendNext(value) expect(current) == value } } it("should error if an attempt fails") { let (baseProducer, observer) = SignalProducer.buffer(1) let producer = baseProducer.attempt { _ in return .Failure(.Default) } var error: TestError? producer.startWithFailed { err in error = err } observer.sendNext(42) expect(error) == TestError.Default } } describe("attemptMap") { it("should forward mapped values upon success") { let (baseProducer, observer) = SignalProducer.buffer(1) let producer = baseProducer.attemptMap { num -> Result in return .Success(num % 2 == 0) } var even: Bool? producer.startWithNext { value in even = value } observer.sendNext(1) expect(even) == false observer.sendNext(2) expect(even) == true } it("should error if a mapping fails") { let (baseProducer, observer) = SignalProducer.buffer(1) let producer = baseProducer.attemptMap { _ -> Result in return .Failure(.Default) } var error: TestError? producer.startWithFailed { err in error = err } observer.sendNext(42) expect(error) == TestError.Default } } describe("combinePrevious") { var observer: Signal.Observer! let initialValue: Int = 0 var latestValues: (Int, Int)? beforeEach { latestValues = nil let (signal, baseObserver) = SignalProducer.buffer(1) observer = baseObserver signal.combinePrevious(initialValue).startWithNext { latestValues = $0 } } it("should forward the latest value with previous value") { expect(latestValues).to(beNil()) observer.sendNext(1) expect(latestValues?.0) == initialValue expect(latestValues?.1) == 1 observer.sendNext(2) expect(latestValues?.0) == 1 expect(latestValues?.1) == 2 } } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Swift/SignalProducerNimbleMatchers.swift ================================================ // // SignalProducerNimbleMatchers.swift // ReactiveCocoa // // Created by Javier Soto on 1/25/15. // Copyright (c) 2015 GitHub. All rights reserved. // import Foundation import ReactiveCocoa import Nimble public func sendValue(value: T?, sendError: E?, complete: Bool) -> NonNilMatcherFunc> { return sendValues(value.map { [$0] } ?? [], sendError: sendError, complete: complete) } public func sendValues(values: [T], sendError maybeSendError: E?, complete: Bool) -> NonNilMatcherFunc> { return NonNilMatcherFunc { actualExpression, failureMessage in precondition(maybeSendError == nil || !complete, "Signals can't both send an error and complete") failureMessage.postfixMessage = "Send values \(values). Send error \(maybeSendError). Complete: \(complete)" let maybeProducer = try actualExpression.evaluate() if let signalProducer = maybeProducer { var sentValues: [T] = [] var sentError: E? var signalCompleted = false signalProducer.start { event in switch event { case let .Next(value): sentValues.append(value) case .Completed: signalCompleted = true case let .Failed(error): sentError = error default: break } } if sentValues != values { return false } if sentError != maybeSendError { return false } return signalCompleted == complete } else { return false } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Swift/SignalProducerSpec.swift ================================================ // // SignalProducerSpec.swift // ReactiveCocoa // // Created by Justin Spahr-Summers on 2015-01-23. // Copyright (c) 2015 GitHub. All rights reserved. // import Foundation import Result import Nimble import Quick import ReactiveCocoa class SignalProducerSpec: QuickSpec { override func spec() { describe("init") { it("should run the handler once per start()") { var handlerCalledTimes = 0 let signalProducer = SignalProducer() { observer, disposable in handlerCalledTimes++ return } signalProducer.start() signalProducer.start() expect(handlerCalledTimes) == 2 } it("should release signal observers when given disposable is disposed") { var disposable: Disposable! let producer = SignalProducer { observer, innerDisposable in disposable = innerDisposable innerDisposable.addDisposable { // This is necessary to keep the observer long enough to // even test the memory management. observer.sendNext(0) } } weak var objectRetainedByObserver: NSObject? producer.startWithSignal { signal, _ in let object = NSObject() objectRetainedByObserver = object signal.observeNext { _ in object } } expect(objectRetainedByObserver).toNot(beNil()) disposable.dispose() expect(objectRetainedByObserver).to(beNil()) } it("should dispose of added disposables upon completion") { let addedDisposable = SimpleDisposable() var observer: Signal<(), NoError>.Observer! let producer = SignalProducer<(), NoError>() { incomingObserver, disposable in disposable.addDisposable(addedDisposable) observer = incomingObserver } producer.start() expect(addedDisposable.disposed) == false observer.sendCompleted() expect(addedDisposable.disposed) == true } it("should dispose of added disposables upon error") { let addedDisposable = SimpleDisposable() var observer: Signal<(), TestError>.Observer! let producer = SignalProducer<(), TestError>() { incomingObserver, disposable in disposable.addDisposable(addedDisposable) observer = incomingObserver } producer.start() expect(addedDisposable.disposed) == false observer.sendFailed(.Default) expect(addedDisposable.disposed) == true } it("should dispose of added disposables upon interruption") { let addedDisposable = SimpleDisposable() var observer: Signal<(), NoError>.Observer! let producer = SignalProducer<(), NoError>() { incomingObserver, disposable in disposable.addDisposable(addedDisposable) observer = incomingObserver } producer.start() expect(addedDisposable.disposed) == false observer.sendInterrupted() expect(addedDisposable.disposed) == true } it("should dispose of added disposables upon start() disposal") { let addedDisposable = SimpleDisposable() let producer = SignalProducer<(), TestError>() { _, disposable in disposable.addDisposable(addedDisposable) return } let startDisposable = producer.start() expect(addedDisposable.disposed) == false startDisposable.dispose() expect(addedDisposable.disposed) == true } } describe("init(signal:)") { var signal: Signal! var observer: Signal.Observer! beforeEach { // Cannot directly assign due to compiler crash on Xcode 7.0.1 let (signalTemp, observerTemp) = Signal.pipe() signal = signalTemp observer = observerTemp } it("should emit values then complete") { let producer = SignalProducer(signal: signal) var values: [Int] = [] var error: TestError? var completed = false producer.start { event in switch event { case let .Next(value): values.append(value) case let .Failed(err): error = err case .Completed: completed = true default: break } } expect(values) == [] expect(error).to(beNil()) expect(completed) == false observer.sendNext(1) expect(values) == [ 1 ] observer.sendNext(2) observer.sendNext(3) expect(values) == [ 1, 2, 3 ] observer.sendCompleted() expect(completed) == true } it("should emit error") { let producer = SignalProducer(signal: signal) var error: TestError? let sentError = TestError.Default producer.start { event in switch event { case let .Failed(err): error = err default: break } } expect(error).to(beNil()) observer.sendFailed(sentError) expect(error) == sentError } } describe("init(value:)") { it("should immediately send the value then complete") { let producerValue = "StringValue" let signalProducer = SignalProducer(value: producerValue) expect(signalProducer).to(sendValue(producerValue, sendError: nil, complete: true)) } } describe("init(error:)") { it("should immediately send the error") { let producerError = NSError(domain: "com.reactivecocoa.errordomain", code: 4815, userInfo: nil) let signalProducer = SignalProducer(error: producerError) expect(signalProducer).to(sendValue(nil, sendError: producerError, complete: false)) } } describe("init(result:)") { it("should immediately send the value then complete") { let producerValue = "StringValue" let producerResult = .Success(producerValue) as Result let signalProducer = SignalProducer(result: producerResult) expect(signalProducer).to(sendValue(producerValue, sendError: nil, complete: true)) } it("should immediately send the error") { let producerError = NSError(domain: "com.reactivecocoa.errordomain", code: 4815, userInfo: nil) let producerResult = .Failure(producerError) as Result let signalProducer = SignalProducer(result: producerResult) expect(signalProducer).to(sendValue(nil, sendError: producerError, complete: false)) } } describe("init(values:)") { it("should immediately send the sequence of values") { let sequenceValues = [1, 2, 3] let signalProducer = SignalProducer(values: sequenceValues) expect(signalProducer).to(sendValues(sequenceValues, sendError: nil, complete: true)) } } describe("SignalProducer.empty") { it("should immediately complete") { let signalProducer = SignalProducer.empty expect(signalProducer).to(sendValue(nil, sendError: nil, complete: true)) } } describe("SignalProducer.never") { it("should not send any events") { let signalProducer = SignalProducer.never expect(signalProducer).to(sendValue(nil, sendError: nil, complete: false)) } } describe("SignalProducer.buffer") { it("should replay buffered events when started, then forward events as added") { let (producer, observer) = SignalProducer.buffer(Int.max) observer.sendNext(1) observer.sendNext(2) observer.sendNext(3) var values: [Int] = [] var completed = false producer.start { event in switch event { case let .Next(value): values.append(value) case .Completed: completed = true default: break } } expect(values) == [1, 2, 3] expect(completed) == false observer.sendNext(4) observer.sendNext(5) expect(values) == [1, 2, 3, 4, 5] expect(completed) == false observer.sendCompleted() expect(values) == [1, 2, 3, 4, 5] expect(completed) == true } it("should drop earliest events to maintain the capacity") { let (producer, observer) = SignalProducer.buffer(1) observer.sendNext(1) observer.sendNext(2) var values: [Int] = [] var error: TestError? producer.start { event in switch event { case let .Next(value): values.append(value) case let .Failed(err): error = err default: break } } expect(values) == [2] expect(error).to(beNil()) observer.sendNext(3) observer.sendNext(4) expect(values) == [2, 3, 4] expect(error).to(beNil()) observer.sendFailed(.Default) expect(values) == [2, 3, 4] expect(error) == TestError.Default } it("should always replay termination event") { let (producer, observer) = SignalProducer.buffer(0) var completed = false observer.sendCompleted() producer.startWithCompleted { completed = true } expect(completed) == true } it("should replay values after being terminated") { let (producer, observer) = SignalProducer.buffer(1) var value: Int? var completed = false observer.sendNext(123) observer.sendCompleted() producer.start { event in switch event { case let .Next(val): value = val case .Completed: completed = true default: break } } expect(value) == 123 expect(completed) == true } it("should not deadlock when started while sending") { let (producer, observer) = SignalProducer.buffer(Int.max) observer.sendNext(1) observer.sendNext(2) observer.sendNext(3) var values: [Int] = [] producer.startWithCompleted { values = [] producer.startWithNext { value in values.append(value) } } observer.sendCompleted() expect(values) == [ 1, 2, 3 ] } it("should buffer values before sending recursively to new observers") { let (producer, observer) = SignalProducer.buffer(Int.max) var values: [Int] = [] var lastBufferedValues: [Int] = [] producer.startWithNext { newValue in values.append(newValue) var bufferedValues: [Int] = [] producer.startWithNext { bufferedValue in bufferedValues.append(bufferedValue) } expect(bufferedValues) == values lastBufferedValues = bufferedValues } observer.sendNext(1) expect(values) == [ 1 ] expect(lastBufferedValues) == values observer.sendNext(2) expect(values) == [ 1, 2 ] expect(lastBufferedValues) == values observer.sendNext(3) expect(values) == [ 1, 2, 3 ] expect(lastBufferedValues) == values } } describe("trailing closure") { it("receives next values") { var values = [Int]() let (producer, observer) = SignalProducer.buffer(1) observer.sendNext(1) producer.startWithNext { next in values.append(next) } expect(values) == [1] } } describe("SignalProducer.attempt") { it("should run the operation once per start()") { var operationRunTimes = 0 let operation: () -> Result = { operationRunTimes++ return .Success("OperationValue") } SignalProducer.attempt(operation).start() SignalProducer.attempt(operation).start() expect(operationRunTimes) == 2 } it("should send the value then complete") { let operationReturnValue = "OperationValue" let operation: () -> Result = { return .Success(operationReturnValue) } let signalProducer = SignalProducer.attempt(operation) expect(signalProducer).to(sendValue(operationReturnValue, sendError: nil, complete: true)) } it("should send the error") { let operationError = NSError(domain: "com.reactivecocoa.errordomain", code: 4815, userInfo: nil) let operation: () -> Result = { return .Failure(operationError) } let signalProducer = SignalProducer.attempt(operation) expect(signalProducer).to(sendValue(nil, sendError: operationError, complete: false)) } } describe("startWithSignal") { it("should invoke the closure before any effects or events") { var started = false var value: Int? SignalProducer(value: 42) .on(started: { started = true }, next: { value = $0 }) .startWithSignal { _ in expect(started) == false expect(value).to(beNil()) } expect(started) == true expect(value) == 42 } it("should dispose of added disposables if disposed") { let addedDisposable = SimpleDisposable() var disposable: Disposable! let producer = SignalProducer() { _, disposable in disposable.addDisposable(addedDisposable) return } producer.startWithSignal { _, innerDisposable in disposable = innerDisposable } expect(addedDisposable.disposed) == false disposable.dispose() expect(addedDisposable.disposed) == true } it("should send interrupted if disposed") { var interrupted = false var disposable: Disposable! SignalProducer(value: 42) .startOn(TestScheduler()) .startWithSignal { signal, innerDisposable in signal.observeInterrupted { interrupted = true } disposable = innerDisposable } expect(interrupted) == false disposable.dispose() expect(interrupted) == true } it("should release signal observers if disposed") { weak var objectRetainedByObserver: NSObject? var disposable: Disposable! let producer = SignalProducer.never producer.startWithSignal { signal, innerDisposable in let object = NSObject() objectRetainedByObserver = object signal.observeNext { _ in object.description } disposable = innerDisposable } expect(objectRetainedByObserver).toNot(beNil()) disposable.dispose() expect(objectRetainedByObserver).to(beNil()) } it("should not trigger effects if disposed before closure return") { var started = false var value: Int? SignalProducer(value: 42) .on(started: { started = true }, next: { value = $0 }) .startWithSignal { _, disposable in expect(started) == false expect(value).to(beNil()) disposable.dispose() } expect(started) == false expect(value).to(beNil()) } it("should send interrupted if disposed before closure return") { var interrupted = false SignalProducer(value: 42) .startWithSignal { signal, disposable in expect(interrupted) == false signal.observeInterrupted { interrupted = true } disposable.dispose() } expect(interrupted) == true } it("should dispose of added disposables upon completion") { let addedDisposable = SimpleDisposable() var observer: Signal.Observer! let producer = SignalProducer() { incomingObserver, disposable in disposable.addDisposable(addedDisposable) observer = incomingObserver } producer.startWithSignal { _ in } expect(addedDisposable.disposed) == false observer.sendCompleted() expect(addedDisposable.disposed) == true } it("should dispose of added disposables upon error") { let addedDisposable = SimpleDisposable() var observer: Signal.Observer! let producer = SignalProducer() { incomingObserver, disposable in disposable.addDisposable(addedDisposable) observer = incomingObserver } producer.startWithSignal { _ in } expect(addedDisposable.disposed) == false observer.sendFailed(.Default) expect(addedDisposable.disposed) == true } } describe("start") { it("should immediately begin sending events") { let producer = SignalProducer(values: [1, 2]) var values: [Int] = [] var completed = false producer.start { event in switch event { case let .Next(value): values.append(value) case .Completed: completed = true default: break } } expect(values) == [1, 2] expect(completed) == true } it("should send interrupted if disposed") { let producer = SignalProducer<(), NoError>.never var interrupted = false let disposable = producer.startWithInterrupted { interrupted = true } expect(interrupted) == false disposable.dispose() expect(interrupted) == true } it("should release observer when disposed") { weak var objectRetainedByObserver: NSObject? var disposable: Disposable! let test: () -> () = { let producer = SignalProducer.never let object = NSObject() objectRetainedByObserver = object disposable = producer.startWithNext { _ in object } } test() expect(objectRetainedByObserver).toNot(beNil()) disposable.dispose() expect(objectRetainedByObserver).to(beNil()) } describe("trailing closure") { it("receives next values") { var values = [Int]() let (producer, observer) = SignalProducer.buffer(1) producer.startWithNext { next in values.append(next) } observer.sendNext(1) observer.sendNext(2) observer.sendNext(3) observer.sendCompleted() expect(values) == [1, 2, 3] } } } describe("lift") { describe("over unary operators") { it("should invoke transformation once per started signal") { let baseProducer = SignalProducer(values: [1, 2]) var counter = 0 let transform = { (signal: Signal) -> Signal in counter += 1 return signal } let producer = baseProducer.lift(transform) expect(counter) == 0 producer.start() expect(counter) == 1 producer.start() expect(counter) == 2 } it("should not miss any events") { let baseProducer = SignalProducer(values: [1, 2, 3, 4]) let producer = baseProducer.lift { signal in return signal.map { $0 * $0 } } let result = producer.collect().single() expect(result?.value) == [1, 4, 9, 16] } } describe("over binary operators") { it("should invoke transformation once per started signal") { let baseProducer = SignalProducer(values: [1, 2]) let otherProducer = SignalProducer(values: [3, 4]) var counter = 0 let transform = { (signal: Signal) -> Signal -> Signal<(Int, Int), NoError> in return { otherSignal in counter += 1 return zip(signal, otherSignal) } } let producer = baseProducer.lift(transform)(otherProducer) expect(counter) == 0 producer.start() expect(counter) == 1 producer.start() expect(counter) == 2 } it("should not miss any events") { let baseProducer = SignalProducer(values: [1, 2, 3]) let otherProducer = SignalProducer(values: [4, 5, 6]) let transform = { (signal: Signal) -> Signal -> Signal in return { otherSignal in return zip(signal, otherSignal).map { first, second in first + second } } } let producer = baseProducer.lift(transform)(otherProducer) let result = producer.collect().single() expect(result?.value) == [5, 7, 9] } } describe("over binary operators with signal") { it("should invoke transformation once per started signal") { let baseProducer = SignalProducer(values: [1, 2]) let (otherSignal, otherSignalObserver) = Signal.pipe() var counter = 0 let transform = { (signal: Signal) -> Signal -> Signal<(Int, Int), NoError> in return { otherSignal in counter += 1 return zip(signal, otherSignal) } } let producer = baseProducer.lift(transform)(otherSignal) expect(counter) == 0 producer.start() otherSignalObserver.sendNext(1) expect(counter) == 1 producer.start() otherSignalObserver.sendNext(2) expect(counter) == 2 } it("should not miss any events") { let baseProducer = SignalProducer(values: [ 1, 2, 3 ]) let (otherSignal, otherSignalObserver) = Signal.pipe() let transform = { (signal: Signal) -> Signal -> Signal in return { otherSignal in return zip(signal, otherSignal).map(+) } } let producer = baseProducer.lift(transform)(otherSignal) var result: [Int] = [] var completed: Bool = false producer.start { event in switch event { case .Next(let value): result.append(value) case .Completed: completed = true default: break } } otherSignalObserver.sendNext(4) expect(result) == [ 5 ] otherSignalObserver.sendNext(5) expect(result) == [ 5, 7 ] otherSignalObserver.sendNext(6) expect(result) == [ 5, 7, 9 ] expect(completed) == true } } } describe("sequence operators") { var producerA: SignalProducer! var producerB: SignalProducer! beforeEach { producerA = SignalProducer(values: [ 1, 2 ]) producerB = SignalProducer(values: [ 3, 4 ]) } it("should combine the events to one array") { let producer = combineLatest([producerA, producerB]) let result = producer.collect().single() expect(result?.value) == [[1, 4], [2, 4]] } it("should zip the events to one array") { let producer = zip([producerA, producerB]) let result = producer.collect().single() expect(result?.value) == [[1, 3], [2, 4]] } } describe("timer") { it("should send the current date at the given interval") { let scheduler = TestScheduler() let producer = timer(1, onScheduler: scheduler, withLeeway: 0) var dates: [NSDate] = [] producer.startWithNext { dates.append($0) } scheduler.advanceByInterval(0.9) expect(dates) == [] scheduler.advanceByInterval(1) let firstTick = scheduler.currentDate expect(dates) == [firstTick] scheduler.advance() expect(dates) == [firstTick] scheduler.advanceByInterval(0.2) let secondTick = scheduler.currentDate expect(dates) == [firstTick, secondTick] scheduler.advanceByInterval(1) expect(dates) == [firstTick, secondTick, scheduler.currentDate] } it("should release the signal when disposed") { let scheduler = TestScheduler() let producer = timer(1, onScheduler: scheduler, withLeeway: 0) weak var weakSignal: Signal? producer.startWithSignal { signal, disposable in weakSignal = signal scheduler.schedule { disposable.dispose() } } expect(weakSignal).toNot(beNil()) scheduler.run() expect(weakSignal).to(beNil()) } } describe("on") { it("should attach event handlers to each started signal") { let (baseProducer, observer) = SignalProducer.buffer(1) var started = 0 var event = 0 var next = 0 var completed = 0 var terminated = 0 let producer = baseProducer .on(started: { () -> () in started += 1 }, event: { (e: Event) -> () in event += 1 }, next: { (n: Int) -> () in next += 1 }, completed: { () -> () in completed += 1 }, terminated: { () -> () in terminated += 1 }) producer.start() expect(started) == 1 producer.start() expect(started) == 2 observer.sendNext(1) expect(event) == 2 expect(next) == 2 observer.sendCompleted() expect(event) == 4 expect(completed) == 2 expect(terminated) == 2 } it("should attach event handlers for disposal") { let (baseProducer, _) = SignalProducer.buffer(1) var disposed: Bool = false let producer = baseProducer .on(disposed: { disposed = true }) let disposable = producer.start() expect(disposed) == false disposable.dispose() expect(disposed) == true } } describe("startOn") { it("should invoke effects on the given scheduler") { let scheduler = TestScheduler() var invoked = false let producer = SignalProducer() { _ in invoked = true } producer.startOn(scheduler).start() expect(invoked) == false scheduler.advance() expect(invoked) == true } it("should forward events on their original scheduler") { let startScheduler = TestScheduler() let testScheduler = TestScheduler() let producer = timer(2, onScheduler: testScheduler, withLeeway: 0) var next: NSDate? producer.startOn(startScheduler).startWithNext { next = $0 } startScheduler.advanceByInterval(2) expect(next).to(beNil()) testScheduler.advanceByInterval(1) expect(next).to(beNil()) testScheduler.advanceByInterval(1) expect(next) == testScheduler.currentDate } } describe("flatMapError") { it("should invoke the handler and start new producer for an error") { let (baseProducer, baseObserver) = SignalProducer.buffer(1) baseObserver.sendNext(1) baseObserver.sendFailed(.Default) var values: [Int] = [] var completed = false baseProducer .flatMapError { (error: TestError) -> SignalProducer in expect(error) == TestError.Default expect(values) == [1] let (innerProducer, innerObserver) = SignalProducer.buffer(1) innerObserver.sendNext(2) innerObserver.sendCompleted() return innerProducer } .start { event in switch event { case let .Next(value): values.append(value) case .Completed: completed = true default: break } } expect(values) == [1, 2] expect(completed) == true } it("should interrupt the replaced producer on disposal") { let (baseProducer, baseObserver) = SignalProducer.buffer(1) var (disposed, interrupted) = (false, false) let disposable = baseProducer .flatMapError { (error: TestError) -> SignalProducer in return SignalProducer { _, disposable in disposable += ActionDisposable { disposed = true } } } .startWithInterrupted { interrupted = true } baseObserver.sendFailed(.Default) disposable.dispose() expect(interrupted) == true expect(disposed) == true } } describe("flatten") { describe("FlattenStrategy.Concat") { describe("sequencing") { var completePrevious: (Void -> Void)! var sendSubsequent: (Void -> Void)! var completeOuter: (Void -> Void)! var subsequentStarted = false beforeEach { let (outerProducer, outerObserver) = SignalProducer, NoError>.buffer(1) let (previousProducer, previousObserver) = SignalProducer.buffer(1) subsequentStarted = false let subsequentProducer = SignalProducer { _ in subsequentStarted = true } completePrevious = { previousObserver.sendCompleted() } sendSubsequent = { outerObserver.sendNext(subsequentProducer) } completeOuter = { outerObserver.sendCompleted() } outerProducer.flatten(.Concat).start() outerObserver.sendNext(previousProducer) } it("should immediately start subsequent inner producer if previous inner producer has already completed") { completePrevious() sendSubsequent() expect(subsequentStarted) == true } context("with queued producers") { beforeEach { // Place the subsequent producer into `concat`'s queue. sendSubsequent() expect(subsequentStarted) == false } it("should start subsequent inner producer upon completion of previous inner producer") { completePrevious() expect(subsequentStarted) == true } it("should start subsequent inner producer upon completion of previous inner producer and completion of outer producer") { completeOuter() completePrevious() expect(subsequentStarted) == true } } } it("should forward an error from an inner producer") { let errorProducer = SignalProducer(error: TestError.Default) let outerProducer = SignalProducer, TestError>(value: errorProducer) var error: TestError? (outerProducer.flatten(.Concat)).startWithFailed { e in error = e } expect(error) == TestError.Default } it("should forward an error from the outer producer") { let (outerProducer, outerObserver) = SignalProducer, TestError>.buffer(1) var error: TestError? outerProducer.flatten(.Concat).startWithFailed { e in error = e } outerObserver.sendFailed(TestError.Default) expect(error) == TestError.Default } describe("completion") { var completeOuter: (Void -> Void)! var completeInner: (Void -> Void)! var completed = false beforeEach { let (outerProducer, outerObserver) = SignalProducer, NoError>.buffer(1) let (innerProducer, innerObserver) = SignalProducer.buffer(1) completeOuter = { outerObserver.sendCompleted() } completeInner = { innerObserver.sendCompleted() } completed = false outerProducer.flatten(.Concat).startWithCompleted { completed = true } outerObserver.sendNext(innerProducer) } it("should complete when inner producers complete, then outer producer completes") { completeInner() expect(completed) == false completeOuter() expect(completed) == true } it("should complete when outer producers completes, then inner producers complete") { completeOuter() expect(completed) == false completeInner() expect(completed) == true } } } describe("FlattenStrategy.Merge") { describe("behavior") { var completeA: (Void -> Void)! var sendA: (Void -> Void)! var completeB: (Void -> Void)! var sendB: (Void -> Void)! var outerCompleted = false var recv = [Int]() beforeEach { let (outerProducer, outerObserver) = SignalProducer, NoError>.buffer(Int.max) let (producerA, observerA) = SignalProducer.buffer(Int.max) let (producerB, observerB) = SignalProducer.buffer(Int.max) completeA = { observerA.sendCompleted() } completeB = { observerB.sendCompleted() } var a = 0 sendA = { observerA.sendNext(a++) } var b = 100 sendB = { observerB.sendNext(b++) } outerObserver.sendNext(producerA) outerObserver.sendNext(producerB) outerProducer.flatten(.Merge).start { event in switch event { case let .Next(i): recv.append(i) case .Completed: outerCompleted = true default: break } } outerObserver.sendCompleted() } it("should forward values from any inner signals") { sendA() sendA() sendB() sendA() sendB() expect(recv) == [0, 1, 100, 2, 101] } it("should complete when all signals have completed") { completeA() expect(outerCompleted) == false completeB() expect(outerCompleted) == true } } describe("error handling") { it("should forward an error from an inner signal") { let errorProducer = SignalProducer(error: TestError.Default) let outerProducer = SignalProducer, TestError>(value: errorProducer) var error: TestError? outerProducer.flatten(.Merge).startWithFailed { e in error = e } expect(error) == TestError.Default } it("should forward an error from the outer signal") { let (outerProducer, outerObserver) = SignalProducer, TestError>.buffer(1) var error: TestError? outerProducer.flatten(.Merge).startWithFailed { e in error = e } outerObserver.sendFailed(TestError.Default) expect(error) == TestError.Default } } } describe("FlattenStrategy.Latest") { it("should forward values from the latest inner signal") { let (outer, outerObserver) = SignalProducer, TestError>.buffer(1) let (firstInner, firstInnerObserver) = SignalProducer.buffer(1) let (secondInner, secondInnerObserver) = SignalProducer.buffer(1) var receivedValues: [Int] = [] var errored = false var completed = false outer.flatten(.Latest).start { event in switch event { case let .Next(value): receivedValues.append(value) case .Completed: completed = true case .Failed(_): errored = true default: break } } firstInnerObserver.sendNext(1) secondInnerObserver.sendNext(2) outerObserver.sendNext(SignalProducer(value: 0)) outerObserver.sendNext(firstInner) outerObserver.sendNext(secondInner) outerObserver.sendCompleted() expect(receivedValues) == [ 0, 1, 2 ] expect(errored) == false expect(completed) == false firstInnerObserver.sendNext(3) firstInnerObserver.sendCompleted() secondInnerObserver.sendNext(4) secondInnerObserver.sendCompleted() expect(receivedValues) == [ 0, 1, 2, 4 ] expect(errored) == false expect(completed) == true } it("should forward an error from an inner signal") { let inner = SignalProducer(error: .Default) let outer = SignalProducer, TestError>(value: inner) let result = outer.flatten(.Latest).first() expect(result?.error) == TestError.Default } it("should forward an error from the outer signal") { let outer = SignalProducer, TestError>(error: .Default) let result = outer.flatten(.Latest).first() expect(result?.error) == TestError.Default } it("should complete when the original and latest signals have completed") { let inner = SignalProducer.empty let outer = SignalProducer, TestError>(value: inner) var completed = false outer.flatten(.Latest).startWithCompleted { completed = true } expect(completed) == true } it("should complete when the outer signal completes before sending any signals") { let outer = SignalProducer, TestError>.empty var completed = false outer.flatten(.Latest).startWithCompleted { completed = true } expect(completed) == true } it("should not deadlock") { let producer = SignalProducer(value: 1) .flatMap(.Latest) { _ in SignalProducer(value: 10) } let result = producer.take(1).last() expect(result?.value) == 10 } } describe("interruption") { var innerObserver: Signal<(), NoError>.Observer! var outerObserver: Signal, NoError>.Observer! var execute: (FlattenStrategy -> Void)! var interrupted = false var completed = false beforeEach { let (innerProducer, incomingInnerObserver) = SignalProducer<(), NoError>.buffer(1) let (outerProducer, incomingOuterObserver) = SignalProducer, NoError>.buffer(1) innerObserver = incomingInnerObserver outerObserver = incomingOuterObserver execute = { strategy in interrupted = false completed = false outerProducer .flatten(strategy) .start { event in switch event { case .Interrupted: interrupted = true case .Completed: completed = true default: break } } } incomingOuterObserver.sendNext(innerProducer) } describe("Concat") { it("should drop interrupted from an inner producer") { execute(.Concat) innerObserver.sendInterrupted() expect(interrupted) == false expect(completed) == false outerObserver.sendCompleted() expect(completed) == true } it("should forward interrupted from the outer producer") { execute(.Concat) outerObserver.sendInterrupted() expect(interrupted) == true } } describe("Latest") { it("should drop interrupted from an inner producer") { execute(.Latest) innerObserver.sendInterrupted() expect(interrupted) == false expect(completed) == false outerObserver.sendCompleted() expect(completed) == true } it("should forward interrupted from the outer producer") { execute(.Latest) outerObserver.sendInterrupted() expect(interrupted) == true } } describe("Merge") { it("should drop interrupted from an inner producer") { execute(.Merge) innerObserver.sendInterrupted() expect(interrupted) == false expect(completed) == false outerObserver.sendCompleted() expect(completed) == true } it("should forward interrupted from the outer producer") { execute(.Merge) outerObserver.sendInterrupted() expect(interrupted) == true } } } describe("disposal") { var completeOuter: (Void -> Void)! var disposeOuter: (Void -> Void)! var execute: (FlattenStrategy -> Void)! var innerDisposable = SimpleDisposable() var interrupted = false beforeEach { execute = { strategy in let (outerProducer, outerObserver) = SignalProducer, NoError>.buffer(1) innerDisposable = SimpleDisposable() let innerProducer = SignalProducer { $1.addDisposable(innerDisposable) } interrupted = false let outerDisposable = outerProducer.flatten(strategy).startWithInterrupted { interrupted = true } completeOuter = outerObserver.sendCompleted disposeOuter = outerDisposable.dispose outerObserver.sendNext(innerProducer) } } describe("Concat") { it("should cancel inner work when disposed before the outer producer completes") { execute(.Concat) expect(innerDisposable.disposed) == false expect(interrupted) == false disposeOuter() expect(innerDisposable.disposed) == true expect(interrupted) == true } it("should cancel inner work when disposed after the outer producer completes") { execute(.Concat) completeOuter() expect(innerDisposable.disposed) == false expect(interrupted) == false disposeOuter() expect(innerDisposable.disposed) == true expect(interrupted) == true } } describe("Latest") { it("should cancel inner work when disposed before the outer producer completes") { execute(.Latest) expect(innerDisposable.disposed) == false expect(interrupted) == false disposeOuter() expect(innerDisposable.disposed) == true expect(interrupted) == true } it("should cancel inner work when disposed after the outer producer completes") { execute(.Latest) completeOuter() expect(innerDisposable.disposed) == false expect(interrupted) == false disposeOuter() expect(innerDisposable.disposed) == true expect(interrupted) == true } } describe("Merge") { it("should cancel inner work when disposed before the outer producer completes") { execute(.Merge) expect(innerDisposable.disposed) == false expect(interrupted) == false disposeOuter() expect(innerDisposable.disposed) == true expect(interrupted) == true } it("should cancel inner work when disposed after the outer producer completes") { execute(.Merge) completeOuter() expect(innerDisposable.disposed) == false expect(interrupted) == false disposeOuter() expect(innerDisposable.disposed) == true expect(interrupted) == true } } } } describe("times") { it("should start a signal N times upon completion") { let original = SignalProducer(values: [ 1, 2, 3 ]) let producer = original.times(3) let result = producer.collect().single() expect(result?.value) == [ 1, 2, 3, 1, 2, 3, 1, 2, 3 ] } it("should produce an equivalent signal producer if count is 1") { let original = SignalProducer(value: 1) let producer = original.times(1) let result = producer.collect().single() expect(result?.value) == [ 1 ] } it("should produce an empty signal if count is 0") { let original = SignalProducer(value: 1) let producer = original.times(0) let result = producer.first() expect(result).to(beNil()) } it("should not repeat upon error") { let results: [Result] = [ .Success(1), .Success(2), .Failure(.Default) ] let original = SignalProducer.attemptWithResults(results) let producer = original.times(3) let events = producer .materialize() .collect() .single() let result = events?.value let expectedEvents: [Event] = [ .Next(1), .Next(2), .Failed(.Default) ] // TODO: if let result = result where result.count == expectedEvents.count if result?.count != expectedEvents.count { fail("Invalid result: \(result)") } else { // Can't test for equality because Array is not Equatable, // and neither is Event. expect(result![0] == expectedEvents[0]) == true expect(result![1] == expectedEvents[1]) == true expect(result![2] == expectedEvents[2]) == true } } it("should evaluate lazily") { let original = SignalProducer(value: 1) let producer = original.times(Int.max) let result = producer.take(1).single() expect(result?.value) == 1 } } describe("retry") { it("should start a signal N times upon error") { let results: [Result] = [ .Failure(.Error1), .Failure(.Error2), .Success(1) ] let original = SignalProducer.attemptWithResults(results) let producer = original.retry(2) let result = producer.single() expect(result?.value) == 1 } it("should forward errors that occur after all retries") { let results: [Result] = [ .Failure(.Default), .Failure(.Error1), .Failure(.Error2), ] let original = SignalProducer.attemptWithResults(results) let producer = original.retry(2) let result = producer.single() expect(result?.error) == TestError.Error2 } it("should not retry upon completion") { let results: [Result] = [ .Success(1), .Success(2), .Success(3) ] let original = SignalProducer.attemptWithResults(results) let producer = original.retry(2) let result = producer.single() expect(result?.value) == 1 } } describe("then") { it("should start the subsequent producer after the completion of the original") { let (original, observer) = SignalProducer.buffer(1) var subsequentStarted = false let subsequent = SignalProducer { observer, _ in subsequentStarted = true } let producer = original.then(subsequent) producer.start() expect(subsequentStarted) == false observer.sendCompleted() expect(subsequentStarted) == true } it("should forward errors from the original producer") { let original = SignalProducer(error: .Default) let subsequent = SignalProducer.empty let result = original.then(subsequent).first() expect(result?.error) == TestError.Default } it("should forward errors from the subsequent producer") { let original = SignalProducer.empty let subsequent = SignalProducer(error: .Default) let result = original.then(subsequent).first() expect(result?.error) == TestError.Default } it("should complete when both inputs have completed") { let (original, originalObserver) = SignalProducer.buffer(1) let (subsequent, subsequentObserver) = SignalProducer.buffer(1) let producer = original.then(subsequent) var completed = false producer.startWithCompleted { completed = true } originalObserver.sendCompleted() expect(completed) == false subsequentObserver.sendCompleted() expect(completed) == true } } describe("first") { it("should start a signal then block on the first value") { let (producer, observer) = SignalProducer.buffer(1) var result: Result? let group = dispatch_group_create() dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { result = producer.first() } expect(result).to(beNil()) observer.sendNext(1) dispatch_group_wait(group, DISPATCH_TIME_FOREVER) expect(result?.value) == 1 } it("should return a nil result if no values are sent before completion") { let result = SignalProducer.empty.first() expect(result).to(beNil()) } it("should return the first value if more than one value is sent") { let result = SignalProducer(values: [ 1, 2 ]).first() expect(result?.value) == 1 } it("should return an error if one occurs before the first value") { let result = SignalProducer(error: .Default).first() expect(result?.error) == TestError.Default } } describe("single") { it("should start a signal then block until completion") { let (producer, observer) = SignalProducer.buffer(1) var result: Result? let group = dispatch_group_create() dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { result = producer.single() } expect(result).to(beNil()) observer.sendNext(1) expect(result).to(beNil()) observer.sendCompleted() dispatch_group_wait(group, DISPATCH_TIME_FOREVER) expect(result?.value) == 1 } it("should return a nil result if no values are sent before completion") { let result = SignalProducer.empty.single() expect(result).to(beNil()) } it("should return a nil result if more than one value is sent before completion") { let result = SignalProducer(values: [ 1, 2 ]).single() expect(result).to(beNil()) } it("should return an error if one occurs") { let result = SignalProducer(error: .Default).single() expect(result?.error) == TestError.Default } } describe("last") { it("should start a signal then block until completion") { let (producer, observer) = SignalProducer.buffer(1) var result: Result? let group = dispatch_group_create() dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { result = producer.last() } expect(result).to(beNil()) observer.sendNext(1) observer.sendNext(2) expect(result).to(beNil()) observer.sendCompleted() dispatch_group_wait(group, DISPATCH_TIME_FOREVER) expect(result?.value) == 2 } it("should return a nil result if no values are sent before completion") { let result = SignalProducer.empty.last() expect(result).to(beNil()) } it("should return the last value if more than one value is sent") { let result = SignalProducer(values: [ 1, 2 ]).last() expect(result?.value) == 2 } it("should return an error if one occurs") { let result = SignalProducer(error: .Default).last() expect(result?.error) == TestError.Default } } describe("wait") { it("should start a signal then block until completion") { let (producer, observer) = SignalProducer.buffer(1) var result: Result<(), NoError>? let group = dispatch_group_create() dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { result = producer.wait() } expect(result).to(beNil()) observer.sendCompleted() dispatch_group_wait(group, DISPATCH_TIME_FOREVER) expect(result?.value).toNot(beNil()) } it("should return an error if one occurs") { let result = SignalProducer(error: .Default).wait() expect(result.error) == TestError.Default } } describe("observeOn") { it("should immediately cancel upstream producer's work when disposed") { var upstreamDisposable: Disposable! let producer = SignalProducer<(), NoError>{ _, innerDisposable in upstreamDisposable = innerDisposable } var downstreamDisposable: Disposable! producer .observeOn(TestScheduler()) .startWithSignal { signal, innerDisposable in downstreamDisposable = innerDisposable } expect(upstreamDisposable.disposed) == false downstreamDisposable.dispose() expect(upstreamDisposable.disposed) == true } } describe("take") { it("Should not start concat'ed producer if the first one sends a value when using take(1)") { let scheduler: QueueScheduler if #available(OSX 10.10, *) { scheduler = QueueScheduler() } else { scheduler = QueueScheduler(queue: dispatch_get_main_queue()) } // Delaying producer1 from sending a value to test whether producer2 is started in the mean-time. let producer1 = SignalProducer() { handler, _ in handler.sendNext(1) handler.sendCompleted() }.startOn(scheduler) var started = false let producer2 = SignalProducer() { handler, _ in started = true handler.sendNext(2) handler.sendCompleted() } let result = producer1.concat(producer2).take(1).collect().first() expect(result?.value) == [1] expect(started) == false } } describe("replayLazily") { var producer: SignalProducer! var observer: SignalProducer.ProducedSignal.Observer! var replayedProducer: SignalProducer! beforeEach { let (producerTemp, observerTemp) = SignalProducer.buffer(0) producer = producerTemp observer = observerTemp replayedProducer = producer.replayLazily(2) } context("subscribing to underlying producer") { it("emits new values") { var last: Int? replayedProducer.startWithNext { last = $0 } expect(last).to(beNil()) observer.sendNext(1) expect(last) == 1 observer.sendNext(2) expect(last) == 2 } it("emits errors") { var error: TestError? replayedProducer.startWithFailed { error = $0 } expect(error).to(beNil()) observer.sendFailed(.Default) expect(error) == TestError.Default } } context("buffers past values") { it("emits last value upon subscription") { let disposable = replayedProducer .start() observer.sendNext(1) disposable.dispose() var last: Int? replayedProducer .startWithNext { last = $0 } expect(last) == 1 } it("emits previous failure upon subscription") { let disposable = replayedProducer .start() observer.sendFailed(.Default) disposable.dispose() var error: TestError? replayedProducer .startWithFailed { error = $0 } expect(error) == TestError.Default } it("emits last n values upon subscription") { var disposable = replayedProducer .start() observer.sendNext(1) observer.sendNext(2) observer.sendNext(3) observer.sendNext(4) disposable.dispose() var values: [Int] = [] disposable = replayedProducer .startWithNext { values.append($0) } expect(values) == [ 3, 4 ] observer.sendNext(5) expect(values) == [ 3, 4, 5 ] disposable.dispose() values = [] replayedProducer .startWithNext { values.append($0) } expect(values) == [ 4, 5 ] } } context("starting underying producer") { it("starts lazily") { var started = false let producer = SignalProducer(value: 0) .on(started: { started = true }) expect(started) == false let replayedProducer = producer .replayLazily(1) expect(started) == false replayedProducer.start() expect(started) == true } it("shares a single subscription") { var startedTimes = 0 let producer = SignalProducer.never .on(started: { startedTimes++ }) expect(startedTimes) == 0 let replayedProducer = producer .replayLazily(1) expect(startedTimes) == 0 replayedProducer.start() expect(startedTimes) == 1 replayedProducer.start() expect(startedTimes) == 1 } it("does not start multiple times when subscribing multiple times") { var startedTimes = 0 let producer = SignalProducer(value: 0) .on(started: { startedTimes++ }) let replayedProducer = producer .replayLazily(1) expect(startedTimes) == 0 replayedProducer.start().dispose() expect(startedTimes) == 1 replayedProducer.start().dispose() expect(startedTimes) == 1 } it("does not start again if it finished") { var startedTimes = 0 let producer = SignalProducer.empty .on(started: { startedTimes++ }) expect(startedTimes) == 0 let replayedProducer = producer .replayLazily(1) expect(startedTimes) == 0 replayedProducer.start() expect(startedTimes) == 1 replayedProducer.start() expect(startedTimes) == 1 } } context("lifetime") { it("does not dispose underlying subscription if the replayed producer is still in memory") { var disposed = false let producer = SignalProducer.never .on(disposed: { disposed = true }) let replayedProducer = producer .replayLazily(1) expect(disposed) == false let disposable = replayedProducer.start() expect(disposed) == false disposable.dispose() expect(disposed) == false } it("disposes underlying producer when the producer is deallocated") { var disposed = false let producer = SignalProducer.never .on(disposed: { disposed = true }) var replayedProducer = ImplicitlyUnwrappedOptional(producer.replayLazily(1)) expect(disposed) == false let disposable = replayedProducer.start() expect(disposed) == false disposable.dispose() expect(disposed) == false replayedProducer = nil expect(disposed) == true } it("does not leak buffered values") { final class Value { private let deinitBlock: () -> () init(deinitBlock: () -> ()) { self.deinitBlock = deinitBlock } deinit { self.deinitBlock() } } var deinitValues = 0 var producer: SignalProducer! = SignalProducer(value: Value { deinitValues++ }) expect(deinitValues) == 0 var replayedProducer: SignalProducer! = producer .replayLazily(1) let disposable = replayedProducer .start() disposable.dispose() expect(deinitValues) == 0 producer = nil expect(deinitValues) == 0 replayedProducer = nil expect(deinitValues) == 1 } } } } } extension SignalProducer { /// Creates a producer that can be started as many times as elements in `results`. /// Each signal will immediately send either a value or an error. private static func attemptWithResults, C.Index.Distance == Int>(results: C) -> SignalProducer { let resultCount = results.count var operationIndex = 0 precondition(resultCount > 0) let operation: () -> Result = { if operationIndex < resultCount { return results[results.startIndex.advancedBy(operationIndex++)] } else { fail("Operation started too many times") return results[results.startIndex.advancedBy(0)] } } return SignalProducer.attempt(operation) } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Swift/SignalSpec.swift ================================================ // // SignalSpec.swift // ReactiveCocoa // // Created by Justin Spahr-Summers on 2015-01-23. // Copyright (c) 2015 GitHub. All rights reserved. // import Result import Nimble import Quick import ReactiveCocoa class SignalSpec: QuickSpec { override func spec() { describe("init") { var testScheduler: TestScheduler! beforeEach { testScheduler = TestScheduler() } it("should run the generator immediately") { var didRunGenerator = false Signal { observer in didRunGenerator = true return nil } expect(didRunGenerator) == true } it("should forward events to observers") { let numbers = [ 1, 2, 5 ] let signal: Signal = Signal { observer in testScheduler.schedule { for number in numbers { observer.sendNext(number) } observer.sendCompleted() } return nil } var fromSignal: [Int] = [] var completed = false signal.observe { event in switch event { case let .Next(number): fromSignal.append(number) case .Completed: completed = true default: break } } expect(completed) == false expect(fromSignal).to(beEmpty()) testScheduler.run() expect(completed) == true expect(fromSignal) == numbers } it("should dispose of returned disposable upon error") { let disposable = SimpleDisposable() let signal: Signal = Signal { observer in testScheduler.schedule { observer.sendFailed(TestError.Default) } return disposable } var errored = false signal.observeFailed { _ in errored = true } expect(errored) == false expect(disposable.disposed) == false testScheduler.run() expect(errored) == true expect(disposable.disposed) == true } it("should dispose of returned disposable upon completion") { let disposable = SimpleDisposable() let signal: Signal = Signal { observer in testScheduler.schedule { observer.sendCompleted() } return disposable } var completed = false signal.observeCompleted { completed = true } expect(completed) == false expect(disposable.disposed) == false testScheduler.run() expect(completed) == true expect(disposable.disposed) == true } it("should dispose of returned disposable upon interrupted") { let disposable = SimpleDisposable() let signal: Signal = Signal { observer in testScheduler.schedule { observer.sendInterrupted() } return disposable } var interrupted = false signal.observeInterrupted { interrupted = true } expect(interrupted) == false expect(disposable.disposed) == false testScheduler.run() expect(interrupted) == true expect(disposable.disposed) == true } } describe("Signal.empty") { it("should interrupt its observers without emitting any value") { let signal = Signal<(), NoError>.empty var hasUnexpectedEventsEmitted = false var signalInterrupted = false signal.observe { event in switch event { case .Next, .Failed, .Completed: hasUnexpectedEventsEmitted = false case .Interrupted: signalInterrupted = true } } expect(hasUnexpectedEventsEmitted) == false expect(signalInterrupted) == true } } describe("Signal.pipe") { it("should forward events to observers") { let (signal, observer) = Signal.pipe() var fromSignal: [Int] = [] var completed = false signal.observe { event in switch event { case let .Next(number): fromSignal.append(number) case .Completed: completed = true default: break } } expect(fromSignal).to(beEmpty()) expect(completed) == false observer.sendNext(1) expect(fromSignal) == [ 1 ] observer.sendNext(2) expect(fromSignal) == [ 1, 2 ] expect(completed) == false observer.sendCompleted() expect(completed) == true } context("memory") { it("should not crash allocating memory with a few observers") { let (signal, _) = Signal.pipe() for _ in 0..<50 { autoreleasepool { let disposable = signal.observe { _ in } disposable!.dispose() } } } } } describe("observe") { var testScheduler: TestScheduler! beforeEach { testScheduler = TestScheduler() } it("should stop forwarding events when disposed") { let disposable = SimpleDisposable() let signal: Signal = Signal { observer in testScheduler.schedule { for number in [ 1, 2 ] { observer.sendNext(number) } observer.sendCompleted() observer.sendNext(4) } return disposable } var fromSignal: [Int] = [] signal.observeNext { number in fromSignal.append(number) } expect(disposable.disposed) == false expect(fromSignal).to(beEmpty()) testScheduler.run() expect(disposable.disposed) == true expect(fromSignal) == [ 1, 2 ] } it("should not trigger side effects") { var runCount = 0 let signal: Signal<(), NoError> = Signal { observer in runCount += 1 return nil } expect(runCount) == 1 signal.observe(Observer<(), NoError>()) expect(runCount) == 1 } it("should release observer after termination") { weak var testStr: NSMutableString? let (signal, observer) = Signal.pipe() let test: () -> () = { let innerStr: NSMutableString = NSMutableString() signal.observeNext { value in innerStr.appendString("\(value)") } testStr = innerStr } test() observer.sendNext(1) expect(testStr) == "1" observer.sendNext(2) expect(testStr) == "12" observer.sendCompleted() expect(testStr).to(beNil()) } it("should release observer after interruption") { weak var testStr: NSMutableString? let (signal, observer) = Signal.pipe() let test: () -> () = { let innerStr: NSMutableString = NSMutableString() signal.observeNext { value in innerStr.appendString("\(value)") } testStr = innerStr } test() observer.sendNext(1) expect(testStr) == "1" observer.sendNext(2) expect(testStr) == "12" observer.sendInterrupted() expect(testStr).to(beNil()) } } describe("trailing closure") { it("receives next values") { var values = [Int]() let (signal, observer) = Signal.pipe() signal.observeNext { next in values.append(next) } observer.sendNext(1) expect(values) == [1] } } describe("map") { it("should transform the values of the signal") { let (signal, observer) = Signal.pipe() let mappedSignal = signal.map { String($0 + 1) } var lastValue: String? mappedSignal.observeNext { lastValue = $0 return } expect(lastValue).to(beNil()) observer.sendNext(0) expect(lastValue) == "1" observer.sendNext(1) expect(lastValue) == "2" } } describe("mapError") { it("should transform the errors of the signal") { let (signal, observer) = Signal.pipe() let producerError = NSError(domain: "com.reactivecocoa.errordomain", code: 100, userInfo: nil) var error: NSError? signal .mapError { _ in producerError } .observeFailed { err in error = err } expect(error).to(beNil()) observer.sendFailed(TestError.Default) expect(error) == producerError } } describe("filter") { it("should omit values from the signal") { let (signal, observer) = Signal.pipe() let mappedSignal = signal.filter { $0 % 2 == 0 } var lastValue: Int? mappedSignal.observeNext { lastValue = $0 } expect(lastValue).to(beNil()) observer.sendNext(0) expect(lastValue) == 0 observer.sendNext(1) expect(lastValue) == 0 observer.sendNext(2) expect(lastValue) == 2 } } describe("Signal.merge") { it("should emit values from all signals") { let (signal1, observer1) = Signal.pipe() let (signal2, observer2) = Signal.pipe() let mergedSignals = Signal.merge([signal1, signal2]) var lastValue: Int? mergedSignals.observeNext { lastValue = $0 } expect(lastValue).to(beNil()) observer1.sendNext(1) expect(lastValue) == 1 observer2.sendNext(2) expect(lastValue) == 2 observer1.sendNext(3) expect(lastValue) == 3 } it("should not stop when one signal completes") { let (signal1, observer1) = Signal.pipe() let (signal2, observer2) = Signal.pipe() let mergedSignals = Signal.merge([signal1, signal2]) var lastValue: Int? mergedSignals.observeNext { lastValue = $0 } expect(lastValue).to(beNil()) observer1.sendNext(1) expect(lastValue) == 1 observer1.sendCompleted() expect(lastValue) == 1 observer2.sendNext(2) expect(lastValue) == 2 } it("should complete when all signals complete") { let (signal1, observer1) = Signal.pipe() let (signal2, observer2) = Signal.pipe() let mergedSignals = Signal.merge([signal1, signal2]) var completed = false mergedSignals.observeCompleted { completed = true } expect(completed) == false observer1.sendNext(1) expect(completed) == false observer1.sendCompleted() expect(completed) == false observer2.sendCompleted() expect(completed) == true } } describe("ignoreNil") { it("should forward only non-nil values") { let (signal, observer) = Signal.pipe() let mappedSignal = signal.ignoreNil() var lastValue: Int? mappedSignal.observeNext { lastValue = $0 } expect(lastValue).to(beNil()) observer.sendNext(nil) expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue) == 1 observer.sendNext(nil) expect(lastValue) == 1 observer.sendNext(2) expect(lastValue) == 2 } } describe("scan") { it("should incrementally accumulate a value") { let (baseSignal, observer) = Signal.pipe() let signal = baseSignal.scan("", +) var lastValue: String? signal.observeNext { lastValue = $0 } expect(lastValue).to(beNil()) observer.sendNext("a") expect(lastValue) == "a" observer.sendNext("bb") expect(lastValue) == "abb" } } describe("reduce") { it("should accumulate one value") { let (baseSignal, observer) = Signal.pipe() let signal = baseSignal.reduce(1, +) var lastValue: Int? var completed = false signal.observe { event in switch event { case let .Next(value): lastValue = value case .Completed: completed = true default: break } } expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue).to(beNil()) observer.sendNext(2) expect(lastValue).to(beNil()) expect(completed) == false observer.sendCompleted() expect(completed) == true expect(lastValue) == 4 } it("should send the initial value if none are received") { let (baseSignal, observer) = Signal.pipe() let signal = baseSignal.reduce(1, +) var lastValue: Int? var completed = false signal.observe { event in switch event { case let .Next(value): lastValue = value case .Completed: completed = true default: break } } expect(lastValue).to(beNil()) expect(completed) == false observer.sendCompleted() expect(lastValue) == 1 expect(completed) == true } } describe("skip") { it("should skip initial values") { let (baseSignal, observer) = Signal.pipe() let signal = baseSignal.skip(1) var lastValue: Int? signal.observeNext { lastValue = $0 } expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue).to(beNil()) observer.sendNext(2) expect(lastValue) == 2 } it("should not skip any values when 0") { let (baseSignal, observer) = Signal.pipe() let signal = baseSignal.skip(0) var lastValue: Int? signal.observeNext { lastValue = $0 } expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue) == 1 observer.sendNext(2) expect(lastValue) == 2 } } describe("skipRepeats") { it("should skip duplicate Equatable values") { let (baseSignal, observer) = Signal.pipe() let signal = baseSignal.skipRepeats() var values: [Bool] = [] signal.observeNext { values.append($0) } expect(values) == [] observer.sendNext(true) expect(values) == [ true ] observer.sendNext(true) expect(values) == [ true ] observer.sendNext(false) expect(values) == [ true, false ] observer.sendNext(true) expect(values) == [ true, false, true ] } it("should skip values according to a predicate") { let (baseSignal, observer) = Signal.pipe() let signal = baseSignal.skipRepeats { $0.characters.count == $1.characters.count } var values: [String] = [] signal.observeNext { values.append($0) } expect(values) == [] observer.sendNext("a") expect(values) == [ "a" ] observer.sendNext("b") expect(values) == [ "a" ] observer.sendNext("cc") expect(values) == [ "a", "cc" ] observer.sendNext("d") expect(values) == [ "a", "cc", "d" ] } } describe("skipWhile") { var signal: Signal! var observer: Signal.Observer! var lastValue: Int? beforeEach { let (baseSignal, incomingObserver) = Signal.pipe() signal = baseSignal.skipWhile { $0 < 2 } observer = incomingObserver lastValue = nil signal.observeNext { lastValue = $0 } } it("should skip while the predicate is true") { expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue).to(beNil()) observer.sendNext(2) expect(lastValue) == 2 observer.sendNext(0) expect(lastValue) == 0 } it("should not skip any values when the predicate starts false") { expect(lastValue).to(beNil()) observer.sendNext(3) expect(lastValue) == 3 observer.sendNext(1) expect(lastValue) == 1 } } describe("skipUntil") { var signal: Signal! var observer: Signal.Observer! var triggerObserver: Signal<(), NoError>.Observer! var lastValue: Int? = nil beforeEach { let (baseSignal, incomingObserver) = Signal.pipe() let (triggerSignal, incomingTriggerObserver) = Signal<(), NoError>.pipe() signal = baseSignal.skipUntil(triggerSignal) observer = incomingObserver triggerObserver = incomingTriggerObserver lastValue = nil signal.observe { event in switch event { case let .Next(value): lastValue = value default: break } } } it("should skip values until the trigger fires") { expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue).to(beNil()) observer.sendNext(2) expect(lastValue).to(beNil()) triggerObserver.sendNext(()) observer.sendNext(0) expect(lastValue) == 0 } it("should skip values until the trigger completes") { expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue).to(beNil()) observer.sendNext(2) expect(lastValue).to(beNil()) triggerObserver.sendCompleted() observer.sendNext(0) expect(lastValue) == 0 } } describe("take") { it("should take initial values") { let (baseSignal, observer) = Signal.pipe() let signal = baseSignal.take(2) var lastValue: Int? var completed = false signal.observe { event in switch event { case let .Next(value): lastValue = value case .Completed: completed = true default: break } } expect(lastValue).to(beNil()) expect(completed) == false observer.sendNext(1) expect(lastValue) == 1 expect(completed) == false observer.sendNext(2) expect(lastValue) == 2 expect(completed) == true } it("should complete immediately after taking given number of values") { let numbers = [ 1, 2, 4, 4, 5 ] let testScheduler = TestScheduler() var signal: Signal = Signal { observer in testScheduler.schedule { for number in numbers { observer.sendNext(number) } } return nil } var completed = false signal = signal.take(numbers.count) signal.observeCompleted { completed = true } expect(completed) == false testScheduler.run() expect(completed) == true } it("should interrupt when 0") { let numbers = [ 1, 2, 4, 4, 5 ] let testScheduler = TestScheduler() let signal: Signal = Signal { observer in testScheduler.schedule { for number in numbers { observer.sendNext(number) } } return nil } var result: [Int] = [] var interrupted = false signal .take(0) .observe { event in switch event { case let .Next(number): result.append(number) case .Interrupted: interrupted = true default: break } } expect(interrupted) == true testScheduler.run() expect(result).to(beEmpty()) } } describe("collect") { it("should collect all values") { let (original, observer) = Signal.pipe() let signal = original.collect() let expectedResult = [ 1, 2, 3 ] var result: [Int]? signal.observeNext { value in expect(result).to(beNil()) result = value } for number in expectedResult { observer.sendNext(number) } expect(result).to(beNil()) observer.sendCompleted() expect(result) == expectedResult } it("should complete with an empty array if there are no values") { let (original, observer) = Signal.pipe() let signal = original.collect() var result: [Int]? signal.observeNext { result = $0 } expect(result).to(beNil()) observer.sendCompleted() expect(result) == [] } it("should forward errors") { let (original, observer) = Signal.pipe() let signal = original.collect() var error: TestError? signal.observeFailed { error = $0 } expect(error).to(beNil()) observer.sendFailed(.Default) expect(error) == TestError.Default } } describe("takeUntil") { var signal: Signal! var observer: Signal.Observer! var triggerObserver: Signal<(), NoError>.Observer! var lastValue: Int? = nil var completed: Bool = false beforeEach { let (baseSignal, incomingObserver) = Signal.pipe() let (triggerSignal, incomingTriggerObserver) = Signal<(), NoError>.pipe() signal = baseSignal.takeUntil(triggerSignal) observer = incomingObserver triggerObserver = incomingTriggerObserver lastValue = nil completed = false signal.observe { event in switch event { case let .Next(value): lastValue = value case .Completed: completed = true default: break } } } it("should take values until the trigger fires") { expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue) == 1 observer.sendNext(2) expect(lastValue) == 2 expect(completed) == false triggerObserver.sendNext(()) expect(completed) == true } it("should take values until the trigger completes") { expect(lastValue).to(beNil()) observer.sendNext(1) expect(lastValue) == 1 observer.sendNext(2) expect(lastValue) == 2 expect(completed) == false triggerObserver.sendCompleted() expect(completed) == true } it("should complete if the trigger fires immediately") { expect(lastValue).to(beNil()) expect(completed) == false triggerObserver.sendNext(()) expect(completed) == true expect(lastValue).to(beNil()) } } describe("takeUntilReplacement") { var signal: Signal! var observer: Signal.Observer! var replacementObserver: Signal.Observer! var lastValue: Int? = nil var completed: Bool = false beforeEach { let (baseSignal, incomingObserver) = Signal.pipe() let (replacementSignal, incomingReplacementObserver) = Signal.pipe() signal = baseSignal.takeUntilReplacement(replacementSignal) observer = incomingObserver replacementObserver = incomingReplacementObserver lastValue = nil completed = false signal.observe { event in switch event { case let .Next(value): lastValue = value case .Completed: completed = true default: break } } } it("should take values from the original then the replacement") { expect(lastValue).to(beNil()) expect(completed) == false observer.sendNext(1) expect(lastValue) == 1 observer.sendNext(2) expect(lastValue) == 2 replacementObserver.sendNext(3) expect(lastValue) == 3 expect(completed) == false observer.sendNext(4) expect(lastValue) == 3 expect(completed) == false replacementObserver.sendNext(5) expect(lastValue) == 5 expect(completed) == false replacementObserver.sendCompleted() expect(completed) == true } } describe("takeWhile") { var signal: Signal! var observer: Signal.Observer! beforeEach { let (baseSignal, incomingObserver) = Signal.pipe() signal = baseSignal.takeWhile { $0 <= 4 } observer = incomingObserver } it("should take while the predicate is true") { var latestValue: Int! var completed = false signal.observe { event in switch event { case let .Next(value): latestValue = value case .Completed: completed = true default: break } } for value in -1...4 { observer.sendNext(value) expect(latestValue) == value expect(completed) == false } observer.sendNext(5) expect(latestValue) == 4 expect(completed) == true } it("should complete if the predicate starts false") { var latestValue: Int? var completed = false signal.observe { event in switch event { case let .Next(value): latestValue = value case .Completed: completed = true default: break } } observer.sendNext(5) expect(latestValue).to(beNil()) expect(completed) == true } } describe("observeOn") { it("should send events on the given scheduler") { let testScheduler = TestScheduler() let (signal, observer) = Signal.pipe() var result: [Int] = [] signal .observeOn(testScheduler) .observeNext { result.append($0) } observer.sendNext(1) observer.sendNext(2) expect(result).to(beEmpty()) testScheduler.run() expect(result) == [ 1, 2 ] } } describe("delay") { it("should send events on the given scheduler after the interval") { let testScheduler = TestScheduler() let signal: Signal = Signal { observer in testScheduler.schedule { observer.sendNext(1) } testScheduler.scheduleAfter(5, action: { observer.sendNext(2) observer.sendCompleted() }) return nil } var result: [Int] = [] var completed = false signal .delay(10, onScheduler: testScheduler) .observe { event in switch event { case let .Next(number): result.append(number) case .Completed: completed = true default: break } } testScheduler.advanceByInterval(4) // send initial value expect(result).to(beEmpty()) testScheduler.advanceByInterval(10) // send second value and receive first expect(result) == [ 1 ] expect(completed) == false testScheduler.advanceByInterval(10) // send second value and receive first expect(result) == [ 1, 2 ] expect(completed) == true } it("should schedule errors immediately") { let testScheduler = TestScheduler() let signal: Signal = Signal { observer in testScheduler.schedule { observer.sendFailed(TestError.Default) } return nil } var errored = false signal .delay(10, onScheduler: testScheduler) .observeFailed { _ in errored = true } testScheduler.advance() expect(errored) == true } } describe("throttle") { var scheduler: TestScheduler! var observer: Signal.Observer! var signal: Signal! beforeEach { scheduler = TestScheduler() let (baseSignal, baseObserver) = Signal.pipe() observer = baseObserver signal = baseSignal.throttle(1, onScheduler: scheduler) expect(signal).notTo(beNil()) } it("should send values on the given scheduler at no less than the interval") { var values: [Int] = [] signal.observeNext { value in values.append(value) } expect(values) == [] observer.sendNext(0) expect(values) == [] scheduler.advance() expect(values) == [ 0 ] observer.sendNext(1) observer.sendNext(2) expect(values) == [ 0 ] scheduler.advanceByInterval(1.5) expect(values) == [ 0, 2 ] scheduler.advanceByInterval(3) expect(values) == [ 0, 2 ] observer.sendNext(3) expect(values) == [ 0, 2 ] scheduler.advance() expect(values) == [ 0, 2, 3 ] observer.sendNext(4) observer.sendNext(5) scheduler.advance() expect(values) == [ 0, 2, 3 ] scheduler.run() expect(values) == [ 0, 2, 3, 5 ] } it("should schedule completion immediately") { var values: [Int] = [] var completed = false signal.observe { event in switch event { case let .Next(value): values.append(value) case .Completed: completed = true default: break } } observer.sendNext(0) scheduler.advance() expect(values) == [ 0 ] observer.sendNext(1) observer.sendCompleted() expect(completed) == false scheduler.run() expect(values) == [ 0 ] expect(completed) == true } } describe("sampleOn") { var sampledSignal: Signal! var observer: Signal.Observer! var samplerObserver: Signal<(), NoError>.Observer! beforeEach { let (signal, incomingObserver) = Signal.pipe() let (sampler, incomingSamplerObserver) = Signal<(), NoError>.pipe() sampledSignal = signal.sampleOn(sampler) observer = incomingObserver samplerObserver = incomingSamplerObserver } it("should forward the latest value when the sampler fires") { var result: [Int] = [] sampledSignal.observeNext { result.append($0) } observer.sendNext(1) observer.sendNext(2) samplerObserver.sendNext(()) expect(result) == [ 2 ] } it("should do nothing if sampler fires before signal receives value") { var result: [Int] = [] sampledSignal.observeNext { result.append($0) } samplerObserver.sendNext(()) expect(result).to(beEmpty()) } it("should send lates value multiple times when sampler fires multiple times") { var result: [Int] = [] sampledSignal.observeNext { result.append($0) } observer.sendNext(1) samplerObserver.sendNext(()) samplerObserver.sendNext(()) expect(result) == [ 1, 1 ] } it("should complete when both inputs have completed") { var completed = false sampledSignal.observeCompleted { completed = true } observer.sendCompleted() expect(completed) == false samplerObserver.sendCompleted() expect(completed) == true } } describe("combineLatestWith") { var combinedSignal: Signal<(Int, Double), NoError>! var observer: Signal.Observer! var otherObserver: Signal.Observer! beforeEach { let (signal, incomingObserver) = Signal.pipe() let (otherSignal, incomingOtherObserver) = Signal.pipe() combinedSignal = signal.combineLatestWith(otherSignal) observer = incomingObserver otherObserver = incomingOtherObserver } it("should forward the latest values from both inputs") { var latest: (Int, Double)? combinedSignal.observeNext { latest = $0 } observer.sendNext(1) expect(latest).to(beNil()) // is there a better way to test tuples? otherObserver.sendNext(1.5) expect(latest?.0) == 1 expect(latest?.1) == 1.5 observer.sendNext(2) expect(latest?.0) == 2 expect(latest?.1) == 1.5 } it("should complete when both inputs have completed") { var completed = false combinedSignal.observeCompleted { completed = true } observer.sendCompleted() expect(completed) == false otherObserver.sendCompleted() expect(completed) == true } } describe("zipWith") { var leftObserver: Signal.Observer! var rightObserver: Signal.Observer! var zipped: Signal<(Int, String), NoError>! beforeEach { let (leftSignal, incomingLeftObserver) = Signal.pipe() let (rightSignal, incomingRightObserver) = Signal.pipe() leftObserver = incomingLeftObserver rightObserver = incomingRightObserver zipped = leftSignal.zipWith(rightSignal) } it("should combine pairs") { var result: [String] = [] zipped.observeNext { (left, right) in result.append("\(left)\(right)") } leftObserver.sendNext(1) leftObserver.sendNext(2) expect(result) == [] rightObserver.sendNext("foo") expect(result) == [ "1foo" ] leftObserver.sendNext(3) rightObserver.sendNext("bar") expect(result) == [ "1foo", "2bar" ] rightObserver.sendNext("buzz") expect(result) == [ "1foo", "2bar", "3buzz" ] rightObserver.sendNext("fuzz") expect(result) == [ "1foo", "2bar", "3buzz" ] leftObserver.sendNext(4) expect(result) == [ "1foo", "2bar", "3buzz", "4fuzz" ] } it("should complete when the shorter signal has completed") { var result: [String] = [] var completed = false zipped.observe { event in switch event { case let .Next(left, right): result.append("\(left)\(right)") case .Completed: completed = true default: break } } expect(completed) == false leftObserver.sendNext(0) leftObserver.sendCompleted() expect(completed) == false expect(result) == [] rightObserver.sendNext("foo") expect(completed) == true expect(result) == [ "0foo" ] } } describe("materialize") { it("should reify events from the signal") { let (signal, observer) = Signal.pipe() var latestEvent: Event? signal .materialize() .observeNext { latestEvent = $0 } observer.sendNext(2) expect(latestEvent).toNot(beNil()) if let latestEvent = latestEvent { switch latestEvent { case let .Next(value): expect(value) == 2 default: fail() } } observer.sendFailed(TestError.Default) if let latestEvent = latestEvent { switch latestEvent { case .Failed: () default: fail() } } } } describe("dematerialize") { typealias IntEvent = Event var observer: Signal.Observer! var dematerialized: Signal! beforeEach { let (signal, incomingObserver) = Signal.pipe() observer = incomingObserver dematerialized = signal.dematerialize() } it("should send values for Next events") { var result: [Int] = [] dematerialized.observeNext { result.append($0) } expect(result).to(beEmpty()) observer.sendNext(.Next(2)) expect(result) == [ 2 ] observer.sendNext(.Next(4)) expect(result) == [ 2, 4 ] } it("should error out for Error events") { var errored = false dematerialized.observeFailed { _ in errored = true } expect(errored) == false observer.sendNext(.Failed(TestError.Default)) expect(errored) == true } it("should complete early for Completed events") { var completed = false dematerialized.observeCompleted { completed = true } expect(completed) == false observer.sendNext(IntEvent.Completed) expect(completed) == true } } describe("takeLast") { var observer: Signal.Observer! var lastThree: Signal! beforeEach { let (signal, incomingObserver) = Signal.pipe() observer = incomingObserver lastThree = signal.takeLast(3) } it("should send the last N values upon completion") { var result: [Int] = [] lastThree.observeNext { result.append($0) } observer.sendNext(1) observer.sendNext(2) observer.sendNext(3) observer.sendNext(4) expect(result).to(beEmpty()) observer.sendCompleted() expect(result) == [ 2, 3, 4 ] } it("should send less than N values if not enough were received") { var result: [Int] = [] lastThree.observeNext { result.append($0) } observer.sendNext(1) observer.sendNext(2) observer.sendCompleted() expect(result) == [ 1, 2 ] } it("should send nothing when errors") { var result: [Int] = [] var errored = false lastThree.observe { event in switch event { case let .Next(value): result.append(value) case .Failed: errored = true default: break } } observer.sendNext(1) observer.sendNext(2) observer.sendNext(3) expect(errored) == false observer.sendFailed(TestError.Default) expect(errored) == true expect(result).to(beEmpty()) } } describe("timeoutWithError") { var testScheduler: TestScheduler! var signal: Signal! var observer: Signal.Observer! beforeEach { testScheduler = TestScheduler() let (baseSignal, incomingObserver) = Signal.pipe() signal = baseSignal.timeoutWithError(TestError.Default, afterInterval: 2, onScheduler: testScheduler) observer = incomingObserver } it("should complete if within the interval") { var completed = false var errored = false signal.observe { event in switch event { case .Completed: completed = true case .Failed: errored = true default: break } } testScheduler.scheduleAfter(1) { observer.sendCompleted() } expect(completed) == false expect(errored) == false testScheduler.run() expect(completed) == true expect(errored) == false } it("should error if not completed before the interval has elapsed") { var completed = false var errored = false signal.observe { event in switch event { case .Completed: completed = true case .Failed: errored = true default: break } } testScheduler.scheduleAfter(3) { observer.sendCompleted() } expect(completed) == false expect(errored) == false testScheduler.run() expect(completed) == false expect(errored) == true } } describe("attempt") { it("should forward original values upon success") { let (baseSignal, observer) = Signal.pipe() let signal = baseSignal.attempt { _ in return .Success() } var current: Int? signal.observeNext { value in current = value } for value in 1...5 { observer.sendNext(value) expect(current) == value } } it("should error if an attempt fails") { let (baseSignal, observer) = Signal.pipe() let signal = baseSignal.attempt { _ in return .Failure(.Default) } var error: TestError? signal.observeFailed { err in error = err } observer.sendNext(42) expect(error) == TestError.Default } } describe("attemptMap") { it("should forward mapped values upon success") { let (baseSignal, observer) = Signal.pipe() let signal = baseSignal.attemptMap { num -> Result in return .Success(num % 2 == 0) } var even: Bool? signal.observeNext { value in even = value } observer.sendNext(1) expect(even) == false observer.sendNext(2) expect(even) == true } it("should error if a mapping fails") { let (baseSignal, observer) = Signal.pipe() let signal = baseSignal.attemptMap { _ -> Result in return .Failure(.Default) } var error: TestError? signal.observeFailed { err in error = err } observer.sendNext(42) expect(error) == TestError.Default } } describe("combinePrevious") { var observer: Signal.Observer! let initialValue: Int = 0 var latestValues: (Int, Int)? beforeEach { latestValues = nil let (signal, baseObserver) = Signal.pipe() observer = baseObserver signal.combinePrevious(initialValue).observeNext { latestValues = $0 } } it("should forward the latest value with previous value") { expect(latestValues).to(beNil()) observer.sendNext(1) expect(latestValues?.0) == initialValue expect(latestValues?.1) == 1 observer.sendNext(2) expect(latestValues?.0) == 1 expect(latestValues?.1) == 2 } } describe("combineLatest") { var signalA: Signal! var signalB: Signal! var signalC: Signal! var observerA: Signal.Observer! var observerB: Signal.Observer! var observerC: Signal.Observer! var combinedValues: [Int]? var completed: Bool! beforeEach { combinedValues = nil completed = false let (baseSignalA, baseObserverA) = Signal.pipe() let (baseSignalB, baseObserverB) = Signal.pipe() let (baseSignalC, baseObserverC) = Signal.pipe() signalA = baseSignalA signalB = baseSignalB signalC = baseSignalC observerA = baseObserverA observerB = baseObserverB observerC = baseObserverC } let combineLatestExampleName = "combineLatest examples" sharedExamples(combineLatestExampleName) { it("should forward the latest values from all inputs"){ expect(combinedValues).to(beNil()) observerA.sendNext(0) observerB.sendNext(1) observerC.sendNext(2) expect(combinedValues) == [0, 1, 2] observerA.sendNext(10) expect(combinedValues) == [10, 1, 2] } it("should not forward the latest values before all inputs"){ expect(combinedValues).to(beNil()) observerA.sendNext(0) expect(combinedValues).to(beNil()) observerB.sendNext(1) expect(combinedValues).to(beNil()) observerC.sendNext(2) expect(combinedValues) == [0, 1, 2] } it("should complete when all inputs have completed"){ expect(completed) == false observerA.sendCompleted() observerB.sendCompleted() expect(completed) == false observerC.sendCompleted() expect(completed) == true } } describe("tuple") { beforeEach { combineLatest(signalA, signalB, signalC) .observe { event in switch event { case let .Next(value): combinedValues = [value.0, value.1, value.2] case .Completed: completed = true default: break } } } itBehavesLike(combineLatestExampleName) } describe("sequence") { beforeEach { combineLatest([signalA, signalB, signalC]) .observe { event in switch event { case let .Next(values): combinedValues = values case .Completed: completed = true default: break } } } itBehavesLike(combineLatestExampleName) } } describe("zip") { var signalA: Signal! var signalB: Signal! var signalC: Signal! var observerA: Signal.Observer! var observerB: Signal.Observer! var observerC: Signal.Observer! var zippedValues: [Int]? var completed: Bool! beforeEach { zippedValues = nil completed = false let (baseSignalA, baseObserverA) = Signal.pipe() let (baseSignalB, baseObserverB) = Signal.pipe() let (baseSignalC, baseObserverC) = Signal.pipe() signalA = baseSignalA signalB = baseSignalB signalC = baseSignalC observerA = baseObserverA observerB = baseObserverB observerC = baseObserverC } let zipExampleName = "zip examples" sharedExamples(zipExampleName) { it("should combine all set"){ expect(zippedValues).to(beNil()) observerA.sendNext(0) expect(zippedValues).to(beNil()) observerB.sendNext(1) expect(zippedValues).to(beNil()) observerC.sendNext(2) expect(zippedValues) == [0, 1, 2] observerA.sendNext(10) expect(zippedValues) == [0, 1, 2] observerA.sendNext(20) expect(zippedValues) == [0, 1, 2] observerB.sendNext(11) expect(zippedValues) == [0, 1, 2] observerC.sendNext(12) expect(zippedValues) == [10, 11, 12] } it("should complete when the shorter signal has completed"){ expect(completed) == false observerB.sendNext(1) observerC.sendNext(2) observerB.sendCompleted() observerC.sendCompleted() expect(completed) == false observerA.sendNext(0) expect(completed) == true } } describe("tuple") { beforeEach { zip(signalA, signalB, signalC) .observe { event in switch event { case let .Next(value): zippedValues = [value.0, value.1, value.2] case .Completed: completed = true default: break } } } itBehavesLike(zipExampleName) } describe("sequence") { beforeEach { zip([signalA, signalB, signalC]) .observe { event in switch event { case let .Next(values): zippedValues = values case .Completed: completed = true default: break } } } itBehavesLike(zipExampleName) } } } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/Swift/TestError.swift ================================================ // // TestError.swift // ReactiveCocoa // // Created by Almas Sapargali on 1/26/15. // Copyright (c) 2015 GitHub. All rights reserved. // enum TestError: Int { case Default = 0 case Error1 = 1 case Error2 = 2 } extension TestError: ErrorType { } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/ReactiveCocoaTests/test-data.json ================================================ [ { "item": 1 }, { "item": 2 }, { "item": 3 } ] ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/script/LICENSE.md ================================================ **Copyright (c) 2013 Justin Spahr-Summers** 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. ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/script/README.md ================================================ # objc-build-scripts This project is a collection of scripts created with two goals: 1. To standardize how Objective-C projects are bootstrapped after cloning 1. To easily build Objective-C projects on continuous integration servers ## Scripts Right now, there are two important scripts: [`bootstrap`](#bootstrap) and [`cibuild`](#cibuild). Both are Bash scripts, to maximize compatibility and eliminate pesky system configuration issues (like setting up a working Ruby environment). The structure of the scripts on disk is meant to follow that of a typical Ruby project: ``` script/ bootstrap cibuild ``` ### bootstrap This script is responsible for bootstrapping (initializing) your project after it's been checked out. Here, you should install or clone any dependencies that are required for a working build and development environment. By default, the script will verify that [xctool][] is installed, then initialize and update submodules recursively. If any submodules contain `script/bootstrap`, that will be run as well. To check that other tools are installed, you can set the `REQUIRED_TOOLS` environment variable before running `script/bootstrap`, or edit it within the script directly. Note that no installation is performed automatically, though this can always be added within your specific project. ### cibuild This script is responsible for building the project, as you would want it built for continuous integration. This is preferable to putting the logic on the CI server itself, since it ensures that any changes are versioned along with the source. By default, the script will run [`bootstrap`](#bootstrap), look for any Xcode workspace or project in the working directory, then build all targets/schemes (as found by `xcodebuild -list`) using [xctool][]. You can also specify the schemes to build by passing them into the script: ```sh script/cibuild ReactiveCocoa-Mac ReactiveCocoa-iOS ``` As with the `bootstrap` script, there are several environment variables that can be used to customize behavior. They can be set on the command line before invoking the script, or the defaults changed within the script directly. ## Getting Started To add the scripts to your project, read the contents of this repository into a `script` folder: ``` $ git remote add objc-build-scripts https://github.com/jspahrsummers/objc-build-scripts.git $ git fetch objc-build-scripts $ git read-tree --prefix=script/ -u objc-build-scripts/master ``` Then commit the changes, to incorporate the scripts into your own repository's history. You can also freely tweak the scripts for your specific project's needs. To merge in upstream changes later: ``` $ git fetch -p objc-build-scripts $ git merge --ff --squash -Xsubtree=script objc-build-scripts/master ``` [xctool]: https://github.com/facebook/xctool ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/script/bootstrap ================================================ #!/bin/bash export SCRIPT_DIR=$(dirname "$0") ## ## Bootstrap Process ## main () { local submodules=$(git submodule status) local result=$? if [ "$result" -ne "0" ] then exit $result fi if [ -n "$submodules" ] then echo "*** Updating submodules..." update_submodules fi } bootstrap_submodule () { local bootstrap="script/bootstrap" if [ -e "$bootstrap" ] then echo "*** Bootstrapping $name..." "$bootstrap" >/dev/null else update_submodules fi } update_submodules () { git submodule sync --quiet && git submodule update --init && git submodule foreach --quiet bootstrap_submodule } export -f bootstrap_submodule export -f update_submodules main ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/script/cibuild ================================================ #!/bin/bash export SCRIPT_DIR=$(dirname "$0") ## ## Configuration Variables ## SCHEMES="$@" config () { # The workspace to build. # # If not set and no workspace is found, the -workspace flag will not be passed # to `xctool`. # # Only one of `XCWORKSPACE` and `XCODEPROJ` needs to be set. The former will # take precedence. : ${XCWORKSPACE=$(find_pattern "*.xcworkspace")} # The project to build. # # If not set and no project is found, the -project flag will not be passed # to `xctool`. # # Only one of `XCWORKSPACE` and `XCODEPROJ` needs to be set. The former will # take precedence. : ${XCODEPROJ=$(find_pattern "*.xcodeproj")} # A bootstrap script to run before building. # # If this file does not exist, it is not considered an error. : ${BOOTSTRAP="$SCRIPT_DIR/bootstrap"} # Extra options to pass to xctool. : ${XCTOOL_OPTIONS="RUN_CLANG_STATIC_ANALYZER=NO"} # A whitespace-separated list of default schemes to build. # # Individual names can be quoted to avoid word splitting. : ${SCHEMES:=$(xcodebuild -list -project "$XCODEPROJ" 2>/dev/null | awk -f "$SCRIPT_DIR/schemes.awk")} # A whitespace-separated list of executables that must be present and locatable. : ${REQUIRED_TOOLS="xctool"} export XCWORKSPACE export XCODEPROJ export BOOTSTRAP export XCTOOL_OPTIONS export SCHEMES export REQUIRED_TOOLS } ## ## Build Process ## main () { config if [ -n "$REQUIRED_TOOLS" ] then echo "*** Checking dependencies..." check_deps fi if [ -f "$BOOTSTRAP" ] then echo "*** Bootstrapping..." "$BOOTSTRAP" || exit $? fi echo "*** The following schemes will be built:" echo "$SCHEMES" | xargs -n 1 echo " " echo echo "$SCHEMES" | xargs -n 1 | ( local status=0 while read scheme do build_scheme "$scheme" || status=1 done exit $status ) } check_deps () { for tool in $REQUIRED_TOOLS do which -s "$tool" if [ "$?" -ne "0" ] then echo "*** Error: $tool not found. Please install it and cibuild again." exit 1 fi done } find_pattern () { ls -d $1 2>/dev/null | head -n 1 } run_xctool () { if [ -n "$XCWORKSPACE" ] then xctool -workspace "$XCWORKSPACE" $XCTOOL_OPTIONS "$@" 2>&1 elif [ -n "$XCODEPROJ" ] then xctool -project "$XCODEPROJ" $XCTOOL_OPTIONS "$@" 2>&1 else echo "*** No workspace or project file found." exit 1 fi } parse_build () { awk -f "$SCRIPT_DIR/xctool.awk" 2>&1 >/dev/null } build_scheme () { local scheme=$1 echo "*** Building and testing $scheme..." echo local sdkflag= local action=test # Determine whether we can run unit tests for this target. run_xctool -scheme "$scheme" run-tests | parse_build local awkstatus=$? if [ "$awkstatus" -eq "1" ] then # SDK not found, try for iphonesimulator. sdkflag="-sdk iphonesimulator" # Determine whether the unit tests will run with iphonesimulator run_xctool $sdkflag -scheme "$scheme" run-tests | parse_build awkstatus=$? if [ "$awkstatus" -ne "0" ] then # Unit tests will not run on iphonesimulator. sdkflag="" fi fi if [ "$awkstatus" -ne "0" ] then # Unit tests aren't supported. action=build fi run_xctool $sdkflag -scheme "$scheme" $action } export -f build_scheme export -f run_xctool export -f parse_build main ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/script/schemes.awk ================================================ BEGIN { FS = "\n"; } /Schemes:/ { while (getline && $0 != "") { sub(/^ +/, ""); print "'" $0 "'"; } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/script/targets.awk ================================================ BEGIN { FS = "\n"; } /Targets:/ { while (getline && $0 != "") { if ($0 ~ /Tests/) continue; sub(/^ +/, ""); print "'" $0 "'"; } } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/script/xcodebuild.awk ================================================ # Exit statuses: # # 0 - No errors found. # 1 - Build or test failure. Errors will be logged automatically. # 2 - Untestable target. Retry with the "build" action. BEGIN { status = 0; } { print; fflush(stdout); } /is not valid for Testing/ { exit 2; } /[0-9]+: (error|warning):/ { errors = errors $0 "\n"; } /(TEST|BUILD) FAILED/ { status = 1; } END { if (length(errors) > 0) { print "\n*** All errors:\n" errors; } fflush(stdout); exit status; } ================================================ FILE: Carthage/Checkouts/ReactiveCocoa/script/xctool.awk ================================================ # Exit statuses: # # 0 - No errors found. # 1 - Wrong SDK. Retry with SDK `iphonesimulator`. # 2 - Missing target. BEGIN { status = 0; } { print; } /Testing with the '(.+)' SDK is not yet supported/ { status = 1; } /does not contain a target named/ { status = 2; } END { exit status; } ================================================ FILE: Carthage/Checkouts/Result/.gitignore ================================================ .DS_Store xcuserdata *.xcuserdatad *.xccheckout *.mode* *.pbxuser Carthage/Build .build ================================================ FILE: Carthage/Checkouts/Result/.travis.yml ================================================ language: objective-c osx_image: xcode7.1 script: - xcodebuild test -scheme Result-Mac - xcodebuild test -scheme Result-iOS -sdk iphonesimulator - xcodebuild test -scheme Result-tvOS -sdk appletvsimulator - xcodebuild build -scheme Result-watchOS -sdk watchsimulator - pod lib lint notifications: email: false ================================================ FILE: Carthage/Checkouts/Result/CONTRIBUTING.md ================================================ We love that you're interested in contributing to this project! To make the process as painless as possible, we have just a couple of guidelines that should make life easier for everyone involved. ## Prefer Pull Requests If you know exactly how to implement the feature being suggested or fix the bug being reported, please open a pull request instead of an issue. Pull requests are easier than patches or inline code blocks for discussing and merging the changes. If you can't make the change yourself, please open an issue after making sure that one isn't already logged. ## Contributing Code Fork this repository, make it awesomer (preferably in a branch named for the topic), send a pull request! All code contributions should match our [coding conventions](https://github.com/github/swift-style-guide). Thanks for contributing! :boom::camel: ================================================ FILE: Carthage/Checkouts/Result/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Rob Rix 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. ================================================ FILE: Carthage/Checkouts/Result/Package.swift ================================================ import PackageDescription let package = Package( name: "Result", targets: [ Target( name: "Result" ) ] ) ================================================ FILE: Carthage/Checkouts/Result/README.md ================================================ # Result [![Build Status](https://travis-ci.org/antitypical/Result.svg?branch=master)](https://travis-ci.org/antitypical/Result) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![CocoaPods](https://img.shields.io/cocoapods/v/Result.svg)](https://cocoapods.org/) [![Reference Status](https://www.versioneye.com/objective-c/result/reference_badge.svg?style=flat)](https://www.versioneye.com/objective-c/result/references) This is a Swift µframework providing `Result`. `Result` values are either successful (wrapping `Value`) or failed (wrapping `Error`). This is similar to Swift’s native `Optional` type: `Success` is like `Some`, and `Failure` is like `None` except with an associated `ErrorType` value. The addition of an associated `ErrorType` allows errors to be passed along for logging or displaying to the user. Using this µframework instead of rolling your own `Result` type allows you to easily interface with other frameworks that also use `Result`. ## Use Use `Result` whenever an operation has the possibility of failure. Consider the following example of a function that tries to extract a `String` for a given key from a JSON `Dictionary`. ```swift typealias JSONObject = [String:AnyObject] enum JSONError : ErrorType { case NoSuchKey(String) case TypeMismatch } func stringForKey(json: JSONObject, key: String) -> Result { guard let value = json[key] else { return .Failure(.NoSuchKey(key)) } if let value = value as? String { return .Success(value) } else { return .Failure(.TypeMismatch) } } ``` This function provides a more robust wrapper around the default subscripting provided by `Dictionary`. Rather than return `AnyObject?`, it returns a `Result` that either contains the `String` value for the given key, or an `ErrorType` detailing what went wrong. One simple way to handle a `Result` is to deconstruct it using a `switch` statement. ```swift switch stringForKey(json, key: "email") { case let .Success(email): print("The email is \(email)") case let .Failure(JSONError.NoSuchKey(key)): print("\(key) is not a valid key") case .Failure(JSONError.TypeMismatch): print("Didn't have the right type") } ``` Using a `switch` statement allows powerful pattern matching, and ensures all possible results are covered. Swift 2.0 offers new ways to deconstruct enums like the `if-case` statement, but be wary as such methods do not ensure errors are handled. Other methods available for processing `Result` are detailed in the [API documentation](http://cocoadocs.org/docsets/Result/). ## Result vs. Throws Swift 2.0 introduces error handling via throwing and catching `ErrorType`. `Result` accomplishes the same goal by encapsulating the result instead of hijacking control flow. The `Result` abstraction allows enables powerful functionality such as `map` and `flatMap`, making `Result` more composable than `throw`. Since dealing with APIs that throw is common, you can convert functions such functions into a `Result` by using the `materialize` method. Conversely, a `Result` can be used to throw an error by calling `dematerialize`. [Note: due to compiler issues, `materialize` is not currently available] ## Higher Order Functions `map` and `flatMap` operate the same as `Optional.map` and `Optional.flatMap` except they apply to `Result`. `map` transforms a `Result` into a `Result` of a new type. It does this by taking a function that transforms the `Value` type into a new value. This transformation is only applied in the case of a `Success`. In the case of a `Failure`, the associated error is re-wrapped in the new `Result`. ```swift // transforms a Result to a Result let idResult = intForKey(json, key:"id").map { id in String(id) } ``` Here, the final result is either the id as a `String`, or carries over the `.Failure` from the previous result. `flatMap` is similar to `map` in that in transforms the `Result` into another `Result`. However, the function passed into `flatMap` must return a `Result`. An in depth discussion of `map` and `flatMap` is beyond the scope of this documentation. If you would like a deeper understanding, read about functors and monads. This article is a good place to [start](http://www.javiersoto.me/post/106875422394). ## Integration 1. Add this repository as a submodule and/or [add it to your Cartfile](https://github.com/Carthage/Carthage/blob/master/Documentation/Artifacts.md#cartfile) if you’re using [carthage](https://github.com/Carthage/Carthage/) to manage your dependencies. 2. Drag `Result.xcodeproj` into your project or workspace. 3. Link your target against `Result.framework`. 4. Application targets should ensure that the framework gets copied into their application bundle. (Framework targets should instead require the application linking them to include Result.) ================================================ FILE: Carthage/Checkouts/Result/Result/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0.2 CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright Copyright © 2015 Rob Rix. All rights reserved. NSPrincipalClass ================================================ FILE: Carthage/Checkouts/Result/Result/Result.h ================================================ // Copyright (c) 2015 Rob Rix. All rights reserved. /// Project version number for Result. extern double ResultVersionNumber; /// Project version string for Result. extern const unsigned char ResultVersionString[]; ================================================ FILE: Carthage/Checkouts/Result/Result/Result.swift ================================================ // Copyright (c) 2015 Rob Rix. All rights reserved. /// An enum representing either a failure with an explanatory error, or a success with a result value. public enum Result: ResultType, CustomStringConvertible, CustomDebugStringConvertible { case Success(T) case Failure(Error) // MARK: Constructors /// Constructs a success wrapping a `value`. public init(value: T) { self = .Success(value) } /// Constructs a failure wrapping an `error`. public init(error: Error) { self = .Failure(error) } /// Constructs a result from an Optional, failing with `Error` if `nil`. public init(_ value: T?, @autoclosure failWith: () -> Error) { self = value.map(Result.Success) ?? .Failure(failWith()) } /// Constructs a result from a function that uses `throw`, failing with `Error` if throws. public init(@autoclosure _ f: () throws -> T) { self.init(attempt: f) } /// Constructs a result from a function that uses `throw`, failing with `Error` if throws. public init(@noescape attempt f: () throws -> T) { do { self = .Success(try f()) } catch { self = .Failure(error as! Error) } } // MARK: Deconstruction /// Returns the value from `Success` Results or `throw`s the error. public func dematerialize() throws -> T { switch self { case let .Success(value): return value case let .Failure(error): throw error } } /// Case analysis for Result. /// /// Returns the value produced by applying `ifFailure` to `Failure` Results, or `ifSuccess` to `Success` Results. public func analysis(@noescape ifSuccess ifSuccess: T -> Result, @noescape ifFailure: Error -> Result) -> Result { switch self { case let .Success(value): return ifSuccess(value) case let .Failure(value): return ifFailure(value) } } // MARK: Higher-order functions /// Returns `self.value` if this result is a .Success, or the given value otherwise. Equivalent with `??` public func recover(@autoclosure value: () -> T) -> T { return self.value ?? value() } /// Returns this result if it is a .Success, or the given result otherwise. Equivalent with `??` public func recoverWith(@autoclosure result: () -> Result) -> Result { return analysis( ifSuccess: { _ in self }, ifFailure: { _ in result() }) } // MARK: Errors /// The domain for errors constructed by Result. public static var errorDomain: String { return "com.antitypical.Result" } /// The userInfo key for source functions in errors constructed by Result. public static var functionKey: String { return "\(errorDomain).function" } /// The userInfo key for source file paths in errors constructed by Result. public static var fileKey: String { return "\(errorDomain).file" } /// The userInfo key for source file line numbers in errors constructed by Result. public static var lineKey: String { return "\(errorDomain).line" } /// Constructs an error. public static func error(message: String? = nil, function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__) -> NSError { var userInfo: [String: AnyObject] = [ functionKey: function, fileKey: file, lineKey: line, ] if let message = message { userInfo[NSLocalizedDescriptionKey] = message } return NSError(domain: errorDomain, code: 0, userInfo: userInfo) } // MARK: CustomStringConvertible public var description: String { return analysis( ifSuccess: { ".Success(\($0))" }, ifFailure: { ".Failure(\($0))" }) } // MARK: CustomDebugStringConvertible public var debugDescription: String { return description } } /// Returns `true` if `left` and `right` are both `Success`es and their values are equal, or if `left` and `right` are both `Failure`s and their errors are equal. public func == (left: Result, right: Result) -> Bool { if let left = left.value, right = right.value { return left == right } else if let left = left.error, right = right.error { return left == right } return false } /// Returns `true` if `left` and `right` represent different cases, or if they represent the same case but different values. public func != (left: Result, right: Result) -> Bool { return !(left == right) } /// Returns the value of `left` if it is a `Success`, or `right` otherwise. Short-circuits. public func ?? (left: Result, @autoclosure right: () -> T) -> T { return left.recover(right()) } /// Returns `left` if it is a `Success`es, or `right` otherwise. Short-circuits. public func ?? (left: Result, @autoclosure right: () -> Result) -> Result { return left.recoverWith(right()) } // MARK: - Derive result from failable closure public func materialize(@noescape f: () throws -> T) -> Result { return materialize(try f()) } public func materialize(@autoclosure f: () throws -> T) -> Result { do { return .Success(try f()) } catch { return .Failure(error as NSError) } } // MARK: - Cocoa API conveniences /// Constructs a Result with the result of calling `try` with an error pointer. /// /// This is convenient for wrapping Cocoa API which returns an object or `nil` + an error, by reference. e.g.: /// /// Result.try { NSData(contentsOfURL: URL, options: .DataReadingMapped, error: $0) } public func `try`(function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__, `try`: NSErrorPointer -> T?) -> Result { var error: NSError? return `try`(&error).map(Result.Success) ?? .Failure(error ?? Result.error(function: function, file: file, line: line)) } /// Constructs a Result with the result of calling `try` with an error pointer. /// /// This is convenient for wrapping Cocoa API which returns a `Bool` + an error, by reference. e.g.: /// /// Result.try { NSFileManager.defaultManager().removeItemAtURL(URL, error: $0) } public func `try`(function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__, `try`: NSErrorPointer -> Bool) -> Result<(), NSError> { var error: NSError? return `try`(&error) ? .Success(()) : .Failure(error ?? Result<(), NSError>.error(function: function, file: file, line: line)) } // MARK: - Operators infix operator >>- { // Left-associativity so that chaining works like you’d expect, and for consistency with Haskell, Runes, swiftz, etc. associativity left // Higher precedence than function application, but lower than function composition. precedence 100 } /// Returns the result of applying `transform` to `Success`es’ values, or re-wrapping `Failure`’s errors. /// /// This is a synonym for `flatMap`. public func >>- (result: Result, @noescape transform: T -> Result) -> Result { return result.flatMap(transform) } // MARK: - ErrorTypeConvertible conformance /// Make NSError conform to ErrorTypeConvertible extension NSError: ErrorTypeConvertible { public static func errorFromErrorType(error: ErrorType) -> NSError { return error as NSError } } // MARK: - /// An “error” that is impossible to construct. /// /// This can be used to describe `Result`s where failures will never /// be generated. For example, `Result` describes a result that /// contains an `Int`eger and is guaranteed never to be a `Failure`. public enum NoError: ErrorType { } import Foundation ================================================ FILE: Carthage/Checkouts/Result/Result/ResultType.swift ================================================ // Copyright (c) 2015 Rob Rix. All rights reserved. /// A type that can represent either failure with an error or success with a result value. public protocol ResultType { typealias Value typealias Error: ErrorType /// Constructs a successful result wrapping a `value`. init(value: Value) /// Constructs a failed result wrapping an `error`. init(error: Error) /// Case analysis for ResultType. /// /// Returns the value produced by appliying `ifFailure` to the error if self represents a failure, or `ifSuccess` to the result value if self represents a success. func analysis(@noescape ifSuccess ifSuccess: Value -> U, @noescape ifFailure: Error -> U) -> U /// Returns the value if self represents a success, `nil` otherwise. /// /// A default implementation is provided by a protocol extension. Conforming types may specialize it. var value: Value? { get } /// Returns the error if self represents a failure, `nil` otherwise. /// /// A default implementation is provided by a protocol extension. Conforming types may specialize it. var error: Error? { get } } public extension ResultType { /// Returns the value if self represents a success, `nil` otherwise. public var value: Value? { return analysis(ifSuccess: { $0 }, ifFailure: { _ in nil }) } /// Returns the error if self represents a failure, `nil` otherwise. public var error: Error? { return analysis(ifSuccess: { _ in nil }, ifFailure: { $0 }) } /// Returns a new Result by mapping `Success`es’ values using `transform`, or re-wrapping `Failure`s’ errors. public func map(@noescape transform: Value -> U) -> Result { return flatMap { .Success(transform($0)) } } /// Returns the result of applying `transform` to `Success`es’ values, or re-wrapping `Failure`’s errors. public func flatMap(@noescape transform: Value -> Result) -> Result { return analysis( ifSuccess: transform, ifFailure: Result.Failure) } /// Returns a new Result by mapping `Failure`'s values using `transform`, or re-wrapping `Success`es’ values. public func mapError(@noescape transform: Error -> Error2) -> Result { return flatMapError { .Failure(transform($0)) } } /// Returns the result of applying `transform` to `Failure`’s errors, or re-wrapping `Success`es’ values. public func flatMapError(@noescape transform: Error -> Result) -> Result { return analysis( ifSuccess: Result.Success, ifFailure: transform) } } /// Protocol used to constrain `tryMap` to `Result`s with compatible `Error`s. public protocol ErrorTypeConvertible: ErrorType { typealias ConvertibleType = Self static func errorFromErrorType(error: ErrorType) -> ConvertibleType } public extension ResultType where Error: ErrorTypeConvertible { /// Returns the result of applying `transform` to `Success`es’ values, or wrapping thrown errors. public func tryMap(@noescape transform: Value throws -> U) -> Result { return flatMap { value in do { return .Success(try transform(value)) } catch { let convertedError = Error.errorFromErrorType(error) as! Error // Revisit this in a future version of Swift. https://twitter.com/jckarter/status/672931114944696321 return .Failure(convertedError) } } } } // MARK: - Operators infix operator &&& { /// Same associativity as &&. associativity left /// Same precedence as &&. precedence 120 } /// Returns a Result with a tuple of `left` and `right` values if both are `Success`es, or re-wrapping the error of the earlier `Failure`. public func &&& (left: L, @autoclosure right: () -> R) -> Result<(L.Value, R.Value), L.Error> { return left.flatMap { left in right().map { right in (left, right) } } } ================================================ FILE: Carthage/Checkouts/Result/Result.podspec ================================================ Pod::Spec.new do |s| s.name = 'Result' s.version = '1.0.2' s.summary = 'Swift type modelling the success/failure of arbitrary operations' s.homepage = 'https://github.com/antitypical/Result' s.license = { :type => 'MIT', :file => 'LICENSE' } s.author = { 'Rob Rix' => 'rob.rix@github.com' } s.source = { :git => 'https://github.com/antitypical/Result.git', :tag => s.version } s.source_files = 'Result/*.swift' s.requires_arc = true s.ios.deployment_target = '8.0' s.osx.deployment_target = '10.9' s.watchos.deployment_target = '2.0' s.tvos.deployment_target = '9.0' end ================================================ FILE: Carthage/Checkouts/Result/Result.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 45AE89E61B3A6564007B99D7 /* ResultType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93621451B35596200948F2A /* ResultType.swift */; }; 57FCDE3E1BA280DC00130C48 /* ResultType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93621451B35596200948F2A /* ResultType.swift */; }; 57FCDE3F1BA280DC00130C48 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = D45480961A957465009D7229 /* Result.swift */; }; 57FCDE421BA280DC00130C48 /* Result.h in Headers */ = {isa = PBXBuildFile; fileRef = D454805C1A9572F5009D7229 /* Result.h */; settings = {ATTRIBUTES = (Public, ); }; }; 57FCDE4D1BA280E000130C48 /* ResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D454806E1A9572F5009D7229 /* ResultTests.swift */; }; 57FCDE561BA2814300130C48 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57FCDE471BA280DC00130C48 /* Result.framework */; }; D035799B1B2B788F005D26AE /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = D45480961A957465009D7229 /* Result.swift */; }; D035799E1B2B788F005D26AE /* Result.h in Headers */ = {isa = PBXBuildFile; fileRef = D454805C1A9572F5009D7229 /* Result.h */; settings = {ATTRIBUTES = (Public, ); }; }; D03579A91B2B78A1005D26AE /* ResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D454806E1A9572F5009D7229 /* ResultTests.swift */; }; D03579B41B2B78C4005D26AE /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03579A31B2B788F005D26AE /* Result.framework */; }; D454805D1A9572F5009D7229 /* Result.h in Headers */ = {isa = PBXBuildFile; fileRef = D454805C1A9572F5009D7229 /* Result.h */; settings = {ATTRIBUTES = (Public, ); }; }; D45480681A9572F5009D7229 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D45480571A9572F5009D7229 /* Result.framework */; }; D454806F1A9572F5009D7229 /* ResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D454806E1A9572F5009D7229 /* ResultTests.swift */; }; D45480881A957362009D7229 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D454807D1A957361009D7229 /* Result.framework */; }; D45480971A957465009D7229 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = D45480961A957465009D7229 /* Result.swift */; }; D45480981A957465009D7229 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = D45480961A957465009D7229 /* Result.swift */; }; D45480991A9574B8009D7229 /* ResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D454806E1A9572F5009D7229 /* ResultTests.swift */; }; D454809A1A9574BB009D7229 /* Result.h in Headers */ = {isa = PBXBuildFile; fileRef = D454805C1A9572F5009D7229 /* Result.h */; settings = {ATTRIBUTES = (Public, ); }; }; E93621461B35596200948F2A /* ResultType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93621451B35596200948F2A /* ResultType.swift */; }; E93621471B35596200948F2A /* ResultType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E93621451B35596200948F2A /* ResultType.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 57FCDE571BA2814A00130C48 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D454804E1A9572F5009D7229 /* Project object */; proxyType = 1; remoteGlobalIDString = 57FCDE3C1BA280DC00130C48; remoteInfo = "Result-tvOS"; }; D03579B21B2B78BB005D26AE /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D454804E1A9572F5009D7229 /* Project object */; proxyType = 1; remoteGlobalIDString = D03579991B2B788F005D26AE; remoteInfo = "Result-watchOS"; }; D45480691A9572F5009D7229 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D454804E1A9572F5009D7229 /* Project object */; proxyType = 1; remoteGlobalIDString = D45480561A9572F5009D7229; remoteInfo = Result; }; D45480891A957362009D7229 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D454804E1A9572F5009D7229 /* Project object */; proxyType = 1; remoteGlobalIDString = D454807C1A957361009D7229; remoteInfo = "Result-iOS"; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 57FCDE471BA280DC00130C48 /* Result.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Result.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 57FCDE541BA280E000130C48 /* Result-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Result-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; D03579A31B2B788F005D26AE /* Result.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Result.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D03579B01B2B78A1005D26AE /* Result-watchOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Result-watchOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; D45480571A9572F5009D7229 /* Result.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Result.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D454805B1A9572F5009D7229 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D454805C1A9572F5009D7229 /* Result.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Result.h; sourceTree = ""; }; D45480671A9572F5009D7229 /* Result-MacTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Result-MacTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; D454806D1A9572F5009D7229 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D454806E1A9572F5009D7229 /* ResultTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultTests.swift; sourceTree = ""; }; D454807D1A957361009D7229 /* Result.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Result.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D45480871A957362009D7229 /* Result-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Result-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; D45480961A957465009D7229 /* Result.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = ""; }; E93621451B35596200948F2A /* ResultType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultType.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 57FCDE401BA280DC00130C48 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 57FCDE4E1BA280E000130C48 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 57FCDE561BA2814300130C48 /* Result.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; D035799C1B2B788F005D26AE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D03579AA1B2B78A1005D26AE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( D03579B41B2B78C4005D26AE /* Result.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; D45480531A9572F5009D7229 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D45480641A9572F5009D7229 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( D45480681A9572F5009D7229 /* Result.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; D45480791A957361009D7229 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D45480841A957362009D7229 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( D45480881A957362009D7229 /* Result.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ D454804D1A9572F5009D7229 = { isa = PBXGroup; children = ( D45480591A9572F5009D7229 /* Result */, D454806B1A9572F5009D7229 /* ResultTests */, D45480581A9572F5009D7229 /* Products */, ); sourceTree = ""; usesTabs = 1; }; D45480581A9572F5009D7229 /* Products */ = { isa = PBXGroup; children = ( D45480571A9572F5009D7229 /* Result.framework */, D45480671A9572F5009D7229 /* Result-MacTests.xctest */, D454807D1A957361009D7229 /* Result.framework */, D45480871A957362009D7229 /* Result-iOSTests.xctest */, D03579A31B2B788F005D26AE /* Result.framework */, D03579B01B2B78A1005D26AE /* Result-watchOSTests.xctest */, 57FCDE471BA280DC00130C48 /* Result.framework */, 57FCDE541BA280E000130C48 /* Result-tvOSTests.xctest */, ); name = Products; sourceTree = ""; }; D45480591A9572F5009D7229 /* Result */ = { isa = PBXGroup; children = ( D454805C1A9572F5009D7229 /* Result.h */, D45480961A957465009D7229 /* Result.swift */, E93621451B35596200948F2A /* ResultType.swift */, D454805A1A9572F5009D7229 /* Supporting Files */, ); path = Result; sourceTree = ""; }; D454805A1A9572F5009D7229 /* Supporting Files */ = { isa = PBXGroup; children = ( D454805B1A9572F5009D7229 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; D454806B1A9572F5009D7229 /* ResultTests */ = { isa = PBXGroup; children = ( D454806E1A9572F5009D7229 /* ResultTests.swift */, D454806C1A9572F5009D7229 /* Supporting Files */, ); name = ResultTests; path = Tests; sourceTree = ""; }; D454806C1A9572F5009D7229 /* Supporting Files */ = { isa = PBXGroup; children = ( D454806D1A9572F5009D7229 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 57FCDE411BA280DC00130C48 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 57FCDE421BA280DC00130C48 /* Result.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; D035799D1B2B788F005D26AE /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( D035799E1B2B788F005D26AE /* Result.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; D45480541A9572F5009D7229 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( D454805D1A9572F5009D7229 /* Result.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; D454807A1A957361009D7229 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( D454809A1A9574BB009D7229 /* Result.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 57FCDE3C1BA280DC00130C48 /* Result-tvOS */ = { isa = PBXNativeTarget; buildConfigurationList = 57FCDE441BA280DC00130C48 /* Build configuration list for PBXNativeTarget "Result-tvOS" */; buildPhases = ( 57FCDE3D1BA280DC00130C48 /* Sources */, 57FCDE401BA280DC00130C48 /* Frameworks */, 57FCDE411BA280DC00130C48 /* Headers */, 57FCDE431BA280DC00130C48 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Result-tvOS"; productName = "Result-iOS"; productReference = 57FCDE471BA280DC00130C48 /* Result.framework */; productType = "com.apple.product-type.framework"; }; 57FCDE491BA280E000130C48 /* Result-tvOSTests */ = { isa = PBXNativeTarget; buildConfigurationList = 57FCDE511BA280E000130C48 /* Build configuration list for PBXNativeTarget "Result-tvOSTests" */; buildPhases = ( 57FCDE4C1BA280E000130C48 /* Sources */, 57FCDE4E1BA280E000130C48 /* Frameworks */, 57FCDE501BA280E000130C48 /* Resources */, ); buildRules = ( ); dependencies = ( 57FCDE581BA2814A00130C48 /* PBXTargetDependency */, ); name = "Result-tvOSTests"; productName = "Result-iOSTests"; productReference = 57FCDE541BA280E000130C48 /* Result-tvOSTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; D03579991B2B788F005D26AE /* Result-watchOS */ = { isa = PBXNativeTarget; buildConfigurationList = D03579A01B2B788F005D26AE /* Build configuration list for PBXNativeTarget "Result-watchOS" */; buildPhases = ( D035799A1B2B788F005D26AE /* Sources */, D035799C1B2B788F005D26AE /* Frameworks */, D035799D1B2B788F005D26AE /* Headers */, D035799F1B2B788F005D26AE /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Result-watchOS"; productName = Result; productReference = D03579A31B2B788F005D26AE /* Result.framework */; productType = "com.apple.product-type.framework"; }; D03579A51B2B78A1005D26AE /* Result-watchOSTests */ = { isa = PBXNativeTarget; buildConfigurationList = D03579AD1B2B78A1005D26AE /* Build configuration list for PBXNativeTarget "Result-watchOSTests" */; buildPhases = ( D03579A81B2B78A1005D26AE /* Sources */, D03579AA1B2B78A1005D26AE /* Frameworks */, D03579AC1B2B78A1005D26AE /* Resources */, ); buildRules = ( ); dependencies = ( D03579B31B2B78BB005D26AE /* PBXTargetDependency */, ); name = "Result-watchOSTests"; productName = ResultTests; productReference = D03579B01B2B78A1005D26AE /* Result-watchOSTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; D45480561A9572F5009D7229 /* Result-Mac */ = { isa = PBXNativeTarget; buildConfigurationList = D45480721A9572F5009D7229 /* Build configuration list for PBXNativeTarget "Result-Mac" */; buildPhases = ( D45480521A9572F5009D7229 /* Sources */, D45480531A9572F5009D7229 /* Frameworks */, D45480541A9572F5009D7229 /* Headers */, D45480551A9572F5009D7229 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Result-Mac"; productName = Result; productReference = D45480571A9572F5009D7229 /* Result.framework */; productType = "com.apple.product-type.framework"; }; D45480661A9572F5009D7229 /* Result-MacTests */ = { isa = PBXNativeTarget; buildConfigurationList = D45480751A9572F5009D7229 /* Build configuration list for PBXNativeTarget "Result-MacTests" */; buildPhases = ( D45480631A9572F5009D7229 /* Sources */, D45480641A9572F5009D7229 /* Frameworks */, D45480651A9572F5009D7229 /* Resources */, ); buildRules = ( ); dependencies = ( D454806A1A9572F5009D7229 /* PBXTargetDependency */, ); name = "Result-MacTests"; productName = ResultTests; productReference = D45480671A9572F5009D7229 /* Result-MacTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; D454807C1A957361009D7229 /* Result-iOS */ = { isa = PBXNativeTarget; buildConfigurationList = D45480941A957362009D7229 /* Build configuration list for PBXNativeTarget "Result-iOS" */; buildPhases = ( D45480781A957361009D7229 /* Sources */, D45480791A957361009D7229 /* Frameworks */, D454807A1A957361009D7229 /* Headers */, D454807B1A957361009D7229 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "Result-iOS"; productName = "Result-iOS"; productReference = D454807D1A957361009D7229 /* Result.framework */; productType = "com.apple.product-type.framework"; }; D45480861A957362009D7229 /* Result-iOSTests */ = { isa = PBXNativeTarget; buildConfigurationList = D45480951A957362009D7229 /* Build configuration list for PBXNativeTarget "Result-iOSTests" */; buildPhases = ( D45480831A957362009D7229 /* Sources */, D45480841A957362009D7229 /* Frameworks */, D45480851A957362009D7229 /* Resources */, ); buildRules = ( ); dependencies = ( D454808A1A957362009D7229 /* PBXTargetDependency */, ); name = "Result-iOSTests"; productName = "Result-iOSTests"; productReference = D45480871A957362009D7229 /* Result-iOSTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ D454804E1A9572F5009D7229 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0700; LastUpgradeCheck = 0700; ORGANIZATIONNAME = "Rob Rix"; TargetAttributes = { D45480561A9572F5009D7229 = { CreatedOnToolsVersion = 6.3; }; D45480661A9572F5009D7229 = { CreatedOnToolsVersion = 6.3; }; D454807C1A957361009D7229 = { CreatedOnToolsVersion = 6.3; }; D45480861A957362009D7229 = { CreatedOnToolsVersion = 6.3; }; }; }; buildConfigurationList = D45480511A9572F5009D7229 /* Build configuration list for PBXProject "Result" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = D454804D1A9572F5009D7229; productRefGroup = D45480581A9572F5009D7229 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( D45480561A9572F5009D7229 /* Result-Mac */, D45480661A9572F5009D7229 /* Result-MacTests */, D454807C1A957361009D7229 /* Result-iOS */, D45480861A957362009D7229 /* Result-iOSTests */, 57FCDE3C1BA280DC00130C48 /* Result-tvOS */, 57FCDE491BA280E000130C48 /* Result-tvOSTests */, D03579991B2B788F005D26AE /* Result-watchOS */, D03579A51B2B78A1005D26AE /* Result-watchOSTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 57FCDE431BA280DC00130C48 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 57FCDE501BA280E000130C48 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D035799F1B2B788F005D26AE /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D03579AC1B2B78A1005D26AE /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D45480551A9572F5009D7229 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D45480651A9572F5009D7229 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D454807B1A957361009D7229 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D45480851A957362009D7229 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 57FCDE3D1BA280DC00130C48 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 57FCDE3E1BA280DC00130C48 /* ResultType.swift in Sources */, 57FCDE3F1BA280DC00130C48 /* Result.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 57FCDE4C1BA280E000130C48 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 57FCDE4D1BA280E000130C48 /* ResultTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D035799A1B2B788F005D26AE /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 45AE89E61B3A6564007B99D7 /* ResultType.swift in Sources */, D035799B1B2B788F005D26AE /* Result.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D03579A81B2B78A1005D26AE /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D03579A91B2B78A1005D26AE /* ResultTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D45480521A9572F5009D7229 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E93621461B35596200948F2A /* ResultType.swift in Sources */, D45480971A957465009D7229 /* Result.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D45480631A9572F5009D7229 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D454806F1A9572F5009D7229 /* ResultTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D45480781A957361009D7229 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E93621471B35596200948F2A /* ResultType.swift in Sources */, D45480981A957465009D7229 /* Result.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; D45480831A957362009D7229 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D45480991A9574B8009D7229 /* ResultTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 57FCDE581BA2814A00130C48 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 57FCDE3C1BA280DC00130C48 /* Result-tvOS */; targetProxy = 57FCDE571BA2814A00130C48 /* PBXContainerItemProxy */; }; D03579B31B2B78BB005D26AE /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D03579991B2B788F005D26AE /* Result-watchOS */; targetProxy = D03579B21B2B78BB005D26AE /* PBXContainerItemProxy */; }; D454806A1A9572F5009D7229 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D45480561A9572F5009D7229 /* Result-Mac */; targetProxy = D45480691A9572F5009D7229 /* PBXContainerItemProxy */; }; D454808A1A957362009D7229 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D454807C1A957361009D7229 /* Result-iOS */; targetProxy = D45480891A957362009D7229 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 57FCDE451BA280DC00130C48 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BITCODE_GENERATION_MODE = bitcode; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=appletvsimulator*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = Result/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Result; SDKROOT = appletvos; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TARGETED_DEVICE_FAMILY = 3; }; name = Debug; }; 57FCDE461BA280DC00130C48 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BITCODE_GENERATION_MODE = bitcode; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=appletvsimulator*]" = ""; COPY_PHASE_STRIP = NO; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Result/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Result; SDKROOT = appletvos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = 3; VALIDATE_PRODUCT = YES; }; name = Release; }; 57FCDE521BA280E000130C48 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; CODE_SIGN_IDENTITY = "iPhone Developer"; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; }; name = Debug; }; 57FCDE531BA280E000130C48 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; VALIDATE_PRODUCT = YES; }; name = Release; }; D03579A11B2B788F005D26AE /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BITCODE_GENERATION_MODE = bitcode; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=watchsimulator*]" = ""; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; INFOPLIST_FILE = Result/Info.plist; INSTALL_PATH = "@rpath"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Result; SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; D03579A21B2B788F005D26AE /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BITCODE_GENERATION_MODE = bitcode; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=watchsimulator*]" = ""; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; INFOPLIST_FILE = Result/Info.plist; INSTALL_PATH = "@rpath"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Result; SDKROOT = watchos; SKIP_INSTALL = YES; }; name = Release; }; D03579AE1B2B78A1005D26AE /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; }; name = Debug; }; D03579AF1B2B78A1005D26AE /* Release */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; }; name = Release; }; D45480701A9572F5009D7229 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; APPLICATION_EXTENSION_API_ONLY = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; 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; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.antitypical.$(PRODUCT_NAME:rfc1034identifier)"; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TVOS_DEPLOYMENT_TARGET = 9.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Debug; }; D45480711A9572F5009D7229 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; APPLICATION_EXTENSION_API_ONLY = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; 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; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.antitypical.$(PRODUCT_NAME:rfc1034identifier)"; SDKROOT = macosx; TVOS_DEPLOYMENT_TARGET = 9.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Release; }; D45480731A9572F5009D7229 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; INFOPLIST_FILE = Result/Info.plist; INSTALL_PATH = "@rpath"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Result; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; VALID_ARCHS = x86_64; }; name = Debug; }; D45480741A9572F5009D7229 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; INFOPLIST_FILE = Result/Info.plist; INSTALL_PATH = "@rpath"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Result; SKIP_INSTALL = YES; VALID_ARCHS = x86_64; }; name = Release; }; D45480761A9572F5009D7229 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; D45480771A9572F5009D7229 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; D45480901A957362009D7229 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BITCODE_GENERATION_MODE = bitcode; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphonesimulator*]" = ""; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = Result/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Result; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; D45480911A957362009D7229 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BITCODE_GENERATION_MODE = bitcode; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphonesimulator*]" = ""; COPY_PHASE_STRIP = NO; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_BITCODE = YES; INFOPLIST_FILE = Result/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = Result; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; D45480921A957362009D7229 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; CODE_SIGN_IDENTITY = "iPhone Developer"; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; }; name = Debug; }; D45480931A957362009D7229 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 57FCDE441BA280DC00130C48 /* Build configuration list for PBXNativeTarget "Result-tvOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 57FCDE451BA280DC00130C48 /* Debug */, 57FCDE461BA280DC00130C48 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 57FCDE511BA280E000130C48 /* Build configuration list for PBXNativeTarget "Result-tvOSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 57FCDE521BA280E000130C48 /* Debug */, 57FCDE531BA280E000130C48 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D03579A01B2B788F005D26AE /* Build configuration list for PBXNativeTarget "Result-watchOS" */ = { isa = XCConfigurationList; buildConfigurations = ( D03579A11B2B788F005D26AE /* Debug */, D03579A21B2B788F005D26AE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D03579AD1B2B78A1005D26AE /* Build configuration list for PBXNativeTarget "Result-watchOSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( D03579AE1B2B78A1005D26AE /* Debug */, D03579AF1B2B78A1005D26AE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D45480511A9572F5009D7229 /* Build configuration list for PBXProject "Result" */ = { isa = XCConfigurationList; buildConfigurations = ( D45480701A9572F5009D7229 /* Debug */, D45480711A9572F5009D7229 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D45480721A9572F5009D7229 /* Build configuration list for PBXNativeTarget "Result-Mac" */ = { isa = XCConfigurationList; buildConfigurations = ( D45480731A9572F5009D7229 /* Debug */, D45480741A9572F5009D7229 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D45480751A9572F5009D7229 /* Build configuration list for PBXNativeTarget "Result-MacTests" */ = { isa = XCConfigurationList; buildConfigurations = ( D45480761A9572F5009D7229 /* Debug */, D45480771A9572F5009D7229 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D45480941A957362009D7229 /* Build configuration list for PBXNativeTarget "Result-iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( D45480901A957362009D7229 /* Debug */, D45480911A957362009D7229 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D45480951A957362009D7229 /* Build configuration list for PBXNativeTarget "Result-iOSTests" */ = { isa = XCConfigurationList; buildConfigurations = ( D45480921A957362009D7229 /* Debug */, D45480931A957362009D7229 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = D454804E1A9572F5009D7229 /* Project object */; } ================================================ FILE: Carthage/Checkouts/Result/Result.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Carthage/Checkouts/Result/Result.xcodeproj/xcshareddata/xcschemes/Result-Mac.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/Result/Result.xcodeproj/xcshareddata/xcschemes/Result-iOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/Result/Result.xcodeproj/xcshareddata/xcschemes/Result-tvOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/Result/Result.xcodeproj/xcshareddata/xcschemes/Result-watchOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/Result/Tests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Carthage/Checkouts/Result/Tests/ResultTests.swift ================================================ // Copyright (c) 2015 Rob Rix. All rights reserved. final class ResultTests: XCTestCase { func testMapTransformsSuccesses() { XCTAssertEqual(success.map { $0.characters.count } ?? 0, 7) } func testMapRewrapsFailures() { XCTAssertEqual(failure.map { $0.characters.count } ?? 0, 0) } func testInitOptionalSuccess() { XCTAssert(Result("success" as String?, failWith: error) == success) } func testInitOptionalFailure() { XCTAssert(Result(nil, failWith: error) == failure) } // MARK: Errors func testErrorsIncludeTheSourceFile() { let file = __FILE__ XCTAssert(Result<(), NSError>.error().file == file) } func testErrorsIncludeTheSourceLine() { let (line, error) = (__LINE__, Result<(), NSError>.error()) XCTAssertEqual(error.line ?? -1, line) } func testErrorsIncludeTheCallingFunction() { let function = __FUNCTION__ XCTAssert(Result<(), NSError>.error().function == function) } // MARK: Try - Catch func testTryCatchProducesSuccesses() { let result: Result = Result(try tryIsSuccess("success")) XCTAssert(result == success) } func testTryCatchProducesFailures() { let result: Result = Result(try tryIsSuccess(nil)) XCTAssert(result.error == error) } func testTryCatchWithFunctionProducesSuccesses() { let function = { try tryIsSuccess("success") } let result: Result = Result(attempt: function) XCTAssert(result == success) } func testTryCatchWithFunctionCatchProducesFailures() { let function = { try tryIsSuccess(nil) } let result: Result = Result(attempt: function) XCTAssert(result.error == error) } func testMaterializeProducesSuccesses() { let result1 = materialize(try tryIsSuccess("success")) XCTAssert(result1 == success) let result2 = materialize { try tryIsSuccess("success") } XCTAssert(result2 == success) } func testMaterializeProducesFailures() { let result1 = materialize(try tryIsSuccess(nil)) XCTAssert(result1.error == error) let result2 = materialize { try tryIsSuccess(nil) } XCTAssert(result2.error == error) } // MARK: Cocoa API idioms func testTryProducesFailuresForBooleanAPIWithErrorReturnedByReference() { let result = `try` { attempt(true, succeed: false, error: $0) } XCTAssertFalse(result ?? false) XCTAssertNotNil(result.error) } func testTryProducesFailuresForOptionalWithErrorReturnedByReference() { let result = `try` { attempt(1, succeed: false, error: $0) } XCTAssertEqual(result ?? 0, 0) XCTAssertNotNil(result.error) } func testTryProducesSuccessesForBooleanAPI() { let result = `try` { attempt(true, succeed: true, error: $0) } XCTAssertTrue(result ?? false) XCTAssertNil(result.error) } func testTryProducesSuccessesForOptionalAPI() { let result = `try` { attempt(1, succeed: true, error: $0) } XCTAssertEqual(result ?? 0, 1) XCTAssertNil(result.error) } func testTryMapProducesSuccess() { let result = success.tryMap(tryIsSuccess) XCTAssert(result == success) } func testTryMapProducesFailure() { let result = Result.Success("fail").tryMap(tryIsSuccess) XCTAssert(result == failure) } // MARK: Operators func testConjunctionOperator() { let resultSuccess = success &&& success if let (x, y) = resultSuccess.value { XCTAssertTrue(x == "success" && y == "success") } else { XCTFail() } let resultFailureBoth = failure &&& failure2 XCTAssert(resultFailureBoth.error == error) let resultFailureLeft = failure &&& success XCTAssert(resultFailureLeft.error == error) let resultFailureRight = success &&& failure2 XCTAssert(resultFailureRight.error == error2) } } // MARK: - Fixtures let success = Result.Success("success") let error = NSError(domain: "com.antitypical.Result", code: 1, userInfo: nil) let error2 = NSError(domain: "com.antitypical.Result", code: 2, userInfo: nil) let failure = Result.Failure(error) let failure2 = Result.Failure(error2) // MARK: - Helpers func attempt(value: T, succeed: Bool, error: NSErrorPointer) -> T? { if succeed { return value } else { error.memory = Result<(), NSError>.error() return nil } } func tryIsSuccess(text: String?) throws -> String { guard let text = text where text == "success" else { throw error } return text } extension NSError { var function: String? { return userInfo[Result<(), NSError>.functionKey as NSString] as? String } var file: String? { return userInfo[Result<(), NSError>.fileKey as NSString] as? String } var line: Int? { return userInfo[Result<(), NSError>.lineKey as NSString] as? Int } } import Result import XCTest ================================================ FILE: Carthage/Checkouts/SIOSocket/.gitignore ================================================ # CocoaPods # # We recommend against adding the Pods directory to your .gitignore. However # you should judge for yourself, the pros and cons are mentioned at: # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control? # # Pods/ node_modules/ SocketIO.xcodeproj/project.xcworkspace/xcuserdata/ ================================================ FILE: Carthage/Checkouts/SIOSocket/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 MegaBits 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. ================================================ FILE: Carthage/Checkouts/SIOSocket/README.md ================================================ # SIOSocket SIOSocket is simple interface for communicating with [Socket.IO 1.0](http://socket.io) from iOS. __There is now a [first-party iOS client](http://socket.io/blog/socket-io-on-ios/) for Socket.IO!__ (Therefore, this library is no longer being actively developed.) Congrats to the Socket.IO team for a job well done. [![No Maintenance Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/) ## How to use SIOSocket can be added as a CocodaPod, submodule, or standalone dependency to any iOS 7.0 (or greater) project. ```ruby pod 'SIOSocket', '~> 0.2.0' ``` then... ```objc #import // ... [SIOSocket socketWithHost: @"http://localhost:3000" response: ^(SIOSocket *socket) { self.socket = socket; }]; ``` or, in Swift... ```swift // ... SIOSocket.socketWithHost("http://localhost:3000") { (socket: SIOSocket) in self.socket = socket } ``` A full demo can be found over at [MegaBits/WorldPin](https://github.com/MegaBits/WorldPin) ## Types #### `typedef NSArray SIOParameterArray` An NSArray of these JSValue-valid objects: - NSNull - NSString - NSNumber - NSDictionary - NSArray - NSData ## Generators #### `+ (void)socketWithHost:response:` Generates a new `SIOSocket` object, begins its connection to the given host, and returns it as the sole parameter of the response block. The host reachable at the given URL string should be running a valid instance of a socket.io server. #### `+ (void)socketWithHost:reconnectAutomatically:attemptLimit:withDelay:maximumDelay:timeout:withTransports:response:` - `reconnectAutomatically` whether to reconnect automatically (`YES`) - `attemptLimit` number of times to attempt a reconnect (Infinite) - `reconnectionDelay` how long to wait before attempting a new reconnection (`1`) - `maximumDelay` maximum amount of time to wait between reconnections (`5`). Each attempt increases the reconnection by the amount specified by `reconnectionDelay`. - `timeout` connection timeout before an `onReconnectionError` event is emitted (`20`) - `withTransports` specifies an array of transports for engine.io (default is 'polling', 'websocket'). ## Properties #### `void (^onConnect)()` Called upon connecting. #### `void (^onDisconnect)()` Called upon a disconnection. #### `void (^onError)(NSDictionary *errorInfo)` Called upon a connection error. #### `void (^onReconnect)(NSInteger numberOfAttempts)` Called upon a successful reconnection. #### `void (^onReconnectionAttempt)(NSInteger numberOfAttempts)` Called upon an attempt to reconnect. #### `void (^onReconnectionError)(NSDictionary *errorInfo)` Called upon a reconnection attempt error. ## Responders #### `-(void)on:callback:` Binds the given `void (^)(SIOParameterArray *)` block, `function`, to the given `event`. `function` is called upon a firing of `event`. ## Emitters #### `-(void)emit:args:` Fires the given `event` with then given SIOParameterArray as arguments. ## License MIT ================================================ FILE: Carthage/Checkouts/SIOSocket/SIOSocket.podspec ================================================ Pod::Spec.new do |s| s.name = "SIOSocket" s.version = "0.2.2" s.summary = "Realtime iOS application framework (client) http://socket.io" s.license = "MIT" s.source = { :tag => "v0.2.2", :git => "https://github.com/MegaBits/SIOSocket.git"} s.platform = :ios, "7.0" s.source_files = "SocketIO/Source/*.{h,m}" s.requires_arc = true s.homepage = "https://github.com/MegaBits/SIOSocket" s.authors = { "Patrick Perini" => "pperini@megabitsapp.com" } end ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIO/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier com.megabits.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIO/SocketIO.m ================================================ // // SocketIO.m // SocketIO // // Created by Patrick Perini on 6/13/14. // // #import #import "SIOSocket.h" @interface SocketIO : XCTestCase @end @implementation SocketIO - (void)testConnectToLocalhost { XCTestExpectation *connectionExpectation = [self expectationWithDescription: @"should connect to localhost"]; [SIOSocket socketWithHost: @"http://localhost:3000" response: ^(SIOSocket *socket) { XCTAssertNotNil(socket, @"socket could not connect to localhost"); [connectionExpectation fulfill]; }]; [self waitForExpectationsWithTimeout: 10 handler: nil]; } - (void)testFalse { XCTestExpectation *falseExpectation = [self expectationWithDescription: @"should work with false"]; [SIOSocket socketWithHost: @"http://localhost:3000" response: ^(SIOSocket *socket) { XCTAssertNotNil(socket, @"socket could not connect to localhost"); [socket on: @"false" callback: ^(SIOParameterArray *args) { XCTAssertFalse([[args firstObject] boolValue], @"response not false"); [falseExpectation fulfill]; }]; [socket emit: @"false"]; }]; [self waitForExpectationsWithTimeout: 10 handler: nil]; } - (void)testUTF8MultibyteCharacters { XCTestExpectation *utf8MultibyteCharactersExpectation = [self expectationWithDescription: @"should work with utf8 multibyte characters"]; NSArray *correctStrings = @[ @"てすと", @"Я Б Г Д Ж Й", @"Ä ä Ü ü ß", @"utf8 — string", @"utf8 — string" ]; [SIOSocket socketWithHost: @"http://localhost:3000" response: ^(SIOSocket *socket) { XCTAssertNotNil(socket, @"socket could not connect to localhost"); __block NSInteger numberOfCorrectStrings = 0; [socket on: @"takeUtf8" callback: ^(SIOParameterArray *args) { NSString *string = [args firstObject]; XCTAssertEqualObjects(string, correctStrings[numberOfCorrectStrings], @"%@ is not equal to %@", string, correctStrings); numberOfCorrectStrings++; if (numberOfCorrectStrings == [correctStrings count]) { [utf8MultibyteCharactersExpectation fulfill]; } }]; [socket emit: @"getUtf8"]; }]; [self waitForExpectationsWithTimeout: 10 handler: nil]; } - (void)testEmitDateAsString { XCTestExpectation *stringExpectation = [self expectationWithDescription: @"should emit date as a string"]; [SIOSocket socketWithHost: @"http://localhost:3000" response: ^(SIOSocket *socket) { XCTAssertNotNil(socket, @"socket could not connect to localhost"); [socket on: @"takeDate" callback: ^(SIOParameterArray *args) { NSString *string = [args firstObject]; XCTAssert([string isKindOfClass: [NSString class]], @"%@ is not a string", string); [stringExpectation fulfill]; }]; [socket emit: @"getDate"]; }]; [self waitForExpectationsWithTimeout: 10 handler: nil]; } - (void)testEmitDateAsObject { XCTestExpectation *stringExpectation = [self expectationWithDescription: @"should emit date as a string"]; [SIOSocket socketWithHost: @"http://localhost:3000" response: ^(SIOSocket *socket) { XCTAssertNotNil(socket, @"socket could not connect to localhost"); [socket on: @"takeDateObj" callback: ^(SIOParameterArray *args) { NSDictionary *dictionary = [args firstObject]; XCTAssert([dictionary isKindOfClass: [NSDictionary class]], @"%@ is not a dictionary", dictionary); XCTAssert([[dictionary objectForKey: @"date"] isKindOfClass: [NSString class]], @"%@['date'] is not a string", dictionary); [stringExpectation fulfill]; }]; [socket emit: @"getDateObj"]; }]; [self waitForExpectationsWithTimeout: 10 handler: nil]; } - (void)testEmitMultiWord { XCTestExpectation *stringExpectation = [self expectationWithDescription: @"should emit multi word"]; [SIOSocket socketWithHost: @"http://localhost:3000" response: ^(SIOSocket *socket) { XCTAssertNotNil(socket, @"socket could not connect to localhost"); [socket on: @"multi word" callback: ^(SIOParameterArray *args) { NSString *response = [args firstObject]; XCTAssert([response isEqualToString: @"word"], @"%@ != 'word'", response); [stringExpectation fulfill]; }]; [socket emit: @"multi word"]; }]; [self waitForExpectationsWithTimeout: 10 handler: nil]; } - (void)testEmitMultiWordWithCharacters { XCTestExpectation *stringExpectation = [self expectationWithDescription: @"should emit multi word"]; [SIOSocket socketWithHost: @"http://localhost:3000" response: ^(SIOSocket *socket) { XCTAssertNotNil(socket, @"socket could not connect to localhost"); [socket on: @"multi-word" callback: ^(SIOParameterArray *args) { NSString *response = [args firstObject]; XCTAssert([response isEqualToString: @"word"], @"%@ != 'word'", response); [stringExpectation fulfill]; }]; [socket emit: @"multi-word"]; }]; [self waitForExpectationsWithTimeout: 10 handler: nil]; } - (void)testBinaryData { XCTestExpectation *blobExpectation = [self expectationWithDescription: @"should send binary data as Blob"]; [SIOSocket socketWithHost: @"http://localhost:3000" response: ^(SIOSocket *socket) { XCTAssertNotNil(socket, @"socket could not conenct to localhost"); [socket on: @"back" callback: ^(SIOParameterArray *args) { [blobExpectation fulfill]; }]; [socket emit: @"blob" args: @[[@"hello world" dataUsingEncoding: NSUTF8StringEncoding]]]; }]; [self waitForExpectationsWithTimeout: 10 handler: nil]; } @end ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIO/Source/SIOSocket.h ================================================ // // Socket.h // SocketIO // // Created by Patrick Perini on 6/13/14. // // #import // NSArray of these JSValue-valid objects: typedef NSArray SIOParameterArray; // -------------------- // NSNull // NSString // NSNumber // NSDictionary // NSArray // NSData // -------------------- @interface SIOSocket : NSObject // Generators + (void)socketWithHost:(NSString *)hostURL response:(void(^)(SIOSocket *socket))response; + (void)socketWithHost:(NSString *)hostURL reconnectAutomatically:(BOOL)reconnectAutomatically attemptLimit:(NSInteger)attempts withDelay:(NSTimeInterval)reconnectionDelay maximumDelay:(NSTimeInterval)maximumDelay timeout:(NSTimeInterval)timeout response:(void(^)(SIOSocket *socket))response; + (void)socketWithHost:(NSString *)hostURL reconnectAutomatically:(BOOL)reconnectAutomatically attemptLimit:(NSInteger)attempts withDelay:(NSTimeInterval)reconnectionDelay maximumDelay:(NSTimeInterval)maximumDelay timeout:(NSTimeInterval)timeout withTransports:(NSArray *)transports response:(void(^)(SIOSocket *socket))response; // Event responders @property (nonatomic, copy) void (^onConnect)(); @property (nonatomic, copy) void (^onConnectError)(NSDictionary *errorInfo); @property (nonatomic, copy) void (^onDisconnect)(); @property (nonatomic, copy) void (^onError)(NSDictionary *errorInfo); @property (nonatomic, copy) void (^onReconnect)(NSInteger numberOfAttempts); @property (nonatomic, copy) void (^onReconnectionAttempt)(NSInteger numberOfAttempts); @property (nonatomic, copy) void (^onReconnectionError)(NSDictionary *errorInfo); - (void)on:(NSString *)event callback:(void (^)(SIOParameterArray *args))function; // Emitters - (void)emit:(NSString *)event; - (void)emit:(NSString *)event args:(SIOParameterArray *)args; - (void)close; @end ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIO/Source/SIOSocket.m ================================================ // // Socket.m // SocketIO // // Created by Patrick Perini on 6/13/14. // // #import "SIOSocket.h" #import #import "socket.io.js.h" #import #ifdef __IPHONE_8_0 #import #endif static NSString *SIOMD5(NSString *string) { const char *cstr = [string UTF8String]; unsigned char result[16]; CC_MD5(cstr, (unsigned int)strlen(cstr), result); return [NSString stringWithFormat: @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7], result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15] ]; }; @interface SIOSocket () @property (nonatomic, strong) NSThread *thread; @property UIWebView *javascriptWebView; @property (readonly) JSContext *javascriptContext; @end @implementation SIOSocket // Generators + (void)socketWithHost:(NSString *)hostURL response:(void (^)(SIOSocket *))response { // Defaults documented with socket.io-client: https://github.com/Automattic/socket.io-client return [self socketWithHost: hostURL reconnectAutomatically: YES attemptLimit: -1 withDelay: 1 maximumDelay: 5 timeout: 20 response: response]; } + (void)socketWithHost:(NSString *)hostURL reconnectAutomatically:(BOOL)reconnectAutomatically attemptLimit:(NSInteger)attempts withDelay:(NSTimeInterval)reconnectionDelay maximumDelay:(NSTimeInterval)maximumDelay timeout:(NSTimeInterval)timeout response:(void (^)(SIOSocket *))response { return [self socketWithHost: hostURL reconnectAutomatically: YES attemptLimit: -1 withDelay: 1 maximumDelay: 5 timeout: 20 withTransports: @[ @"polling", @"websocket" ] response: response]; } + (void)socketWithHost:(NSString *)hostURL reconnectAutomatically:(BOOL)reconnectAutomatically attemptLimit:(NSInteger)attempts withDelay:(NSTimeInterval)reconnectionDelay maximumDelay:(NSTimeInterval)maximumDelay timeout:(NSTimeInterval)timeout withTransports:(NSArray*)transports response:(void (^)(SIOSocket *))response { SIOSocket *socket = [[SIOSocket alloc] init]; if (!socket) { dispatch_async(dispatch_get_main_queue(), ^{ response(nil); }); return; } socket.javascriptWebView = [[UIWebView alloc] init]; [socket.javascriptContext setExceptionHandler: ^(JSContext *context, JSValue *errorValue) { NSLog(@"JSError: %@", errorValue); NSLog(@"%@", [NSThread callStackSymbols]); }]; socket.javascriptContext[@"window"][@"onload"] = ^() { socket.thread = [NSThread currentThread]; [socket.javascriptContext evaluateScript: socket_io_js]; [socket.javascriptContext evaluateScript: blob_factory_js]; NSString *socketConstructor = socket_io_js_constructor(hostURL, reconnectAutomatically, attempts, reconnectionDelay, maximumDelay, timeout, transports ); socket.javascriptContext[@"objc_socket"] = [socket.javascriptContext evaluateScript: socketConstructor]; if (![socket.javascriptContext[@"objc_socket"] toObject]) { dispatch_async(dispatch_get_main_queue(), ^{ response(nil); }); } // Responders __weak typeof(socket) weakSocket = socket; socket.javascriptContext[@"objc_onConnect"] = ^() { dispatch_async(dispatch_get_main_queue(), ^{ if (weakSocket.onConnect) weakSocket.onConnect(); }); }; socket.javascriptContext[@"objc_onConnectError"] = ^(NSDictionary *errorDictionary) { dispatch_async(dispatch_get_main_queue(), ^{ if (weakSocket.onConnectError) weakSocket.onConnectError(errorDictionary); }); }; socket.javascriptContext[@"objc_onDisconnect"] = ^() { dispatch_async(dispatch_get_main_queue(), ^{ if (weakSocket.onDisconnect) weakSocket.onDisconnect(); }); }; socket.javascriptContext[@"objc_onError"] = ^(NSDictionary *errorDictionary) { dispatch_async(dispatch_get_main_queue(), ^{ if (weakSocket.onError) weakSocket.onError(errorDictionary); }); }; socket.javascriptContext[@"objc_onReconnect"] = ^(NSInteger numberOfAttempts) { dispatch_async(dispatch_get_main_queue(), ^{ if (weakSocket.onReconnect) weakSocket.onReconnect(numberOfAttempts); }); }; socket.javascriptContext[@"objc_onReconnectionAttempt"] = ^(NSInteger numberOfAttempts) { dispatch_async(dispatch_get_main_queue(), ^{ if (weakSocket.onReconnectionAttempt) weakSocket.onReconnectionAttempt(numberOfAttempts); }); }; socket.javascriptContext[@"objc_onReconnectionError"] = ^(NSDictionary *errorDictionary) { dispatch_async(dispatch_get_main_queue(), ^{ if (weakSocket.onReconnectionError) weakSocket.onReconnectionError(errorDictionary); }); }; [socket.javascriptContext evaluateScript: @"objc_socket.on('connect', objc_onConnect);"]; [socket.javascriptContext evaluateScript: @"objc_socket.on('error', objc_onError);"]; [socket.javascriptContext evaluateScript: @"objc_socket.on('disconnect', objc_onDisconnect);"]; [socket.javascriptContext evaluateScript: @"objc_socket.on('reconnect', objc_onReconnect);"]; [socket.javascriptContext evaluateScript: @"objc_socket.on('reconnecting', objc_onReconnectionAttempt);"]; [socket.javascriptContext evaluateScript: @"objc_socket.on('reconnect_error', objc_onReconnectionError);"]; dispatch_async(dispatch_get_main_queue(), ^{ response(socket); }); }; [socket.javascriptWebView loadHTMLString: @"" baseURL: nil]; } - (void)dealloc { [self close]; } // Accessors - (JSContext *)javascriptContext { return [self.javascriptWebView valueForKeyPath: @"documentView.webView.mainFrame.javaScriptContext"]; } // Event listeners - (void)on:(NSString *)event callback:(void (^)(SIOParameterArray *args))function { NSString *eventID = SIOMD5(event); self.javascriptContext[[NSString stringWithFormat: @"objc_%@", eventID]] = ^() { NSMutableArray *arguments = [NSMutableArray array]; for (JSValue *object in [JSContext currentArguments]) { if ([object toObject]) { [arguments addObject: [object toObject]]; } } dispatch_async(dispatch_get_main_queue(), ^{ function(arguments); }); }; NSString* script = [NSString stringWithFormat: @"objc_socket.on('%@', objc_%@);", event, eventID]; [self performSelector:@selector(evaluateScript:) onThread:_thread withObject:[script copy] waitUntilDone:NO]; } // Emitters - (void)emit:(NSString *)event { [self emit: event args: nil]; } - (void)emit:(NSString *)event args:(SIOParameterArray *)args { NSMutableArray *arguments = [NSMutableArray arrayWithObject: [NSString stringWithFormat: @"'%@'", event]]; for (id arg in args) { if ([arg isKindOfClass: [NSNull class]]) { [arguments addObject: @"null"]; } else if ([arg isKindOfClass: [NSString class]]) { [arguments addObject: [NSString stringWithFormat: @"'%@'", arg]]; } else if ([arg isKindOfClass: [NSNumber class]]) { [arguments addObject: [NSString stringWithFormat: @"%@", arg]]; } else if ([arg isKindOfClass: [NSData class]]) { NSString *dataString = [[NSString alloc] initWithData: arg encoding: NSUTF8StringEncoding]; [arguments addObject: [NSString stringWithFormat: @"blob('%@')", dataString]]; } else if ([arg isKindOfClass: [NSArray class]] || [arg isKindOfClass: [NSDictionary class]]) { if ([NSJSONSerialization isValidJSONObject:arg]) { [arguments addObject: [[NSString alloc] initWithData: [NSJSONSerialization dataWithJSONObject: arg options: 0 error: nil] encoding: NSUTF8StringEncoding]]; } else { NSLog(@"SIOSocket serialization error at %@", NSStringFromSelector(_cmd)); } } } NSString* script = [NSString stringWithFormat: @"objc_socket.emit(%@);", [arguments componentsJoinedByString: @", "]]; [self performSelector:@selector(evaluateScript:) onThread:_thread withObject:[script copy] waitUntilDone:NO]; } - (void)evaluateScript:(NSString *)script { [self.javascriptContext evaluateScript:script]; } - (void)close { [self.javascriptWebView loadRequest: [NSURLRequest requestWithURL: [NSURL URLWithString: @"about:blank"]]]; [self.javascriptWebView reload]; self.javascriptWebView = nil; } @end ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIO/Source/socket.io.js.h ================================================ // // socket.io.js.h // SocketIO // // Created by Patrick Perini on 6/13/14. // // #import #define MSEC_PER_SEC 1000 /*! * Complete socket.io-1.2.1.js, minified. */ static NSString *const socket_io_js = @"!function(e){if(\"object\"==typeof exports&&\"undefined\"!=typeof module)module.exports=e();else if(\"function\"==typeof define&&define.amd)define([],e);else{var f;\"undefined\"!=typeof window?f=window:\"undefined\"!=typeof global?f=global:\"undefined\"!=typeof self&&(f=self),f.io=e()}}(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error(\"Cannot find module '\"+o+\"'\")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o0&&!this.encoding){var pack=this.packetBuffer.shift();this.packet(pack)}};Manager.prototype.cleanup=function(){var sub;while(sub=this.subs.shift())sub.destroy();this.packetBuffer=[];this.encoding=false;this.decoder.destroy()};Manager.prototype.close=Manager.prototype.disconnect=function(){this.skipReconnect=true;this.readyState=\"closed\";this.engine&&this.engine.close()};Manager.prototype.onclose=function(reason){debug(\"close\");this.cleanup();this.readyState=\"closed\";this.emit(\"close\",reason);if(this._reconnection&&!this.skipReconnect){this.reconnect()}};Manager.prototype.reconnect=function(){if(this.reconnecting||this.skipReconnect)return this;var self=this;this.attempts++;if(this.attempts>this._reconnectionAttempts){debug(\"reconnect failed\");this.emitAll(\"reconnect_failed\");this.reconnecting=false}else{var delay=this.attempts*this.reconnectionDelay();delay=Math.min(delay,this.reconnectionDelayMax());debug(\"will wait %dms before reconnect attempt\",delay);this.reconnecting=true;var timer=setTimeout(function(){if(self.skipReconnect)return;debug(\"attempting reconnect\");self.emitAll(\"reconnect_attempt\",self.attempts);self.emitAll(\"reconnecting\",self.attempts);if(self.skipReconnect)return;self.open(function(err){if(err){debug(\"reconnect attempt error\");self.reconnecting=false;self.reconnect();self.emitAll(\"reconnect_error\",err.data)}else{debug(\"reconnect success\");self.onreconnect()}})},delay);this.subs.push({destroy:function(){clearTimeout(timer)}})}};Manager.prototype.onreconnect=function(){var attempt=this.attempts;this.attempts=0;this.reconnecting=false;this.emitAll(\"reconnect\",attempt)}},{\"./on\":4,\"./socket\":5,\"./url\":6,\"component-bind\":7,\"component-emitter\":8,debug:9,\"engine.io-client\":10,indexof:39,\"object-component\":40,\"socket.io-parser\":43}],4:[function(_dereq_,module,exports){module.exports=on;function on(obj,ev,fn){obj.on(ev,fn);return{destroy:function(){obj.removeListener(ev,fn)}}}},{}],5:[function(_dereq_,module,exports){var parser=_dereq_(\"socket.io-parser\");var Emitter=_dereq_(\"component-emitter\");var toArray=_dereq_(\"to-array\");var on=_dereq_(\"./on\");var bind=_dereq_(\"component-bind\");var debug=_dereq_(\"debug\")(\"socket.io-client:socket\");var hasBin=_dereq_(\"has-binary\");module.exports=exports=Socket;var events={connect:1,connect_error:1,connect_timeout:1,disconnect:1,error:1,reconnect:1,reconnect_attempt:1,reconnect_failed:1,reconnect_error:1,reconnecting:1};var emit=Emitter.prototype.emit;function Socket(io,nsp){this.io=io;this.nsp=nsp;this.json=this;this.ids=0;this.acks={};if(this.io.autoConnect)this.open();this.receiveBuffer=[];this.sendBuffer=[];this.connected=false;this.disconnected=true}Emitter(Socket.prototype);Socket.prototype.subEvents=function(){if(this.subs)return;var io=this.io;this.subs=[on(io,\"open\",bind(this,\"onopen\")),on(io,\"packet\",bind(this,\"onpacket\")),on(io,\"close\",bind(this,\"onclose\"))]};Socket.prototype.open=Socket.prototype.connect=function(){if(this.connected)return this;this.subEvents();this.io.open();if(\"open\"==this.io.readyState)this.onopen();return this};Socket.prototype.send=function(){var args=toArray(arguments);args.unshift(\"message\");this.emit.apply(this,args);return this};Socket.prototype.emit=function(ev){if(events.hasOwnProperty(ev)){emit.apply(this,arguments);return this}var args=toArray(arguments);var parserType=parser.EVENT;if(hasBin(args)){parserType=parser.BINARY_EVENT}var packet={type:parserType,data:args};if(\"function\"==typeof args[args.length-1]){debug(\"emitting packet with ack id %d\",this.ids);this.acks[this.ids]=args.pop();packet.id=this.ids++}if(this.connected){this.packet(packet)}else{this.sendBuffer.push(packet)}return this};Socket.prototype.packet=function(packet){packet.nsp=this.nsp;this.io.packet(packet)};Socket.prototype.onopen=function(){debug(\"transport is open - connecting\");if(\"/\"!=this.nsp){this.packet({type:parser.CONNECT})}};Socket.prototype.onclose=function(reason){debug(\"close (%s)\",reason);this.connected=false;this.disconnected=true;this.emit(\"disconnect\",reason)};Socket.prototype.onpacket=function(packet){if(packet.nsp!=this.nsp)return;switch(packet.type){case parser.CONNECT:this.onconnect();break;case parser.EVENT:this.onevent(packet);break;case parser.BINARY_EVENT:this.onevent(packet);break;case parser.ACK:this.onack(packet);break;case parser.BINARY_ACK:this.onack(packet);break;case parser.DISCONNECT:this.ondisconnect();break;case parser.ERROR:this.emit(\"error\",packet.data);break}};Socket.prototype.onevent=function(packet){var args=packet.data||[];debug(\"emitting event %j\",args);if(null!=packet.id){debug(\"attaching ack callback to event\");args.push(this.ack(packet.id))}if(this.connected){emit.apply(this,args)}else{this.receiveBuffer.push(args)}};Socket.prototype.ack=function(id){var self=this;var sent=false;return function(){if(sent)return;sent=true;var args=toArray(arguments);debug(\"sending ack %j\",args);var type=hasBin(args)?parser.BINARY_ACK:parser.ACK;self.packet({type:type,id:id,data:args})}};Socket.prototype.onack=function(packet){debug(\"calling ack %s with %j\",packet.id,packet.data);var fn=this.acks[packet.id];fn.apply(this,packet.data);delete this.acks[packet.id]};Socket.prototype.onconnect=function(){this.connected=true;this.disconnected=false;this.emit(\"connect\");this.emitBuffered()};Socket.prototype.emitBuffered=function(){var i;for(i=0;i=hour)return(ms/hour).toFixed(1)+\"h\";if(ms>=min)return(ms/min).toFixed(1)+\"m\";if(ms>=sec)return(ms/sec|0)+\"s\";return ms+\"ms\"};debug.enabled=function(name){for(var i=0,len=debug.skips.length;i';iframe=document.createElement(html)}catch(e){iframe=document.createElement(\"iframe\");iframe.name=self.iframeId;iframe.src=\"javascript:0\"}iframe.id=self.iframeId;self.form.appendChild(iframe);self.iframe=iframe}initIframe();data=data.replace(rEscapedNewline,\"\\\\\\n\");this.area.value=data.replace(rNewline,\"\\\\n\");try{this.form.submit()}catch(e){}if(this.iframe.attachEvent){this.iframe.onreadystatechange=function(){if(self.iframe.readyState==\"complete\"){complete()}}}else{this.iframe.onload=complete}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./polling\":17,\"component-inherit\":20}],16:[function(_dereq_,module,exports){(function(global){var XMLHttpRequest=_dereq_(\"xmlhttprequest\");var Polling=_dereq_(\"./polling\");var Emitter=_dereq_(\"component-emitter\");var inherit=_dereq_(\"component-inherit\");var debug=_dereq_(\"debug\")(\"engine.io-client:polling-xhr\");module.exports=XHR;module.exports.Request=Request;function empty(){}function XHR(opts){Polling.call(this,opts);if(global.location){var isSSL=\"https:\"==location.protocol;var port=location.port;if(!port){port=isSSL?443:80}this.xd=opts.hostname!=global.location.hostname||port!=opts.port;this.xs=opts.secure!=isSSL}}inherit(XHR,Polling);XHR.prototype.supportsBinary=true;XHR.prototype.request=function(opts){opts=opts||{};opts.uri=this.uri();opts.xd=this.xd;opts.xs=this.xs;opts.agent=this.agent||false;opts.supportsBinary=this.supportsBinary;opts.enablesXDR=this.enablesXDR;return new Request(opts)};XHR.prototype.doWrite=function(data,fn){var isBinary=typeof data!==\"string\"&&data!==undefined;var req=this.request({method:\"POST\",data:data,isBinary:isBinary});var self=this;req.on(\"success\",fn);req.on(\"error\",function(err){self.onError(\"xhr post error\",err)});this.sendXhr=req};XHR.prototype.doPoll=function(){debug(\"xhr poll\");var req=this.request();var self=this;req.on(\"data\",function(data){self.onData(data)});req.on(\"error\",function(err){self.onError(\"xhr poll error\",err)});this.pollXhr=req};function Request(opts){this.method=opts.method||\"GET\";this.uri=opts.uri;this.xd=!!opts.xd;this.xs=!!opts.xs;this.async=false!==opts.async;this.data=undefined!=opts.data?opts.data:null;this.agent=opts.agent;this.isBinary=opts.isBinary;this.supportsBinary=opts.supportsBinary;this.enablesXDR=opts.enablesXDR;this.create()}Emitter(Request.prototype);Request.prototype.create=function(){var xhr=this.xhr=new XMLHttpRequest({agent:this.agent,xdomain:this.xd,xscheme:this.xs,enablesXDR:this.enablesXDR});var self=this;try{debug(\"xhr open %s: %s\",this.method,this.uri);xhr.open(this.method,this.uri,this.async);if(this.supportsBinary){xhr.responseType=\"arraybuffer\"}if(\"POST\"==this.method){try{if(this.isBinary){xhr.setRequestHeader(\"Content-type\",\"application/octet-stream\")}else{xhr.setRequestHeader(\"Content-type\",\"text/plain;charset=UTF-8\")}}catch(e){}}if(\"withCredentials\"in xhr){xhr.withCredentials=true}if(this.hasXDR()){xhr.onload=function(){self.onLoad()};xhr.onerror=function(){self.onError(xhr.responseText)}}else{xhr.onreadystatechange=function(){if(4!=xhr.readyState)return;if(200==xhr.status||1223==xhr.status){self.onLoad()}else{setTimeout(function(){self.onError(xhr.status)},0)}}}debug(\"xhr data %s\",this.data);xhr.send(this.data)}catch(e){setTimeout(function(){self.onError(e)},0);return}if(global.document){this.index=Request.requestsCount++;Request.requests[this.index]=this}};Request.prototype.onSuccess=function(){this.emit(\"success\");this.cleanup()};Request.prototype.onData=function(data){this.emit(\"data\",data);this.onSuccess()};Request.prototype.onError=function(err){this.emit(\"error\",err);this.cleanup()};Request.prototype.cleanup=function(){if(\"undefined\"==typeof this.xhr||null===this.xhr){return}if(this.hasXDR()){this.xhr.onload=this.xhr.onerror=empty}else{this.xhr.onreadystatechange=empty}try{this.xhr.abort()}catch(e){}if(global.document){delete Request.requests[this.index]}this.xhr=null};Request.prototype.onLoad=function(){var data;try{var contentType;try{contentType=this.xhr.getResponseHeader(\"Content-Type\").split(\";\")[0]}catch(e){}if(contentType===\"application/octet-stream\"){data=this.xhr.response}else{if(!this.supportsBinary){data=this.xhr.responseText}else{data=\"ok\"}}}catch(e){this.onError(e)}if(null!=data){this.onData(data)}};Request.prototype.hasXDR=function(){return\"undefined\"!==typeof global.XDomainRequest&&!this.xs&&this.enablesXDR};Request.prototype.abort=function(){this.cleanup()};if(global.document){Request.requestsCount=0;Request.requests={};if(global.attachEvent){global.attachEvent(\"onunload\",unloadHandler)}else if(global.addEventListener){global.addEventListener(\"beforeunload\",unloadHandler,false)}}function unloadHandler(){for(var i in Request.requests){if(Request.requests.hasOwnProperty(i)){Request.requests[i].abort()}}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{\"./polling\":17,\"component-emitter\":8,\"component-inherit\":20,debug:21,xmlhttprequest:19}],17:[function(_dereq_,module,exports){var Transport=_dereq_(\"../transport\");var parseqs=_dereq_(\"parseqs\");var parser=_dereq_(\"engine.io-parser\");var inherit=_dereq_(\"component-inherit\");var debug=_dereq_(\"debug\")(\"engine.io-client:polling\");module.exports=Polling;var hasXHR2=function(){var XMLHttpRequest=_dereq_(\"xmlhttprequest\");var xhr=new XMLHttpRequest({xdomain:false});return null!=xhr.responseType}();function Polling(opts){var forceBase64=opts&&opts.forceBase64;if(!hasXHR2||forceBase64){this.supportsBinary=false}Transport.call(this,opts)}inherit(Polling,Transport);Polling.prototype.name=\"polling\";Polling.prototype.doOpen=function(){this.poll()};Polling.prototype.pause=function(onPause){var pending=0;var self=this;this.readyState=\"pausing\";function pause(){debug(\"paused\");self.readyState=\"paused\";onPause()}if(this.polling||!this.writable){var total=0;if(this.polling){debug(\"we are currently polling - waiting to pause\");total++;this.once(\"pollComplete\",function(){debug(\"pre-pause polling complete\");--total||pause()})}if(!this.writable){debug(\"we are currently writing - waiting to pause\");total++;this.once(\"drain\",function(){debug(\"pre-pause writing complete\");--total||pause()})}}else{pause()}};Polling.prototype.poll=function(){debug(\"polling\");this.polling=true;this.doPoll();this.emit(\"poll\")};Polling.prototype.onData=function(data){var self=this;debug(\"polling got data %s\",data);var callback=function(packet,index,total){if(\"opening\"==self.readyState){self.onOpen()}if(\"close\"==packet.type){self.onClose();return false}self.onPacket(packet)};parser.decodePayload(data,this.socket.binaryType,callback);if(\"closed\"!=this.readyState){this.polling=false;this.emit(\"pollComplete\");if(\"open\"==this.readyState){this.poll()}else{debug('ignoring poll - transport state \"%s\"',this.readyState)}}};Polling.prototype.doClose=function(){var self=this;function close(){debug(\"writing close packet\");self.write([{type:\"close\"}])}if(\"open\"==this.readyState){debug(\"transport open - closing\");close()}else{debug(\"transport not open - deferring close\");this.once(\"open\",close)}};Polling.prototype.write=function(packets){var self=this;this.writable=false;var callbackfn=function(){self.writable=true;self.emit(\"drain\")};var self=this;parser.encodePayload(packets,this.supportsBinary,function(data){self.doWrite(data,callbackfn)})};Polling.prototype.uri=function(){var query=this.query||{};var schema=this.secure?\"https\":\"http\";var port=\"\";if(false!==this.timestampRequests){query[this.timestampParam]=+new Date+\"-\"+Transport.timestamps++}if(!this.supportsBinary&&!query.sid){query.b64=1}query=parseqs.encode(query);if(this.port&&(\"https\"==schema&&this.port!=443||\"http\"==schema&&this.port!=80)){port=\":\"+this.port}if(query.length){query=\"?\"+query}return schema+\"://\"+this.hostname+port+this.path+query}},{\"../transport\":13,\"component-inherit\":20,debug:21,\"engine.io-parser\":24,parseqs:32,xmlhttprequest:19}],18:[function(_dereq_,module,exports){var Transport=_dereq_(\"../transport\");var parser=_dereq_(\"engine.io-parser\");var parseqs=_dereq_(\"parseqs\");var inherit=_dereq_(\"component-inherit\");var debug=_dereq_(\"debug\")(\"engine.io-client:websocket\");var WebSocket=_dereq_(\"ws\");module.exports=WS;function WS(opts){var forceBase64=opts&&opts.forceBase64;if(forceBase64){this.supportsBinary=false}Transport.call(this,opts)}inherit(WS,Transport);WS.prototype.name=\"websocket\";WS.prototype.supportsBinary=true;WS.prototype.doOpen=function(){if(!this.check()){return}var self=this;var uri=this.uri();var protocols=void 0;var opts={agent:this.agent};this.ws=new WebSocket(uri,protocols,opts);if(this.ws.binaryType===undefined){this.supportsBinary=false}this.ws.binaryType=\"arraybuffer\";this.addEventListeners()};WS.prototype.addEventListeners=function(){var self=this;this.ws.onopen=function(){self.onOpen()};this.ws.onclose=function(){self.onClose()};this.ws.onmessage=function(ev){self.onData(ev.data)};this.ws.onerror=function(e){self.onError(\"websocket error\",e)}};if(\"undefined\"!=typeof navigator&&/iPad|iPhone|iPod/i.test(navigator.userAgent)){WS.prototype.onData=function(data){var self=this;setTimeout(function(){Transport.prototype.onData.call(self,data)},0)}}WS.prototype.write=function(packets){var self=this;this.writable=false;for(var i=0,l=packets.length;i=31}exports.formatters.j=function(v){return JSON.stringify(v)};function formatArgs(){var args=arguments;var useColors=this.useColors;args[0]=(useColors?\"%c\":\"\")+this.namespace+(useColors?\" %c\":\" \")+args[0]+(useColors?\"%c \":\" \")+\"+\"+exports.humanize(this.diff);if(!useColors)return args;var c=\"color: \"+this.color;args=[args[0],c,\"color: inherit\"].concat(Array.prototype.slice.call(args,1));var index=0;var lastC=0;args[0].replace(/%[a-z%]/g,function(match){if(\"%\"===match)return;index++;if(\"%c\"===match){lastC=index}});args.splice(lastC,0,c);return args}function log(){return\"object\"==typeof console&&\"function\"==typeof console.log&&Function.prototype.apply.call(console.log,console,arguments)}function save(namespaces){try{if(null==namespaces){localStorage.removeItem(\"debug\")}else{localStorage.debug=namespaces}}catch(e){}}function load(){var r;try{r=localStorage.debug}catch(e){}return r}exports.enable(load())},{\"./debug\":22}],22:[function(_dereq_,module,exports){exports=module.exports=debug;exports.coerce=coerce;exports.disable=disable;exports.enable=enable;exports.enabled=enabled;exports.humanize=_dereq_(\"ms\");exports.names=[];exports.skips=[];exports.formatters={};var prevColor=0;var prevTime;function selectColor(){return exports.colors[prevColor++%exports.colors.length]}function debug(namespace){function disabled(){}disabled.enabled=false;function enabled(){var self=enabled;var curr=+new Date;var ms=curr-(prevTime||curr);self.diff=ms;self.prev=prevTime;self.curr=curr;prevTime=curr;if(null==self.useColors)self.useColors=exports.useColors();if(null==self.color&&self.useColors)self.color=selectColor();var args=Array.prototype.slice.call(arguments);args[0]=exports.coerce(args[0]);if(\"string\"!==typeof args[0]){args=[\"%o\"].concat(args)}var index=0;args[0]=args[0].replace(/%([a-z%])/g,function(match,format){if(match===\"%\")return match;index++;var formatter=exports.formatters[format];if(\"function\"===typeof formatter){var val=args[index];match=formatter.call(self,val);args.splice(index,1);index--}return match});if(\"function\"===typeof exports.formatArgs){args=exports.formatArgs.apply(self,args)}var logFn=enabled.log||exports.log||console.log.bind(console);logFn.apply(self,args)}enabled.enabled=true;var fn=exports.enabled(namespace)?enabled:disabled;fn.namespace=namespace;return fn}function enable(namespaces){exports.save(namespaces);var split=(namespaces||\"\").split(/[\\s,]+/);var len=split.length;for(var i=0;i=d)return Math.round(ms/d)+\"d\";if(ms>=h)return Math.round(ms/h)+\"h\";if(ms>=m)return Math.round(ms/m)+\"m\";if(ms>=s)return Math.round(ms/s)+\"s\";return ms+\"ms\"}function long(ms){return plural(ms,d,\"day\")||plural(ms,h,\"hour\")||plural(ms,m,\"minute\")||plural(ms,s,\"second\")||ms+\" ms\"}function plural(ms,n,name){if(ms1){return{type:packetslist[type],data:data.substring(1)}}else{return{type:packetslist[type]}}}var asArray=new Uint8Array(data);var type=asArray[0];var rest=sliceBuffer(data,1);if(Blob&&binaryType===\"blob\"){rest=new Blob([rest])}return{type:packetslist[type],data:rest}};exports.decodeBase64Packet=function(msg,binaryType){var type=packetslist[msg.charAt(0)];if(!global.ArrayBuffer){return{type:type,data:{base64:true,data:msg.substr(1)}}}var data=base64encoder.decode(msg.substr(1));if(binaryType===\"blob\"&&Blob){data=new Blob([data])}return{type:type,data:data}};exports.encodePayload=function(packets,supportsBinary,callback){if(typeof supportsBinary==\"function\"){callback=supportsBinary;supportsBinary=null}if(supportsBinary){if(Blob&&!isAndroid){return exports.encodePayloadAsBlob(packets,callback)}return exports.encodePayloadAsArrayBuffer(packets,callback)}if(!packets.length){return callback(\"0:\")}function setLengthHeader(message){return message.length+\":\"+message}function encodeOne(packet,doneCallback){exports.encodePacket(packet,supportsBinary,true,function(message){doneCallback(null,setLengthHeader(message))})}map(packets,encodeOne,function(err,results){return callback(results.join(\"\"))})};function map(ary,each,done){var result=new Array(ary.length);var next=after(ary.length,done);var eachWithIndex=function(i,el,cb){each(el,function(error,msg){result[i]=msg;cb(error,result)})};for(var i=0;i0){var tailArray=new Uint8Array(bufferTail);var isString=tailArray[0]===0;var msgLength=\"\";for(var i=1;;i++){if(tailArray[i]==255)break;if(msgLength.length>310){numberTooLong=true;break}msgLength+=tailArray[i]}if(numberTooLong)return callback(err,0,1);bufferTail=sliceBuffer(bufferTail,2+msgLength.length);msgLength=parseInt(msgLength);var msg=sliceBuffer(bufferTail,0,msgLength);if(isString){try{msg=String.fromCharCode.apply(null,new Uint8Array(msg))}catch(e){var typed=new Uint8Array(msg);msg=\"\";for(var i=0;ibytes){end=bytes}if(start>=bytes||start>=end||bytes===0){return new ArrayBuffer(0)}var abv=new Uint8Array(arraybuffer);var result=new Uint8Array(end-start);for(var i=start,ii=0;i>2];base64+=chars[(bytes[i]&3)<<4|bytes[i+1]>>4];base64+=chars[(bytes[i+1]&15)<<2|bytes[i+2]>>6];base64+=chars[bytes[i+2]&63]}if(len%3===2){base64=base64.substring(0,base64.length-1)+\"=\"}else if(len%3===1){base64=base64.substring(0,base64.length-2)+\"==\"}return base64};exports.decode=function(base64){var bufferLength=base64.length*.75,len=base64.length,i,p=0,encoded1,encoded2,encoded3,encoded4;if(base64[base64.length-1]===\"=\"){bufferLength--;if(base64[base64.length-2]===\"=\"){bufferLength--}}var arraybuffer=new ArrayBuffer(bufferLength),bytes=new Uint8Array(arraybuffer);for(i=0;i>4;bytes[p++]=(encoded2&15)<<4|encoded3>>2;bytes[p++]=(encoded3&3)<<6|encoded4&63}return arraybuffer}})(\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\")},{}],29:[function(_dereq_,module,exports){(function(global){var BlobBuilder=global.BlobBuilder||global.WebKitBlobBuilder||global.MSBlobBuilder||global.MozBlobBuilder;var blobSupported=function(){try{var b=new Blob([\"hi\"]);return b.size==2}catch(e){return false}}();var blobBuilderSupported=BlobBuilder&&BlobBuilder.prototype.append&&BlobBuilder.prototype.getBlob;function BlobBuilderConstructor(ary,options){options=options||{};var bb=new BlobBuilder;for(var i=0;i=55296&&value<=56319&&counter65535){value-=65536;output+=stringFromCharCode(value>>>10&1023|55296);value=56320|value&1023}output+=stringFromCharCode(value)}return output}function createByte(codePoint,shift){return stringFromCharCode(codePoint>>shift&63|128)}function encodeCodePoint(codePoint){if((codePoint&4294967168)==0){return stringFromCharCode(codePoint)}var symbol=\"\";if((codePoint&4294965248)==0){symbol=stringFromCharCode(codePoint>>6&31|192)}else if((codePoint&4294901760)==0){symbol=stringFromCharCode(codePoint>>12&15|224);symbol+=createByte(codePoint,6)}else if((codePoint&4292870144)==0){symbol=stringFromCharCode(codePoint>>18&7|240);symbol+=createByte(codePoint,12);symbol+=createByte(codePoint,6)}symbol+=stringFromCharCode(codePoint&63|128);return symbol}function utf8encode(string){var codePoints=ucs2decode(string);var length=codePoints.length;var index=-1;var codePoint;var byteString=\"\";while(++index=byteCount){throw Error(\"Invalid byte index\")}var continuationByte=byteArray[byteIndex]&255;byteIndex++;if((continuationByte&192)==128){return continuationByte&63}throw Error(\"Invalid continuation byte\")}function decodeSymbol(){var byte1;var byte2;var byte3;var byte4;var codePoint;if(byteIndex>byteCount){throw Error(\"Invalid byte index\")}if(byteIndex==byteCount){return false}byte1=byteArray[byteIndex]&255;byteIndex++;if((byte1&128)==0){return byte1}if((byte1&224)==192){var byte2=readContinuationByte();codePoint=(byte1&31)<<6|byte2;if(codePoint>=128){return codePoint}else{throw Error(\"Invalid continuation byte\")}}if((byte1&240)==224){byte2=readContinuationByte();byte3=readContinuationByte();codePoint=(byte1&15)<<12|byte2<<6|byte3;if(codePoint>=2048){return codePoint}else{throw Error(\"Invalid continuation byte\")}}if((byte1&248)==240){byte2=readContinuationByte();byte3=readContinuationByte();byte4=readContinuationByte();codePoint=(byte1&15)<<18|byte2<<12|byte3<<6|byte4;if(codePoint>=65536&&codePoint<=1114111){return codePoint}}throw Error(\"Invalid UTF-8 detected\")}var byteArray;var byteCount;var byteIndex;function utf8decode(byteString){byteArray=ucs2decode(byteString);byteCount=byteArray.length;byteIndex=0;var codePoints=[];var tmp;while((tmp=decodeSymbol())!==false){codePoints.push(tmp)}return ucs2encode(codePoints)}var utf8={version:\"2.0.0\",encode:utf8encode,decode:utf8decode};if(typeof define==\"function\"&&typeof define.amd==\"object\"&&define.amd){define(function(){return utf8})}else if(freeExports&&!freeExports.nodeType){if(freeModule){freeModule.exports=utf8}else{var object={};var hasOwnProperty=object.hasOwnProperty;for(var key in utf8){hasOwnProperty.call(utf8,key)&&(freeExports[key]=utf8[key])}}}else{root.utf8=utf8}})(this)}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{}],31:[function(_dereq_,module,exports){(function(global){var rvalidchars=/^[\\],:{}\\s]*$/;var rvalidescape=/\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g;var rvalidtokens=/\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g;var rvalidbraces=/(?:^|:|,)(?:\\s*\\[)+/g;var rtrimLeft=/^\\s+/;var rtrimRight=/\\s+$/;module.exports=function parsejson(data){if(\"string\"!=typeof data||!data){return null}data=data.replace(rtrimLeft,\"\").replace(rtrimRight,\"\");if(global.JSON&&JSON.parse){return JSON.parse(data)}if(rvalidchars.test(data.replace(rvalidescape,\"@\").replace(rvalidtokens,\"]\").replace(rvalidbraces,\"\"))){return new Function(\"return \"+data)()}}}).call(this,typeof self!==\"undefined\"?self:typeof window!==\"undefined\"?window:{})},{}],32:[function(_dereq_,module,exports){exports.encode=function(obj){var str=\"\";for(var i in obj){if(obj.hasOwnProperty(i)){if(str.length)str+=\"&\";str+=encodeURIComponent(i)+\"=\"+encodeURIComponent(obj[i])}}return str};exports.decode=function(qs){var qry={};var pairs=qs.split(\"&\");for(var i=0,l=pairs.length;i1)))/4)-floor((year-1901+month)/100)+floor((year-1601+month)/400)}}if(!(isProperty={}.hasOwnProperty)){isProperty=function(property){var members={},constructor;if((members.__proto__=null,members.__proto__={toString:1},members).toString!=getClass){isProperty=function(property){var original=this.__proto__,result=property in(this.__proto__=null,this);this.__proto__=original;return result}}else{constructor=members.constructor;isProperty=function(property){var parent=(this.constructor||constructor).prototype;return property in this&&!(property in parent&&this[property]===parent[property])}}members=null;return isProperty.call(this,property)}}var PrimitiveTypes={\"boolean\":1,number:1,string:1,undefined:1};var isHostType=function(object,property){var type=typeof object[property];return type==\"object\"?!!object[property]:!PrimitiveTypes[type]};forEach=function(object,callback){var size=0,Properties,members,property;(Properties=function(){this.valueOf=0}).prototype.valueOf=0;members=new Properties;for(property in members){if(isProperty.call(members,property)){size++}}Properties=members=null;if(!size){members=[\"valueOf\",\"toString\",\"toLocaleString\",\"propertyIsEnumerable\",\"isPrototypeOf\",\"hasOwnProperty\",\"constructor\"];forEach=function(object,callback){var isFunction=getClass.call(object)==functionClass,property,length;var hasProperty=!isFunction&&typeof object.constructor!=\"function\"&&isHostType(object,\"hasOwnProperty\")?object.hasOwnProperty:isProperty;for(property in object){if(!(isFunction&&property==\"prototype\")&&hasProperty.call(object,property)){callback(property)}}for(length=members.length;property=members[--length];hasProperty.call(object,property)&&callback(property));}}else if(size==2){forEach=function(object,callback){var members={},isFunction=getClass.call(object)==functionClass,property;for(property in object){if(!(isFunction&&property==\"prototype\")&&!isProperty.call(members,property)&&(members[property]=1)&&isProperty.call(object,property)){callback(property)}}}}else{forEach=function(object,callback){var isFunction=getClass.call(object)==functionClass,property,isConstructor;for(property in object){if(!(isFunction&&property==\"prototype\")&&isProperty.call(object,property)&&!(isConstructor=property===\"constructor\")){callback(property)}}if(isConstructor||isProperty.call(object,property=\"constructor\")){callback(property)}}}return forEach(object,callback)};if(!has(\"json-stringify\")){var Escapes={92:\"\\\\\\\\\",34:'\\\\\"',8:\"\\\\b\",12:\"\\\\f\",10:\"\\\\n\",13:\"\\\\r\",9:\"\\\\t\"};var leadingZeroes=\"000000\";var toPaddedString=function(width,value){return(leadingZeroes+(value||0)).slice(-width)};var unicodePrefix=\"\\\\u00\";var quote=function(value){var result='\"',index=0,length=value.length,isLarge=length>10&&charIndexBuggy,symbols;if(isLarge){symbols=value.split(\"\")}for(;index-1/0&&value<1/0){if(getDay){date=floor(value/864e5);for(year=floor(date/365.2425)+1970-1;getDay(year+1,0)<=date;year++);for(month=floor((date-getDay(year,0))/30.42);getDay(year,month+1)<=date;month++);date=1+date-getDay(year,month);time=(value%864e5+864e5)%864e5;hours=floor(time/36e5)%24;minutes=floor(time/6e4)%60;seconds=floor(time/1e3)%60;milliseconds=time%1e3}else{year=value.getUTCFullYear();month=value.getUTCMonth();date=value.getUTCDate();hours=value.getUTCHours();minutes=value.getUTCMinutes();seconds=value.getUTCSeconds();milliseconds=value.getUTCMilliseconds()}value=(year<=0||year>=1e4?(year<0?\"-\":\"+\")+toPaddedString(6,year<0?-year:year):toPaddedString(4,year))+\"-\"+toPaddedString(2,month+1)+\"-\"+toPaddedString(2,date)+\"T\"+toPaddedString(2,hours)+\":\"+toPaddedString(2,minutes)+\":\"+toPaddedString(2,seconds)+\".\"+toPaddedString(3,milliseconds)+\"Z\"}else{value=null}}else if(typeof value.toJSON==\"function\"&&(className!=numberClass&&className!=stringClass&&className!=arrayClass||isProperty.call(value,\"toJSON\"))){value=value.toJSON(property)}}if(callback){value=callback.call(object,property,value)}if(value===null){return\"null\"}className=getClass.call(value);if(className==booleanClass){return\"\"+value}else if(className==numberClass){return value>-1/0&&value<1/0?\"\"+value:\"null\"}else if(className==stringClass){return quote(\"\"+value)}if(typeof value==\"object\"){for(length=stack.length;length--;){if(stack[length]===value){throw TypeError()}}stack.push(value);results=[];prefix=indentation;indentation+=whitespace;if(className==arrayClass){for(index=0,length=value.length;index0){for(whitespace=\"\",width>10&&(width=10);whitespace.length=48&&charCode<=57||charCode>=97&&charCode<=102||charCode>=65&&charCode<=70)){abort()}}value+=fromCharCode(\"0x\"+source.slice(begin,Index));break;default:abort()}}else{if(charCode==34){break}charCode=source.charCodeAt(Index);begin=Index;while(charCode>=32&&charCode!=92&&charCode!=34){charCode=source.charCodeAt(++Index)}value+=source.slice(begin,Index)}}if(source.charCodeAt(Index)==34){Index++;return value}abort();default:begin=Index;if(charCode==45){isSigned=true;charCode=source.charCodeAt(++Index)}if(charCode>=48&&charCode<=57){if(charCode==48&&(charCode=source.charCodeAt(Index+1),charCode>=48&&charCode<=57)){abort()}isSigned=false;for(;Index=48&&charCode<=57);Index++);if(source.charCodeAt(Index)==46){position=++Index;for(;position=48&&charCode<=57);position++);if(position==Index){abort()}Index=position}charCode=source.charCodeAt(Index);if(charCode==101||charCode==69){charCode=source.charCodeAt(++Index);if(charCode==43||charCode==45){Index++}for(position=Index;position=48&&charCode<=57);position++);if(position==Index){abort()}Index=position}return+source.slice(begin,Index)}if(isSigned){abort()}if(source.slice(Index,Index+4)==\"true\"){Index+=4;return true}else if(source.slice(Index,Index+5)==\"false\"){Index+=5;return false}else if(source.slice(Index,Index+4)==\"null\"){Index+=4;return null}abort()}}return\"$\"};var get=function(value){var results,hasMembers;if(value==\"$\"){abort()}if(typeof value==\"string\"){if((charIndexBuggy?value.charAt(0):value[0])==\"@\"){return value.slice(1)}if(value==\"[\"){results=[];for(;;hasMembers||(hasMembers=true)){value=lex();if(value==\"]\"){break}if(hasMembers){if(value==\",\"){value=lex();if(value==\"]\"){abort()}}else{abort()}}if(value==\",\"){abort()}results.push(get(value))}return results}else if(value==\"{\"){results={};for(;;hasMembers||(hasMembers=true)){value=lex();if(value==\"}\"){break}if(hasMembers){if(value==\",\"){value=lex();if(value==\"}\"){abort()}}else{abort()}}if(value==\",\"||typeof value!=\"string\"||(charIndexBuggy?value.charAt(0):value[0])!=\"@\"||lex()!=\":\"){abort()}results[value.slice(1)]=get(lex())}return results}abort()}return value};var update=function(source,property,callback){var element=walk(source,property,callback);if(element===undef){delete source[property]}else{source[property]=element}};var walk=function(source,property,callback){var value=source[property],length;if(typeof value==\"object\"&&value){if(getClass.call(value)==arrayClass){for(length=value.length;length--;){update(value,length,callback)}}else{forEach(value,function(property){update(value,property,callback)})}}return callback.call(source,property,value)};JSON3.parse=function(source,callback){var result,value;Index=0;Source=\"\"+source;result=get(lex());if(lex()!=\"$\"){abort()}Index=Source=null;return callback&&getClass.call(callback)==functionClass?walk((value={},value[\"\"]=result,value),\"\",callback):result}}}if(isLoader){define(function(){return JSON3})}})(this)},{}],47:[function(_dereq_,module,exports){module.exports=toArray;function toArray(list,index){var array=[];index=index||0;for(var i=index||0;i ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIO.xcodeproj/xcshareddata/xcschemes/SocketIOFramework.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIO.xcodeproj/xcshareddata/xcschemes/SocketIOHost.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIOFramework/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier com.megabits.$(PRODUCT_NAME:rfc1034identifier) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIOFramework/SocketIOFramework.h ================================================ // // SocketIOFramework.h // SocketIOFramework // // Created by Agnes Vasarhelyi on 30/12/14. // // #import //! Project version number for SocketIOFramework. FOUNDATION_EXPORT double SocketIOFrameworkVersionNumber; //! Project version string for SocketIOFramework. FOUNDATION_EXPORT const unsigned char SocketIOFrameworkVersionString[]; #import #import ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIOHost/AppDelegate.h ================================================ // // AppDelegate.h // SocketIOHost // // Created by Patrick Perini on 9/3/14. // // #import @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @end ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIOHost/AppDelegate.m ================================================ // // AppDelegate.m // SocketIOHost // // Created by Patrick Perini on 9/3/14. // // #import "AppDelegate.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. return YES; } - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @end ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIOHost/Base.lproj/Main.storyboard ================================================ ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIOHost/Images.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIOHost/Images.xcassets/LaunchImage.launchimage/Contents.json ================================================ { "images" : [ { "orientation" : "portrait", "idiom" : "iphone", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "iphone", "subtype" : "retina4", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIOHost/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier com.megabits.$(PRODUCT_NAME:rfc1034identifier) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIOHost/ViewController.h ================================================ // // ViewController.h // SocketIOHost // // Created by Patrick Perini on 9/3/14. // // #import @interface ViewController : UIViewController @end ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIOHost/ViewController.m ================================================ // // ViewController.m // SocketIOHost // // Created by Patrick Perini on 9/3/14. // // #import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end ================================================ FILE: Carthage/Checkouts/SIOSocket/SocketIOHost/main.m ================================================ // // main.m // SocketIOHost // // Created by Patrick Perini on 9/3/14. // // #import #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ================================================ FILE: Carthage/Checkouts/SIOSocket/socket_tester/app.js ================================================ // this is a test server to support tests which make requests var io = require('socket.io'); var server = io(3000); var expect = require('expect.js'); server.on('connection', function(socket){ // simple test socket.on('hi', function(){ socket.emit('hi'); }); // ack tests socket.on('ack', function(){ socket.emit('ack', function(a, b){ if (a == 5 && b.test) { socket.emit('got it'); } }); }); socket.on('getAckDate', function(data, cb){ cb(new Date()); }); socket.on('getDate', function(){ socket.emit('takeDate', new Date()); }); socket.on('getDateObj', function(){ socket.emit('takeDateObj', { date: new Date() }); }); socket.on('getUtf8', function() { socket.emit('takeUtf8', 'てすと'); socket.emit('takeUtf8', 'Я Б Г Д Ж Й'); socket.emit('takeUtf8', 'Ä ä Ü ü ß'); socket.emit('takeUtf8', 'utf8 — string'); socket.emit('takeUtf8', 'utf8 — string'); }); // false test socket.on('false', function(){ socket.emit('false', false); }); // binary test socket.on('doge', function(){ buf = new Buffer('asdfasdf', 'utf8'); socket.emit('doge', buf); }); // expect receiving binary to be buffer socket.on('buffa', function(a){ if (Buffer.isBuffer(a)) socket.emit('buffack'); }); // expect receiving binary with mixed JSON socket.on('jsonbuff', function(a) { expect(a.hello).to.eql('lol'); expect(Buffer.isBuffer(a.message)).to.be(true); expect(a.goodbye).to.eql('gotcha'); socket.emit('jsonbuff-ack'); }); // expect receiving buffers in order var receivedAbuff1 = false; socket.on('abuff1', function(a) { expect(Buffer.isBuffer(a)).to.be(true); receivedAbuff1 = true; }); socket.on('abuff2', function(a) { expect(receivedAbuff1).to.be(true); socket.emit('abuff2-ack'); }); // expect sent blob to be buffer socket.on('blob', function(a){ if (Buffer.isBuffer(a)) socket.emit('back'); }); // expect sent blob mixed with json to be buffer socket.on('jsonblob', function(a) { expect(a.hello).to.eql('lol'); expect(Buffer.isBuffer(a.message)).to.be(true); expect(a.goodbye).to.eql('gotcha'); socket.emit('jsonblob-ack'); }); // expect blobs sent in order to arrive in correct order var receivedblob1 = false; var receivedblob2 = false; socket.on('blob1', function(a) { expect(Buffer.isBuffer(a)).to.be(true); receivedblob1 = true; }); socket.on('blob2', function(a) { expect(receivedblob1).to.be(true); expect(a).to.eql('second'); receivedblob2 = true; }); socket.on('blob3', function(a) { expect(Buffer.isBuffer(a)).to.be(true); expect(receivedblob1).to.be(true); expect(receivedblob2).to.be(true); socket.emit('blob3-ack'); }); // emit buffer to base64 receiving browsers socket.on('getbin', function() { buf = new Buffer('asdfasdf', 'utf8'); socket.emit('takebin', buf); }); // emit multi words socket.on('multi word', function() { socket.emit('multi word', 'word'); }); socket.on('multi-word', function() { socket.emit('multi-word', 'word'); }); }); ================================================ FILE: Carthage/Checkouts/SwiftyJSON/.gitignore ================================================ # Xcode .DS_Store */build/* *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata profile *.moved-aside DerivedData .idea/ *.hmap *.xccheckout #CocoaPods Pods #Carthage Carthage/Build ================================================ FILE: Carthage/Checkouts/SwiftyJSON/.travis.yml ================================================ language: objective-c osx_image: xcode7.1 xcode_sdk: iphonesimulator9.0 script: 'sh scripts/ci.sh' ================================================ FILE: Carthage/Checkouts/SwiftyJSON/CHANGELOG.md ================================================ # Change Log ## [Unreleased](https://github.com/SwiftyJSON/SwiftyJSON/tree/HEAD) [Full Changelog](https://github.com/SwiftyJSON/SwiftyJSON/compare/2.2.0...HEAD) **Closed issues:** - 156 compiler errors Mavericks + Xcode 6.2 [\#220](https://github.com/SwiftyJSON/SwiftyJSON/issues/220) - 'AnyObject' is not convertible to 'String'; did you mean to use 'as!' to force downcast? [\#218](https://github.com/SwiftyJSON/SwiftyJSON/issues/218) - pod -\> SwiftyJSON \(2.1.3\) is out-of-date if we compare it to the version mentioned in README.md file. [\#212](https://github.com/SwiftyJSON/SwiftyJSON/issues/212) - 无法获取到 2.2版本的 [\#211](https://github.com/SwiftyJSON/SwiftyJSON/issues/211) - Publish Podspec for version 2.2.0 [\#210](https://github.com/SwiftyJSON/SwiftyJSON/issues/210) - dropping elements? or am I doing something wrong? [\#209](https://github.com/SwiftyJSON/SwiftyJSON/issues/209) - Not working with Swift 1.2 [\#208](https://github.com/SwiftyJSON/SwiftyJSON/issues/208) - 在 Mac 项目里用 Carthage 无法编译 [\#193](https://github.com/SwiftyJSON/SwiftyJSON/issues/193) - 使用中发现解析效率比较低 [\#190](https://github.com/SwiftyJSON/SwiftyJSON/issues/190) - Looks like it will require a change of "as"es to "as!" for Swift 1.2... [\#150](https://github.com/SwiftyJSON/SwiftyJSON/issues/150) - No response appeared [\#118](https://github.com/SwiftyJSON/SwiftyJSON/issues/118) - Swift Optional Values from JSON [\#116](https://github.com/SwiftyJSON/SwiftyJSON/issues/116) - It seems not easy to manipulate an array or dictionary? [\#110](https://github.com/SwiftyJSON/SwiftyJSON/issues/110) **Merged pull requests:** - Fix for xcode 6.3..1 issue [\#224](https://github.com/SwiftyJSON/SwiftyJSON/pull/224) ([datomnurdin](https://github.com/datomnurdin)) - Update the first two examples snippets [\#223](https://github.com/SwiftyJSON/SwiftyJSON/pull/223) ([kmikael](https://github.com/kmikael)) - Allow .number to parse number from string instead of just numberValue [\#219](https://github.com/SwiftyJSON/SwiftyJSON/pull/219) ([yonaskolb](https://github.com/yonaskolb)) - Fixed spelling and grammar mistakes in README.md. Made some swift syntax... [\#214](https://github.com/SwiftyJSON/SwiftyJSON/pull/214) ([pRizz](https://github.com/pRizz)) ## [2.2.0](https://github.com/SwiftyJSON/SwiftyJSON/tree/2.2.0) (2015-04-13) [Full Changelog](https://github.com/SwiftyJSON/SwiftyJSON/compare/2.1.3...2.2.0) **Closed issues:** - init doesn't set type correctly [\#206](https://github.com/SwiftyJSON/SwiftyJSON/issues/206) - SwitfyJSON breaks with update to iOS 8.3 & Xcode 6.3 [\#200](https://github.com/SwiftyJSON/SwiftyJSON/issues/200) - 'NSString?' is not convertible to 'String?' error with Swift 1.2 [\#198](https://github.com/SwiftyJSON/SwiftyJSON/issues/198) - I can't install it by carthage [\#181](https://github.com/SwiftyJSON/SwiftyJSON/issues/181) - Can't compare JSON to Float [\#171](https://github.com/SwiftyJSON/SwiftyJSON/issues/171) - extend data to results [\#160](https://github.com/SwiftyJSON/SwiftyJSON/issues/160) - Create JSON From String [\#159](https://github.com/SwiftyJSON/SwiftyJSON/issues/159) - No Cocoapods support for iOS 7 [\#151](https://github.com/SwiftyJSON/SwiftyJSON/issues/151) - Update to Swift 1.2 [\#148](https://github.com/SwiftyJSON/SwiftyJSON/issues/148) - Url slashes ' / ' are being replaced with ' \/ ' [\#145](https://github.com/SwiftyJSON/SwiftyJSON/issues/145) - Issues when using carthage [\#144](https://github.com/SwiftyJSON/SwiftyJSON/issues/144) - Can not convert \[JSON\] to JSON [\#143](https://github.com/SwiftyJSON/SwiftyJSON/issues/143) - \[!\] Unable to find a specification for `SwiftyJSON \(= 2.1.3\)` [\#141](https://github.com/SwiftyJSON/SwiftyJSON/issues/141) - Deployment target iOS 7 or iOS 8? [\#131](https://github.com/SwiftyJSON/SwiftyJSON/issues/131) - Cocoapods support [\#126](https://github.com/SwiftyJSON/SwiftyJSON/issues/126) **Merged pull requests:** - Only building tests for testing [\#207](https://github.com/SwiftyJSON/SwiftyJSON/pull/207) ([spanage](https://github.com/spanage)) - Added compatibility with Swift 1.2. [\#204](https://github.com/SwiftyJSON/SwiftyJSON/pull/204) ([jankaltoun](https://github.com/jankaltoun)) - Fix for issue \#200 [\#203](https://github.com/SwiftyJSON/SwiftyJSON/pull/203) ([chschu](https://github.com/chschu)) - Updated to Swift 1.2 [\#202](https://github.com/SwiftyJSON/SwiftyJSON/pull/202) ([scottdelly](https://github.com/scottdelly)) - Updated to Swift 1.2 [\#201](https://github.com/SwiftyJSON/SwiftyJSON/pull/201) ([scottdelly](https://github.com/scottdelly)) - Update to Swift 1.2 [\#199](https://github.com/SwiftyJSON/SwiftyJSON/pull/199) ([kimdv](https://github.com/kimdv)) - Should not get subscript from AnyObject. [\#196](https://github.com/SwiftyJSON/SwiftyJSON/pull/196) ([Candyroot](https://github.com/Candyroot)) - Update for Swift 1.2 [\#195](https://github.com/SwiftyJSON/SwiftyJSON/pull/195) ([justinmakaila](https://github.com/justinmakaila)) - Update README.md [\#194](https://github.com/SwiftyJSON/SwiftyJSON/pull/194) ([manijshrestha](https://github.com/manijshrestha)) - Optimize the code to avoid useless casts to swift arrays. [\#188](https://github.com/SwiftyJSON/SwiftyJSON/pull/188) ([mirion](https://github.com/mirion)) - Fixed the buildable name in the OSX scheme [\#187](https://github.com/SwiftyJSON/SwiftyJSON/pull/187) ([cnoon](https://github.com/cnoon)) - Updated code signing identities for OSX target and tests [\#186](https://github.com/SwiftyJSON/SwiftyJSON/pull/186) ([cnoon](https://github.com/cnoon)) - Fix int overflow compile error [\#178](https://github.com/SwiftyJSON/SwiftyJSON/pull/178) ([mono0926](https://github.com/mono0926)) - Fixed a bug when accessing a value directly via a string subscript when the current object is a dictionary [\#176](https://github.com/SwiftyJSON/SwiftyJSON/pull/176) ([JosephDuffy](https://github.com/JosephDuffy)) - Better support for carthage users [\#174](https://github.com/SwiftyJSON/SwiftyJSON/pull/174) ([rromanchuk](https://github.com/rromanchuk)) - Fixes a 32bit/64bit issue. [\#172](https://github.com/SwiftyJSON/SwiftyJSON/pull/172) ([enhorn](https://github.com/enhorn)) - Update README for new Cocoapods [\#170](https://github.com/SwiftyJSON/SwiftyJSON/pull/170) ([joelparkerhenderson](https://github.com/joelparkerhenderson)) - Fixed a crash when entering json\["NotExistPath"\] [\#167](https://github.com/SwiftyJSON/SwiftyJSON/pull/167) ([ybeapps](https://github.com/ybeapps)) - Adding Swift 1.2 support [\#158](https://github.com/SwiftyJSON/SwiftyJSON/pull/158) ([Jasdev](https://github.com/Jasdev)) - Fix issues with the OS X target and scheme [\#156](https://github.com/SwiftyJSON/SwiftyJSON/pull/156) ([rastersize](https://github.com/rastersize)) - Fix issues with the OS X target and scheme [\#155](https://github.com/SwiftyJSON/SwiftyJSON/pull/155) ([rastersize](https://github.com/rastersize)) - Remove SwiftJSON.xcodeproj/xcuserdata [\#154](https://github.com/SwiftyJSON/SwiftyJSON/pull/154) ([rastersize](https://github.com/rastersize)) - Change to not build test when building iOS framework target \[Xcode 6.3 + external tools\] [\#153](https://github.com/SwiftyJSON/SwiftyJSON/pull/153) ([rastersize](https://github.com/rastersize)) - Fix tests not building for 32-bit \[Xcode 6.3\] [\#152](https://github.com/SwiftyJSON/SwiftyJSON/pull/152) ([rastersize](https://github.com/rastersize)) - Swift 1.2 compatibility fixes [\#149](https://github.com/SwiftyJSON/SwiftyJSON/pull/149) ([darrarski](https://github.com/darrarski)) - \[README.md\] Setter for JSON array should use arrayObject not array [\#146](https://github.com/SwiftyJSON/SwiftyJSON/pull/146) ([lwu](https://github.com/lwu)) - add missing ` in comments [\#142](https://github.com/SwiftyJSON/SwiftyJSON/pull/142) ([zhxnlai](https://github.com/zhxnlai)) - Fix README.md nested example [\#139](https://github.com/SwiftyJSON/SwiftyJSON/pull/139) ([watsonbox](https://github.com/watsonbox)) - Shared OSX Scheme. OSX target fixes. [\#138](https://github.com/SwiftyJSON/SwiftyJSON/pull/138) ([haveahennessy](https://github.com/haveahennessy)) - Casting to NSDictionary instead of \[String : AnyObject\] [\#137](https://github.com/SwiftyJSON/SwiftyJSON/pull/137) ([clwkct](https://github.com/clwkct)) - Update README.md [\#136](https://github.com/SwiftyJSON/SwiftyJSON/pull/136) ([esbenvb](https://github.com/esbenvb)) - Update README.md [\#135](https://github.com/SwiftyJSON/SwiftyJSON/pull/135) ([esbenvb](https://github.com/esbenvb)) - Fixed the broken Carthage OS X Support. [\#134](https://github.com/SwiftyJSON/SwiftyJSON/pull/134) ([remaerd](https://github.com/remaerd)) - Prefixed "SequenceType" extension with Module name [\#124](https://github.com/SwiftyJSON/SwiftyJSON/pull/124) ([ravero](https://github.com/ravero)) - Code cleaning [\#123](https://github.com/SwiftyJSON/SwiftyJSON/pull/123) ([wiruzx](https://github.com/wiruzx)) ## [2.1.3](https://github.com/SwiftyJSON/SwiftyJSON/tree/2.1.3) (2015-01-10) [Full Changelog](https://github.com/SwiftyJSON/SwiftyJSON/compare/2.1.2...2.1.3) **Closed issues:** - Cannot install using Carthage [\#122](https://github.com/SwiftyJSON/SwiftyJSON/issues/122) - Use of unresolved identifier 'dataFromNetworking' [\#112](https://github.com/SwiftyJSON/SwiftyJSON/issues/112) - I can't parse out the string like "{a:5}" [\#109](https://github.com/SwiftyJSON/SwiftyJSON/issues/109) - Cocoapods integration [\#108](https://github.com/SwiftyJSON/SwiftyJSON/issues/108) - Compile Error In Loop Array [\#107](https://github.com/SwiftyJSON/SwiftyJSON/issues/107) - Support for Carthage [\#105](https://github.com/SwiftyJSON/SwiftyJSON/issues/105) **Merged pull requests:** - Minor grammar fixes to README [\#128](https://github.com/SwiftyJSON/SwiftyJSON/pull/128) ([johngoren](https://github.com/johngoren)) - Updated because podspec is now available... [\#127](https://github.com/SwiftyJSON/SwiftyJSON/pull/127) ([johngoren](https://github.com/johngoren)) - Fix access modificator of isEmpty property [\#121](https://github.com/SwiftyJSON/SwiftyJSON/pull/121) ([wiruzx](https://github.com/wiruzx)) - Make framework extension friendly [\#119](https://github.com/SwiftyJSON/SwiftyJSON/pull/119) ([technomage](https://github.com/technomage)) - add a new way to access Json [\#117](https://github.com/SwiftyJSON/SwiftyJSON/pull/117) ([zhanghao111111111](https://github.com/zhanghao111111111)) - fix the typos on the code snippets and the links in the TOC on README [\#115](https://github.com/SwiftyJSON/SwiftyJSON/pull/115) ([floydpink](https://github.com/floydpink)) - Use Mac' codesign identities for OSX targets [\#114](https://github.com/SwiftyJSON/SwiftyJSON/pull/114) ([max-potapov](https://github.com/max-potapov)) ## [2.1.2](https://github.com/SwiftyJSON/SwiftyJSON/tree/2.1.2) (2014-12-13) [Full Changelog](https://github.com/SwiftyJSON/SwiftyJSON/compare/2.1.1...2.1.2) **Closed issues:** - Why can't we parse a rawString back to json object? [\#101](https://github.com/SwiftyJSON/SwiftyJSON/issues/101) - Have a Piece of Code that might be of Value to SwiftyJSon [\#97](https://github.com/SwiftyJSON/SwiftyJSON/issues/97) - build osx application \(command line tool\) with swiftyjson error [\#96](https://github.com/SwiftyJSON/SwiftyJSON/issues/96) - 这个应该是bug吧,支持的不是很够 [\#95](https://github.com/SwiftyJSON/SwiftyJSON/issues/95) - Length of an array [\#90](https://github.com/SwiftyJSON/SwiftyJSON/issues/90) - Compilation error [\#89](https://github.com/SwiftyJSON/SwiftyJSON/issues/89) - Can't set value [\#88](https://github.com/SwiftyJSON/SwiftyJSON/issues/88) - Examples with AFHTTPSessionManager? [\#86](https://github.com/SwiftyJSON/SwiftyJSON/issues/86) **Merged pull requests:** - Update README.md to add Carthage instructions [\#113](https://github.com/SwiftyJSON/SwiftyJSON/pull/113) ([justinmakaila](https://github.com/justinmakaila)) - Improve init performance for dictionaries and arrays [\#111](https://github.com/SwiftyJSON/SwiftyJSON/pull/111) ([avorobjov](https://github.com/avorobjov)) - Fix NSNumber != func [\#106](https://github.com/SwiftyJSON/SwiftyJSON/pull/106) ([briankracoff](https://github.com/briankracoff)) - Carthage Support [\#104](https://github.com/SwiftyJSON/SwiftyJSON/pull/104) ([justinmakaila](https://github.com/justinmakaila)) - Added read option for date strings [\#103](https://github.com/SwiftyJSON/SwiftyJSON/pull/103) ([Dschee](https://github.com/Dschee)) - Add Podspec \(Correct mblsha podspec\) [\#100](https://github.com/SwiftyJSON/SwiftyJSON/pull/100) ([ValCapri](https://github.com/ValCapri)) - Add podspec + make it work as a framework [\#99](https://github.com/SwiftyJSON/SwiftyJSON/pull/99) ([mblsha](https://github.com/mblsha)) - Adding new Feature: JsonMapper [\#98](https://github.com/SwiftyJSON/SwiftyJSON/pull/98) ([Drogenix](https://github.com/Drogenix)) - Change recommendation for Alamofire integration [\#92](https://github.com/SwiftyJSON/SwiftyJSON/pull/92) ([JonathanPorta](https://github.com/JonathanPorta)) ## [2.1.1](https://github.com/SwiftyJSON/SwiftyJSON/tree/2.1.1) (2014-11-12) [Full Changelog](https://github.com/SwiftyJSON/SwiftyJSON/compare/2.1.0...2.1.1) **Closed issues:** - NSDictionary to json string to json object [\#93](https://github.com/SwiftyJSON/SwiftyJSON/issues/93) - Error: use of unresolved identifier dataFromNetworking [\#82](https://github.com/SwiftyJSON/SwiftyJSON/issues/82) - Type \[SubscriptType\] Does not conform to protocol 'StringLiteralConvertible' [\#81](https://github.com/SwiftyJSON/SwiftyJSON/issues/81) - Doesn't conform literal protocols [\#80](https://github.com/SwiftyJSON/SwiftyJSON/issues/80) - iOS 8.1 compatability [\#79](https://github.com/SwiftyJSON/SwiftyJSON/issues/79) - Xcode 6.1 Compatibility [\#78](https://github.com/SwiftyJSON/SwiftyJSON/issues/78) - Problem with xCode 6.1 [\#76](https://github.com/SwiftyJSON/SwiftyJSON/issues/76) - Compilation errors [\#75](https://github.com/SwiftyJSON/SwiftyJSON/issues/75) **Merged pull requests:** - Renamed type 'Unknow' to 'Unknown' [\#94](https://github.com/SwiftyJSON/SwiftyJSON/pull/94) ([franklsf95](https://github.com/franklsf95)) - Added OSX target. [\#91](https://github.com/SwiftyJSON/SwiftyJSON/pull/91) ([carloslozano](https://github.com/carloslozano)) - Add date ,dateValue [\#87](https://github.com/SwiftyJSON/SwiftyJSON/pull/87) ([muukii0803](https://github.com/muukii0803)) - Add parse JSON Date [\#85](https://github.com/SwiftyJSON/SwiftyJSON/pull/85) ([ShineWu](https://github.com/ShineWu)) - Update README.md [\#84](https://github.com/SwiftyJSON/SwiftyJSON/pull/84) ([johngoren](https://github.com/johngoren)) - Update README.md for typos [\#83](https://github.com/SwiftyJSON/SwiftyJSON/pull/83) ([johngoren](https://github.com/johngoren)) ## [2.1.0](https://github.com/SwiftyJSON/SwiftyJSON/tree/2.1.0) (2014-10-19) [Full Changelog](https://github.com/SwiftyJSON/SwiftyJSON/compare/2.0.0...2.1.0) **Closed issues:** - 32bit test failures [\#71](https://github.com/SwiftyJSON/SwiftyJSON/issues/71) - Trouble getting string representation [\#70](https://github.com/SwiftyJSON/SwiftyJSON/issues/70) - JSON keep null [\#69](https://github.com/SwiftyJSON/SwiftyJSON/issues/69) - Update .pbxproj to Deployment Target 8.0 [\#66](https://github.com/SwiftyJSON/SwiftyJSON/issues/66) - Looping not working [\#64](https://github.com/SwiftyJSON/SwiftyJSON/issues/64) **Merged pull requests:** - Get number from string in JSON.number [\#74](https://github.com/SwiftyJSON/SwiftyJSON/pull/74) ([yonaskolb](https://github.com/yonaskolb)) - Update SwiftyJSON.swift [\#73](https://github.com/SwiftyJSON/SwiftyJSON/pull/73) ([MaddTheSane](https://github.com/MaddTheSane)) - Generating Raw JSON Strings [\#72](https://github.com/SwiftyJSON/SwiftyJSON/pull/72) ([lesmuc](https://github.com/lesmuc)) - Making SourceKit not freak out about self.object.count being called [\#68](https://github.com/SwiftyJSON/SwiftyJSON/pull/68) ([Noobish1](https://github.com/Noobish1)) - Added support for Xcode 6.1 GM Seed 2. [\#65](https://github.com/SwiftyJSON/SwiftyJSON/pull/65) ([rosskimes](https://github.com/rosskimes)) ## [2.0.0](https://github.com/SwiftyJSON/SwiftyJSON/tree/2.0.0) (2014-10-08) [Full Changelog](https://github.com/SwiftyJSON/SwiftyJSON/compare/1.1.0...2.0.0) **Closed issues:** - JSON to NSData [\#62](https://github.com/SwiftyJSON/SwiftyJSON/issues/62) - Updating a json [\#60](https://github.com/SwiftyJSON/SwiftyJSON/issues/60) **Merged pull requests:** - Update for new features \[Issue \#60\] [\#63](https://github.com/SwiftyJSON/SwiftyJSON/pull/63) ([tangplin](https://github.com/tangplin)) ## [1.1.0](https://github.com/SwiftyJSON/SwiftyJSON/tree/1.1.0) (2014-10-02) [Full Changelog](https://github.com/SwiftyJSON/SwiftyJSON/compare/1.0.0...1.1.0) **Closed issues:** - Long time to parse this json [\#57](https://github.com/SwiftyJSON/SwiftyJSON/issues/57) **Merged pull requests:** - Merge develop [\#59](https://github.com/SwiftyJSON/SwiftyJSON/pull/59) ([tangplin](https://github.com/tangplin)) - Added SwiftyJSON lazy wrapping [\#58](https://github.com/SwiftyJSON/SwiftyJSON/pull/58) ([k06a](https://github.com/k06a)) ## [1.0.0](https://github.com/SwiftyJSON/SwiftyJSON/tree/1.0.0) (2014-09-26) **Implemented enhancements:** - JNumber should be Number not double [\#8](https://github.com/SwiftyJSON/SwiftyJSON/issues/8) - Separate implementations of protocols [\#5](https://github.com/SwiftyJSON/SwiftyJSON/issues/5) **Fixed bugs:** - JNumber should be Number not double [\#8](https://github.com/SwiftyJSON/SwiftyJSON/issues/8) - Fails to compile on Beta2 [\#1](https://github.com/SwiftyJSON/SwiftyJSON/issues/1) **Closed issues:** - No such module "SwiftyJSON" [\#49](https://github.com/SwiftyJSON/SwiftyJSON/issues/49) - how to transfer JSONValue object to Dictionary object? [\#48](https://github.com/SwiftyJSON/SwiftyJSON/issues/48) - JSONValue in @objc [\#47](https://github.com/SwiftyJSON/SwiftyJSON/issues/47) - SwiftyJSON.swift:331:22: Use of undeclared type 'BooleanType' [\#46](https://github.com/SwiftyJSON/SwiftyJSON/issues/46) - Problem converting JSONValue to AnyObject [\#44](https://github.com/SwiftyJSON/SwiftyJSON/issues/44) - Can't use SwiftyJSON as part of a public API within a framework [\#42](https://github.com/SwiftyJSON/SwiftyJSON/issues/42) - how to add JSONValue object into exist JSONValue [\#40](https://github.com/SwiftyJSON/SwiftyJSON/issues/40) - Doesn't work in BETA 6 [\#39](https://github.com/SwiftyJSON/SwiftyJSON/issues/39) - Can't access property [\#38](https://github.com/SwiftyJSON/SwiftyJSON/issues/38) - Couldn't Compile and Run [\#37](https://github.com/SwiftyJSON/SwiftyJSON/issues/37) - Array index out of range [\#35](https://github.com/SwiftyJSON/SwiftyJSON/issues/35) - Iterating through a JSON response [\#32](https://github.com/SwiftyJSON/SwiftyJSON/issues/32) - NSNull in an array is discarded [\#25](https://github.com/SwiftyJSON/SwiftyJSON/issues/25) - Updating Dictionary [\#24](https://github.com/SwiftyJSON/SwiftyJSON/issues/24) - SourcekitService Terminated Issue [\#22](https://github.com/SwiftyJSON/SwiftyJSON/issues/22) - Code does not compile in iOS 8 Beta 3. [\#17](https://github.com/SwiftyJSON/SwiftyJSON/issues/17) - How to use .count [\#14](https://github.com/SwiftyJSON/SwiftyJSON/issues/14) - Add to cocoapods [\#12](https://github.com/SwiftyJSON/SwiftyJSON/issues/12) - String parsing [\#9](https://github.com/SwiftyJSON/SwiftyJSON/issues/9) - Cocoapods integration [\#4](https://github.com/SwiftyJSON/SwiftyJSON/issues/4) - How do I verify SwiftyJSON workS? [\#2](https://github.com/SwiftyJSON/SwiftyJSON/issues/2) **Merged pull requests:** - Revert "Added rawObject method for unwrapping JSONValue enum to objects" [\#56](https://github.com/SwiftyJSON/SwiftyJSON/pull/56) ([tangplin](https://github.com/tangplin)) - set the default JSONReadingOptions to .AllowFragments [\#55](https://github.com/SwiftyJSON/SwiftyJSON/pull/55) ([tangplin](https://github.com/tangplin)) - Fix Unit Test [\#54](https://github.com/SwiftyJSON/SwiftyJSON/pull/54) ([lingoer](https://github.com/lingoer)) - Add NSError to Null type [\#53](https://github.com/SwiftyJSON/SwiftyJSON/pull/53) ([lingoer](https://github.com/lingoer)) - Refactor! [\#51](https://github.com/SwiftyJSON/SwiftyJSON/pull/51) ([tangplin](https://github.com/tangplin)) - Rename LISCENSE to LICENSE [\#50](https://github.com/SwiftyJSON/SwiftyJSON/pull/50) ([fixe](https://github.com/fixe)) - Added rawObject method for unwrapping JSONValue enum to objects [\#45](https://github.com/SwiftyJSON/SwiftyJSON/pull/45) ([k06a](https://github.com/k06a)) - made JSONValue public for usage in framework APIs [\#43](https://github.com/SwiftyJSON/SwiftyJSON/pull/43) ([Dschee](https://github.com/Dschee)) - Adding public/private modifiers so that SwiftyJSON can be used as a framework [\#41](https://github.com/SwiftyJSON/SwiftyJSON/pull/41) ([jansabbe](https://github.com/jansabbe)) - Rename LISCENSE to LICENSE [\#36](https://github.com/SwiftyJSON/SwiftyJSON/pull/36) ([kriswallsmith](https://github.com/kriswallsmith)) - Fix for Xcode 6 beta 5 changes [\#34](https://github.com/SwiftyJSON/SwiftyJSON/pull/34) ([FahimF](https://github.com/FahimF)) - Use BooleanType instead of LogicValue for Beta 5 [\#33](https://github.com/SwiftyJSON/SwiftyJSON/pull/33) ([venables](https://github.com/venables)) - Support for JSON as string [\#31](https://github.com/SwiftyJSON/SwiftyJSON/pull/31) ([bsvingen](https://github.com/bsvingen)) - Support building JSON messages in code. [\#30](https://github.com/SwiftyJSON/SwiftyJSON/pull/30) ([johnno1962](https://github.com/johnno1962)) - Update project to include access modifiers from Xcode beta 4. [\#29](https://github.com/SwiftyJSON/SwiftyJSON/pull/29) ([Baltoli](https://github.com/Baltoli)) - jsonvalue now conforms to sequence protocol for array values [\#28](https://github.com/SwiftyJSON/SwiftyJSON/pull/28) ([NatashaTheRobot](https://github.com/NatashaTheRobot)) - updated array and dictionary syntax for beta3 [\#27](https://github.com/SwiftyJSON/SwiftyJSON/pull/27) ([NatashaTheRobot](https://github.com/NatashaTheRobot)) - Update for Beta 4: exposing JSONValue with public [\#26](https://github.com/SwiftyJSON/SwiftyJSON/pull/26) ([NachoSoto](https://github.com/NachoSoto)) - SourceKitService Termination issue fix [\#23](https://github.com/SwiftyJSON/SwiftyJSON/pull/23) ([ipraba](https://github.com/ipraba)) - Add percent escaping to URL string [\#21](https://github.com/SwiftyJSON/SwiftyJSON/pull/21) ([romanroibu](https://github.com/romanroibu)) - Converting JSON objects to string is fixed [\#20](https://github.com/SwiftyJSON/SwiftyJSON/pull/20) ([bkase](https://github.com/bkase)) - JSONValue can be inited via string [\#19](https://github.com/SwiftyJSON/SwiftyJSON/pull/19) ([bkase](https://github.com/bkase)) - Updated to remove errors in Xcode Beta 3 [\#18](https://github.com/SwiftyJSON/SwiftyJSON/pull/18) ([krishpop](https://github.com/krishpop)) - add first and last in JSONValue, add string to double, int etc. [\#16](https://github.com/SwiftyJSON/SwiftyJSON/pull/16) ([tangplin](https://github.com/tangplin)) - add a "url" property to JSONValue [\#15](https://github.com/SwiftyJSON/SwiftyJSON/pull/15) ([kyoh](https://github.com/kyoh)) - Some typo fixes [\#13](https://github.com/SwiftyJSON/SwiftyJSON/pull/13) ([gregbarbosa](https://github.com/gregbarbosa)) - Separate protocols implementation, refactor prettyString composing [\#6](https://github.com/SwiftyJSON/SwiftyJSON/pull/6) ([garnett](https://github.com/garnett)) - Add project with both OSX/iOS module targets [\#3](https://github.com/SwiftyJSON/SwiftyJSON/pull/3) ([garnett](https://github.com/garnett)) \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Example/Example/AppDelegate.swift ================================================ // SwiftyJSON.h // // Copyright (c) 2014 Pinglin Tang // // 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. import UIKit import SwiftyJSON @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { let navigationController = self.window?.rootViewController as! UINavigationController let viewController = navigationController.topViewController as! ViewController if let file = NSBundle(forClass:AppDelegate.self).pathForResource("SwiftyJSONTests", ofType: "json") { let data = NSData(contentsOfFile: file)! let json = JSON(data:data) viewController.json = json } else { viewController.json = JSON.null } return true } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Example/Example/Base.lproj/LaunchScreen.xib ================================================ ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Example/Example/Base.lproj/Main.storyboard ================================================ HelveticaNeue ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Example/Example/Images.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "1x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "2x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "1x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "2x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "1x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Example/Example/Images.xcassets/LaunchImage.launchimage/Contents.json ================================================ { "images" : [ { "orientation" : "portrait", "idiom" : "iphone", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "2x" }, { "extent" : "full-screen", "idiom" : "iphone", "subtype" : "retina4", "filename" : "Default@2x.png", "minimum-system-version" : "7.0", "orientation" : "portrait", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "ipad", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "1x" }, { "orientation" : "landscape", "idiom" : "ipad", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "1x" }, { "orientation" : "portrait", "idiom" : "ipad", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "2x" }, { "orientation" : "landscape", "idiom" : "ipad", "extent" : "full-screen", "minimum-system-version" : "7.0", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Example/Example/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Example/Example/SwiftyJSONTests.json ================================================ [ { "coordinates":null, "truncated":false, "created_at":"Tue Aug 28 21:16:23 +0000 2012", "favorited":false, "id_str":"240558470661799936", "in_reply_to_user_id_str":null, "entities":{ "urls":[ ], "hashtags":[ ], "user_mentions":[ ] }, "text":"just another test", "contributors":null, "id":240558470661799936, "retweet_count":0, "in_reply_to_status_id_str":null, "geo":null, "retweeted":false, "in_reply_to_user_id":null, "place":null, "source":"<a href=\"//realitytechnicians.com\" rel=\"\"nofollow\"\">OAuth Dancer Reborn</a>", "user":{ "name":"OAuth Dancer", "profile_sidebar_fill_color":"DDEEF6", "profile_background_tile":true, "profile_sidebar_border_color":"C0DEED", "profile_image_url":"http://a0.twimg.com/profile_images/730275945/oauth-dancer_normal.jpg", "created_at":"Wed Mar 03 19:37:35 +0000 2010", "location":"San Francisco, CA", "follow_request_sent":false, "id_str":"119476949", "is_translator":false, "profile_link_color":"0084B4", "entities":{ "url":{ "urls":[ { "expanded_url":null, "url":"http://bit.ly/oauth-dancer", "indices":[ 0, 26 ], "display_url":null } ] }, "description":null }, "default_profile":false, "url":"http://bit.ly/oauth-dancer", "contributors_enabled":false, "favourites_count":7, "utc_offset":null, "profile_image_url_https":"https://si0.twimg.com/profile_images/730275945/oauth-dancer_normal.jpg", "id":119476949, "listed_count":1, "profile_use_background_image":true, "profile_text_color":"333333", "followers_count":28, "lang":"en", "protected":false, "geo_enabled":true, "notifications":false, "description":"", "profile_background_color":"C0DEED", "verified":false, "time_zone":null, "profile_background_image_url_https":"https://si0.twimg.com/profile_background_images/80151733/oauth-dance.png", "statuses_count":166, "profile_background_image_url":"http://a0.twimg.com/profile_background_images/80151733/oauth-dance.png", "default_profile_image":false, "friends_count":14, "following":false, "show_all_inline_media":false, "screen_name":"oauth_dancer" }, "in_reply_to_screen_name":null, "in_reply_to_status_id":null }, { "coordinates":{ "coordinates":[ -122.25831, 37.871609 ], "type":"Point" }, "truncated":false, "created_at":"Tue Aug 28 21:08:15 +0000 2012", "favorited":false, "id_str":"240556426106372096", "in_reply_to_user_id_str":null, "entities":{ "urls":[ { "expanded_url":"http://blogs.ischool.berkeley.edu/i290-abdt-s12/", "url":"http://t.co/bfj7zkDJ", "indices":[ 79, 99 ], "display_url":"blogs.ischool.berkeley.edu/i290-abdt-s12/" } ], "hashtags":[ ], "user_mentions":[ { "name":"Cal", "id_str":"17445752", "id":17445752, "indices":[ 60, 64 ], "screen_name":"Cal" }, { "name":"Othman Laraki", "id_str":"20495814", "id":20495814, "indices":[ 70, 77 ], "screen_name":"othman" } ] }, "text":"lecturing at the \"analyzing big data with twitter\" class at @cal with @othman http://t.co/bfj7zkDJ", "contributors":null, "id":240556426106372096, "retweet_count":3, "in_reply_to_status_id_str":null, "geo":{ "coordinates":[ 37.871609, -122.25831 ], "type":"Point" }, "retweeted":false, "possibly_sensitive":false, "in_reply_to_user_id":null, "place":{ "name":"Berkeley", "country_code":"US", "country":"United States", "attributes":{ }, "url":"http://api.twitter.com/1/geo/id/5ef5b7f391e30aff.json", "id":"5ef5b7f391e30aff", "bounding_box":{ "coordinates":[ [ [ -122.367781, 37.835727 ], [ -122.234185, 37.835727 ], [ -122.234185, 37.905824 ], [ -122.367781, 37.905824 ] ] ], "type":"Polygon" }, "full_name":"Berkeley, CA", "place_type":"city" }, "source":"<a href=\"//www.apple.com\"\" rel=\"\"nofollow\"\">Safari on iOS</a>", "user":{ "name":"Raffi Krikorian", "profile_sidebar_fill_color":"DDEEF6", "profile_background_tile":false, "profile_sidebar_border_color":"C0DEED", "profile_image_url":"http://a0.twimg.com/profile_images/1270234259/raffi-headshot-casual_normal.png", "created_at":"Sun Aug 19 14:24:06 +0000 2007", "location":"San Francisco, California", "follow_request_sent":false, "id_str":"8285392", "is_translator":false, "profile_link_color":"0084B4", "entities":{ "url":{ "urls":[ { "expanded_url":"http://about.me/raffi.krikorian", "url":"http://t.co/eNmnM6q", "indices":[ 0, 19 ], "display_url":"about.me/raffi.krikorian" } ] }, "description":{ "urls":[ ] } }, "default_profile":true, "url":"http://t.co/eNmnM6q", "contributors_enabled":false, "favourites_count":724, "utc_offset":-28800, "profile_image_url_https":"https://si0.twimg.com/profile_images/1270234259/raffi-headshot-casual_normal.png", "id":8285392, "listed_count":619, "profile_use_background_image":true, "profile_text_color":"333333", "followers_count":18752, "lang":"en", "protected":false, "geo_enabled":true, "notifications":false, "description":"Director of @twittereng's Platform Services. I break things.", "profile_background_color":"C0DEED", "verified":false, "time_zone":"Pacific Time (US & Canada)", "profile_background_image_url_https":"https://si0.twimg.com/images/themes/theme1/bg.png", "statuses_count":5007, "profile_background_image_url":"http://a0.twimg.com/images/themes/theme1/bg.png", "default_profile_image":false, "friends_count":701, "following":true, "show_all_inline_media":true, "screen_name":"raffi" }, "in_reply_to_screen_name":null, "in_reply_to_status_id":null }, { "coordinates":null, "truncated":false, "created_at":"Tue Aug 28 19:59:34 +0000 2012", "favorited":false, "id_str":"240539141056638977", "in_reply_to_user_id_str":null, "entities":{ "urls":[ ], "hashtags":[ ], "user_mentions":[ ] }, "text":"You'd be right more often if you thought you were wrong.", "contributors":null, "id":240539141056638977, "retweet_count":1, "in_reply_to_status_id_str":null, "geo":null, "retweeted":false, "in_reply_to_user_id":null, "place":null, "source":"web", "user":{ "name":"Taylor Singletary", "profile_sidebar_fill_color":"FBFBFB", "profile_background_tile":true, "profile_sidebar_border_color":"000000", "profile_image_url":"http://a0.twimg.com/profile_images/2546730059/f6a8zq58mg1hn0ha8vie_normal.jpeg", "created_at":"Wed Mar 07 22:23:19 +0000 2007", "location":"San Francisco, CA", "follow_request_sent":false, "id_str":"819797", "is_translator":false, "profile_link_color":"c71818", "entities":{ "url":{ "urls":[ { "expanded_url":"http://www.rebelmouse.com/episod/", "url":"http://t.co/Lxw7upbN", "indices":[ 0, 20 ], "display_url":"rebelmouse.com/episod/" } ] }, "description":{ "urls":[ ] } }, "default_profile":false, "url":"http://t.co/Lxw7upbN", "contributors_enabled":false, "favourites_count":15990, "utc_offset":-28800, "profile_image_url_https":"https://si0.twimg.com/profile_images/2546730059/f6a8zq58mg1hn0ha8vie_normal.jpeg", "id":819797, "listed_count":340, "profile_use_background_image":true, "profile_text_color":"D20909", "followers_count":7126, "lang":"en", "protected":false, "geo_enabled":true, "notifications":false, "description":"Reality Technician, Twitter API team, synthesizer enthusiast; a most excellent adventure in timelines. I know it's hard to believe in something you can't see.", "profile_background_color":"000000", "verified":false, "time_zone":"Pacific Time (US & Canada)", "profile_background_image_url_https":"https://si0.twimg.com/profile_background_images/643655842/hzfv12wini4q60zzrthg.png", "statuses_count":18076, "profile_background_image_url":"http://a0.twimg.com/profile_background_images/643655842/hzfv12wini4q60zzrthg.png", "default_profile_image":false, "friends_count":5444, "following":true, "show_all_inline_media":true, "screen_name":"episod" }, "in_reply_to_screen_name":null, "in_reply_to_status_id":null } ] ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Example/Example/ViewController.swift ================================================ // SwiftyJSON.h // // Copyright (c) 2014 Pinglin Tang // // 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. import UIKit import SwiftyJSON class ViewController: UITableViewController { var json: JSON = JSON.null // MARK: - Table view data source override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { switch self.json.type { case Type.Array, Type.Dictionary: return self.json.count default: return 1 } } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("JSONCell", forIndexPath: indexPath) as UITableViewCell let row = indexPath.row switch self.json.type { case .Array: cell.textLabel?.text = "\(row)" cell.detailTextLabel?.text = self.json.arrayValue.description case .Dictionary: let key: AnyObject = Array(self.json.dictionaryValue.keys)[row] let value = self.json[key as! String] cell.textLabel?.text = "\(key)" cell.detailTextLabel?.text = value.description default: cell.textLabel?.text = "" cell.detailTextLabel?.text = self.json.description } return cell } // MARK: - Navigation override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) { var nextController: UIViewController? switch UIDevice.currentDevice().systemVersion.compare("8.0.0", options: NSStringCompareOptions.NumericSearch) { case .OrderedSame, .OrderedDescending: nextController = (segue.destinationViewController as! UINavigationController).topViewController case .OrderedAscending: nextController = segue.destinationViewController } if let indexPath = self.tableView.indexPathForSelectedRow { let row = indexPath.row var nextJson: JSON = JSON.null switch self.json.type { case .Array: nextJson = self.json[row] case .Dictionary where row < self.json.dictionaryValue.count: let key = Array(self.json.dictionaryValue.keys)[row] if let value = self.json.dictionary?[key] { nextJson = value } default: print("") } (nextController as! ViewController).json = nextJson print(nextJson) } } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Example/Example.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ A82A1C1F19D926B8009A653D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A82A1C1E19D926B8009A653D /* AppDelegate.swift */; }; A82A1C2419D926B8009A653D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A82A1C2219D926B8009A653D /* Main.storyboard */; }; A82A1C2619D926B8009A653D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A82A1C2519D926B8009A653D /* Images.xcassets */; }; A82A1C2919D926B8009A653D /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = A82A1C2719D926B8009A653D /* LaunchScreen.xib */; }; A82A1C4019D94AE5009A653D /* SwiftyJSONTests.json in Resources */ = {isa = PBXBuildFile; fileRef = A82A1C3F19D94AE5009A653D /* SwiftyJSONTests.json */; }; A82A1C5619D95606009A653D /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A82A1C5519D95606009A653D /* ViewController.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 04294C581BE5A9DE00D0397E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = A82A1C4719D94E86009A653D /* SwiftyJSON.xcodeproj */; proxyType = 2; remoteGlobalIDString = E4D7CCE81B9465A700EE7221; remoteInfo = "SwiftyJSON watchOS"; }; 04294C5A1BE5A9DE00D0397E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = A82A1C4719D94E86009A653D /* SwiftyJSON.xcodeproj */; proxyType = 2; remoteGlobalIDString = 7236B4F61BAC14150020529B; remoteInfo = "SwiftyJSON tvOS"; }; 04294C5C1BE5A9DE00D0397E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = A82A1C4719D94E86009A653D /* SwiftyJSON.xcodeproj */; proxyType = 2; remoteGlobalIDString = A8580F741BCF5C5B00DA927B; remoteInfo = "SwiftyJSON tvOS Tests"; }; A8BF45AA1B871E100066C032 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = A82A1C4719D94E86009A653D /* SwiftyJSON.xcodeproj */; proxyType = 2; remoteGlobalIDString = 2E4FEFDB19575BE100351305; remoteInfo = "SwiftyJSON iOS"; }; A8BF45AC1B871E100066C032 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = A82A1C4719D94E86009A653D /* SwiftyJSON.xcodeproj */; proxyType = 2; remoteGlobalIDString = 2E4FEFE619575BE100351305; remoteInfo = "SwiftyJSON iOS Tests"; }; A8BF45AE1B871E100066C032 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = A82A1C4719D94E86009A653D /* SwiftyJSON.xcodeproj */; proxyType = 2; remoteGlobalIDString = 9C7DFC5B1A9102BD005AA3F7; remoteInfo = "SwiftyJSON OSX"; }; A8BF45B01B871E100066C032 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = A82A1C4719D94E86009A653D /* SwiftyJSON.xcodeproj */; proxyType = 2; remoteGlobalIDString = 9C7DFC651A9102BD005AA3F7; remoteInfo = "SwiftyJSON OSX Tests"; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ A82A1C5419D94E97009A653D /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 04294C501BE5A9DE00D0397E /* Playground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Playground.playground; sourceTree = ""; }; A82A1C1919D926B8009A653D /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; A82A1C1D19D926B8009A653D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; A82A1C1E19D926B8009A653D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; A82A1C2319D926B8009A653D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; A82A1C2519D926B8009A653D /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; A82A1C2819D926B8009A653D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; A82A1C3F19D94AE5009A653D /* SwiftyJSONTests.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = SwiftyJSONTests.json; sourceTree = ""; }; A82A1C4719D94E86009A653D /* SwiftyJSON.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SwiftyJSON.xcodeproj; path = ../SwiftyJSON.xcodeproj; sourceTree = ""; }; A82A1C5519D95606009A653D /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ A82A1C1619D926B8009A653D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ A82A1C1019D926B8009A653D = { isa = PBXGroup; children = ( 04294C501BE5A9DE00D0397E /* Playground.playground */, A82A1C4719D94E86009A653D /* SwiftyJSON.xcodeproj */, A82A1C1B19D926B8009A653D /* Example */, A82A1C1A19D926B8009A653D /* Products */, ); sourceTree = ""; }; A82A1C1A19D926B8009A653D /* Products */ = { isa = PBXGroup; children = ( A82A1C1919D926B8009A653D /* Example.app */, ); name = Products; sourceTree = ""; }; A82A1C1B19D926B8009A653D /* Example */ = { isa = PBXGroup; children = ( A82A1C3F19D94AE5009A653D /* SwiftyJSONTests.json */, A82A1C1E19D926B8009A653D /* AppDelegate.swift */, A82A1C5519D95606009A653D /* ViewController.swift */, A82A1C2219D926B8009A653D /* Main.storyboard */, A82A1C2519D926B8009A653D /* Images.xcassets */, A82A1C2719D926B8009A653D /* LaunchScreen.xib */, A82A1C1C19D926B8009A653D /* Supporting Files */, ); path = Example; sourceTree = ""; }; A82A1C1C19D926B8009A653D /* Supporting Files */ = { isa = PBXGroup; children = ( A82A1C1D19D926B8009A653D /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; A8BF45A41B871E0F0066C032 /* Products */ = { isa = PBXGroup; children = ( A8BF45AB1B871E100066C032 /* SwiftyJSON.framework */, A8BF45AD1B871E100066C032 /* SwiftyJSON iOS Tests.xctest */, A8BF45AF1B871E100066C032 /* SwiftyJSON.framework */, A8BF45B11B871E100066C032 /* SwiftyJSON OSX Tests.xctest */, 04294C591BE5A9DE00D0397E /* SwiftyJSON.framework */, 04294C5B1BE5A9DE00D0397E /* SwiftyJSON.framework */, 04294C5D1BE5A9DE00D0397E /* SwiftyJSON tvOS Tests.xctest */, ); name = Products; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ A82A1C1819D926B8009A653D /* Example */ = { isa = PBXNativeTarget; buildConfigurationList = A82A1C3819D926B8009A653D /* Build configuration list for PBXNativeTarget "Example" */; buildPhases = ( A82A1C1519D926B8009A653D /* Sources */, A82A1C1619D926B8009A653D /* Frameworks */, A82A1C1719D926B8009A653D /* Resources */, A82A1C5419D94E97009A653D /* Embed Frameworks */, ); buildRules = ( ); dependencies = ( ); name = Example; productName = Example; productReference = A82A1C1919D926B8009A653D /* Example.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ A82A1C1119D926B8009A653D /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0700; LastUpgradeCheck = 0700; ORGANIZATIONNAME = swiftyjson; TargetAttributes = { A82A1C1819D926B8009A653D = { CreatedOnToolsVersion = 6.0.1; }; }; }; buildConfigurationList = A82A1C1419D926B8009A653D /* Build configuration list for PBXProject "Example" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = A82A1C1019D926B8009A653D; productRefGroup = A82A1C1A19D926B8009A653D /* Products */; projectDirPath = ""; projectReferences = ( { ProductGroup = A8BF45A41B871E0F0066C032 /* Products */; ProjectRef = A82A1C4719D94E86009A653D /* SwiftyJSON.xcodeproj */; }, ); projectRoot = ""; targets = ( A82A1C1819D926B8009A653D /* Example */, ); }; /* End PBXProject section */ /* Begin PBXReferenceProxy section */ 04294C591BE5A9DE00D0397E /* SwiftyJSON.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; path = SwiftyJSON.framework; remoteRef = 04294C581BE5A9DE00D0397E /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; 04294C5B1BE5A9DE00D0397E /* SwiftyJSON.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; path = SwiftyJSON.framework; remoteRef = 04294C5A1BE5A9DE00D0397E /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; 04294C5D1BE5A9DE00D0397E /* SwiftyJSON tvOS Tests.xctest */ = { isa = PBXReferenceProxy; fileType = wrapper.cfbundle; path = "SwiftyJSON tvOS Tests.xctest"; remoteRef = 04294C5C1BE5A9DE00D0397E /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; A8BF45AB1B871E100066C032 /* SwiftyJSON.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; path = SwiftyJSON.framework; remoteRef = A8BF45AA1B871E100066C032 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; A8BF45AD1B871E100066C032 /* SwiftyJSON iOS Tests.xctest */ = { isa = PBXReferenceProxy; fileType = wrapper.cfbundle; path = "SwiftyJSON iOS Tests.xctest"; remoteRef = A8BF45AC1B871E100066C032 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; A8BF45AF1B871E100066C032 /* SwiftyJSON.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; path = SwiftyJSON.framework; remoteRef = A8BF45AE1B871E100066C032 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; A8BF45B11B871E100066C032 /* SwiftyJSON OSX Tests.xctest */ = { isa = PBXReferenceProxy; fileType = wrapper.cfbundle; path = "SwiftyJSON OSX Tests.xctest"; remoteRef = A8BF45B01B871E100066C032 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */ A82A1C1719D926B8009A653D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( A82A1C2419D926B8009A653D /* Main.storyboard in Resources */, A82A1C2919D926B8009A653D /* LaunchScreen.xib in Resources */, A82A1C2619D926B8009A653D /* Images.xcassets in Resources */, A82A1C4019D94AE5009A653D /* SwiftyJSONTests.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ A82A1C1519D926B8009A653D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( A82A1C5619D95606009A653D /* ViewController.swift in Sources */, A82A1C1F19D926B8009A653D /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ A82A1C2219D926B8009A653D /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( A82A1C2319D926B8009A653D /* Base */, ); name = Main.storyboard; sourceTree = ""; }; A82A1C2719D926B8009A653D /* LaunchScreen.xib */ = { isa = PBXVariantGroup; children = ( A82A1C2819D926B8009A653D /* Base */, ); name = LaunchScreen.xib; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ A82A1C3619D926B8009A653D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; 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; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; A82A1C3719D926B8009A653D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; 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; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; A82A1C3919D926B8009A653D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; INFOPLIST_FILE = Example/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; A82A1C3A19D926B8009A653D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CODE_SIGN_IDENTITY = "iPhone Distribution"; INFOPLIST_FILE = Example/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ A82A1C1419D926B8009A653D /* Build configuration list for PBXProject "Example" */ = { isa = XCConfigurationList; buildConfigurations = ( A82A1C3619D926B8009A653D /* Debug */, A82A1C3719D926B8009A653D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; A82A1C3819D926B8009A653D /* Build configuration list for PBXNativeTarget "Example" */ = { isa = XCConfigurationList; buildConfigurations = ( A82A1C3919D926B8009A653D /* Debug */, A82A1C3A19D926B8009A653D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = A82A1C1119D926B8009A653D /* Project object */; } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Example/Playground.playground/Contents.swift ================================================ //: Playground - noun: a place where people can play import SwiftyJSON ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Example/Playground.playground/contents.xcplayground ================================================ ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Example/Playground.playground/timeline.xctimeline ================================================ ================================================ FILE: Carthage/Checkouts/SwiftyJSON/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Ruoyu Fu 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. ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Package.swift ================================================ ================================================ FILE: Carthage/Checkouts/SwiftyJSON/README.md ================================================ #SwiftyJSON [中文介绍](http://tangplin.github.io/swiftyjson/) [![Travis CI](https://travis-ci.org/SwiftyJSON/SwiftyJSON.svg?branch=master)](https://travis-ci.org/SwiftyJSON/SwiftyJSON) SwiftyJSON makes it easy to deal with JSON data in Swift. 1. [Why is the typical JSON handling in Swift NOT good](#why-is-the-typical-json-handling-in-swift-not-good) 1. [Requirements](#requirements) 1. [Integration](#integration) 1. [Usage](#usage) - [Initialization](#initialization) - [Subscript](#subscript) - [Loop](#loop) - [Error](#error) - [Optional getter](#optional-getter) - [Non-optional getter](#non-optional-getter) - [Setter](#setter) - [Raw object](#raw-object) - [Literal convertibles](#literal-convertibles) 1. [Work with Alamofire](#work-with-alamofire) ##Why is the typical JSON handling in Swift NOT good? Swift is very strict about types. But although explicit typing is good for saving us from mistakes, it becomes painful when dealing with JSON and other areas that are, by nature, implicit about types. Take the Twitter API for example. Say we want to retrieve a user's "name" value of some tweet in Swift (according to Twitter's API https://dev.twitter.com/docs/api/1.1/get/statuses/home_timeline). The code would look like this: ```swift if let statusesArray = try? NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) as? [[String: AnyObject]], let user = statusesArray[0]["user"] as? [String: AnyObject], let username = user["name"] as? String { // Finally we got the username } ``` It's not good. Even if we use optional chaining, it would be messy: ```swift if let JSONObject = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) as? [[String: AnyObject]], let username = (JSONObject[0]["user"] as? [String: AnyObject])?["name"] as? String { // There's our username } ``` An unreadable mess--for something that should really be simple! With SwiftyJSON all you have to do is: ```swift let json = JSON(data: dataFromNetworking) if let userName = json[0]["user"]["name"].string { //Now you got your value } ``` And don't worry about the Optional Wrapping thing. It's done for you automatically. ```swift let json = JSON(data: dataFromNetworking) if let userName = json[999999]["wrong_key"]["wrong_name"].string { //Calm down, take it easy, the ".string" property still produces the correct Optional String type with safety } else { //Print the error print(json[999999]["wrong_key"]["wrong_name"]) } ``` ## Requirements - iOS 7.0+ / Mac OS X 10.9+ - Xcode 7 ##Integration ####CocoaPods (iOS 8+, OS X 10.9+) You can use [Cocoapods](http://cocoapods.org/) to install `SwiftyJSON`by adding it to your `Podfile`: ```ruby platform :ios, '8.0' use_frameworks! target 'MyApp' do pod 'SwiftyJSON', :git => 'https://github.com/SwiftyJSON/SwiftyJSON.git' end ``` Note that this requires CocoaPods version 36, and your iOS deployment target to be at least 8.0: ####Carthage (iOS 8+, OS X 10.9+) You can use [Carthage](https://github.com/Carthage/Carthage) to install `SwiftyJSON` by adding it to your `Cartfile`: ``` github "SwiftyJSON/SwiftyJSON" ``` ####Manually (iOS 7+, OS X 10.9+) To use this library in your project manually you may: 1. for Projects, just drag SwiftyJSON.swift to the project tree 2. for Workspaces, include the whole SwiftyJSON.xcodeproj ## Usage ####Initialization ```swift import SwiftyJSON ``` ```swift let json = JSON(data: dataFromNetworking) ``` ```swift let json = JSON(jsonObject) ``` ```swift if let dataFromString = jsonString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) { let json = JSON(data: dataFromString) } ``` ####Subscript ```swift //Getting a double from a JSON Array let name = json[0].double ``` ```swift //Getting a string from a JSON Dictionary let name = json["name"].stringValue ``` ```swift //Getting a string using a path to the element let path = [1,"list",2,"name"] let name = json[path].string //Just the same let name = json[1]["list"][2]["name"].string //Alternatively let name = json[1,"list",2,"name"].string ``` ```swift //With a hard way let name = json[].string ``` ```swift //With a custom way let keys:[SubscriptType] = [1,"list",2,"name"] let name = json[keys].string ``` ####Loop ```swift //If json is .Dictionary for (key,subJson):(String, JSON) in json { //Do something you want } ``` *The first element is always a String, even if the JSON is an Array* ```swift //If json is .Array //The `index` is 0.. = json["list"].arrayValue ``` ```swift //If not a Dictionary or nil, return [:] let user: Dictionary = json["user"].dictionaryValue ``` ####Setter ```swift json["name"] = JSON("new-name") json[0] = JSON(1) ``` ```swift json["id"].int = 1234567890 json["coordinate"].double = 8766.766 json["name"].string = "Jack" json.arrayObject = [1,2,3,4] json.dictionary = ["name":"Jack", "age":25] ``` ####Raw object ```swift let jsonObject: AnyObject = json.object ``` ```swift if let jsonObject: AnyObject = json.rawValue ``` ```swift //convert the JSON to raw NSData if let data = json.rawData() { //Do something you want } ``` ```swift //convert the JSON to a raw String if let string = json.rawString() { //Do something you want } ``` ####Existance ```swift //shows you whether value specified in JSON or not if json["name"].isExists() ``` ####Literal convertibles For more info about literal convertibles: [Swift Literal Convertibles](http://nshipster.com/swift-literal-convertible/) ```swift //StringLiteralConvertible let json: JSON = "I'm a json" ``` ```swift //IntegerLiteralConvertible let json: JSON = 12345 ``` ```swift //BooleanLiteralConvertible let json: JSON = true ``` ```swift //FloatLiteralConvertible let json: JSON = 2.8765 ``` ```swift //DictionaryLiteralConvertible let json: JSON = ["I":"am", "a":"json"] ``` ```swift //ArrayLiteralConvertible let json: JSON = ["I", "am", "a", "json"] ``` ```swift //NilLiteralConvertible let json: JSON = nil ``` ```swift //With subscript in array var json: JSON = [1,2,3] json[0] = 100 json[1] = 200 json[2] = 300 json[999] = 300 //Don't worry, nothing will happen ``` ```swift //With subscript in dictionary var json: JSON = ["name": "Jack", "age": 25] json["name"] = "Mike" json["age"] = "25" //It's OK to set String json["address"] = "L.A." // Add the "address": "L.A." in json ``` ```swift //Array & Dictionary var json: JSON = ["name": "Jack", "age": 25, "list": ["a", "b", "c", ["what": "this"]]] json["list"][3]["what"] = "that" json["list",3,"what"] = "that" let path = ["list",3,"what"] json[path] = "that" ``` ##Work with Alamofire SwiftyJSON nicely wraps the result of the Alamofire JSON response handler: ```swift Alamofire.request(.GET, url).validate().responseJSON { response in switch response.result { case .Success: if let value = response.result.value { let json = JSON(value) print("JSON: \(json)") } case .Failure(let error): print(error) } } ``` ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Source/Info-OSX.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Source/Info-iOS.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Source/Info-tvOS.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass UIRequiredDeviceCapabilities arm64 ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Source/Info-watchOS.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion ${CURRENT_PROJECT_VERSION} NSPrincipalClass ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Source/SwiftyJSON.h ================================================ // SwiftyJSON.h // // Copyright (c) 2014 Ruoyu Fu, Pinglin Tang // // 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. @import Foundation; //! Project version number for SwiftyJSON. FOUNDATION_EXPORT double SwiftyJSONVersionNumber; //! Project version string for SwiftyJSON. FOUNDATION_EXPORT const unsigned char SwiftyJSONVersionString[]; ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Source/SwiftyJSON.swift ================================================ // SwiftyJSON.swift // // Copyright (c) 2014 Ruoyu Fu, Pinglin Tang // // 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. import Foundation // MARK: - Error ///Error domain public let ErrorDomain: String = "SwiftyJSONErrorDomain" ///Error code public let ErrorUnsupportedType: Int = 999 public let ErrorIndexOutOfBounds: Int = 900 public let ErrorWrongType: Int = 901 public let ErrorNotExist: Int = 500 public let ErrorInvalidJSON: Int = 490 // MARK: - JSON Type /** JSON's type definitions. See http://www.json.org */ public enum Type :Int{ case Number case String case Bool case Array case Dictionary case Null case Unknown } // MARK: - JSON Base public struct JSON { /** Creates a JSON using the data. - parameter data: The NSData used to convert to json.Top level object in data is an NSArray or NSDictionary - parameter opt: The JSON serialization reading options. `.AllowFragments` by default. - parameter error: error The NSErrorPointer used to return the error. `nil` by default. - returns: The created JSON */ public init(data:NSData, options opt: NSJSONReadingOptions = .AllowFragments, error: NSErrorPointer = nil) { do { let object: AnyObject = try NSJSONSerialization.JSONObjectWithData(data, options: opt) self.init(object) } catch let aError as NSError { if error != nil { error.memory = aError } self.init(NSNull()) } } /** Create a JSON from JSON string - parameter string: Normal json string like '{"a":"b"}' - returns: The created JSON */ public static func parse(string:String) -> JSON { return string.dataUsingEncoding(NSUTF8StringEncoding) .flatMap({JSON(data: $0)}) ?? JSON(NSNull()) } /** Creates a JSON using the object. - parameter object: The object must have the following properties: All objects are NSString/String, NSNumber/Int/Float/Double/Bool, NSArray/Array, NSDictionary/Dictionary, or NSNull; All dictionary keys are NSStrings/String; NSNumbers are not NaN or infinity. - returns: The created JSON */ public init(_ object: AnyObject) { self.object = object } /** Creates a JSON from a [JSON] - parameter jsonArray: A Swift array of JSON objects - returns: The created JSON */ public init(_ jsonArray:[JSON]) { self.init(jsonArray.map { $0.object }) } /** Creates a JSON from a [String: JSON] - parameter jsonDictionary: A Swift dictionary of JSON objects - returns: The created JSON */ public init(_ jsonDictionary:[String: JSON]) { var dictionary = [String: AnyObject]() for (key, json) in jsonDictionary { dictionary[key] = json.object } self.init(dictionary) } /// Private object private var rawArray: [AnyObject] = [] private var rawDictionary: [String : AnyObject] = [:] private var rawString: String = "" private var rawNumber: NSNumber = 0 private var rawNull: NSNull = NSNull() /// Private type private var _type: Type = .Null /// prviate error private var _error: NSError? = nil /// Object in JSON public var object: AnyObject { get { switch self.type { case .Array: return self.rawArray case .Dictionary: return self.rawDictionary case .String: return self.rawString case .Number: return self.rawNumber case .Bool: return self.rawNumber default: return self.rawNull } } set { _error = nil switch newValue { case let number as NSNumber: if number.isBool { _type = .Bool } else { _type = .Number } self.rawNumber = number case let string as String: _type = .String self.rawString = string case _ as NSNull: _type = .Null case let array as [AnyObject]: _type = .Array self.rawArray = array case let dictionary as [String : AnyObject]: _type = .Dictionary self.rawDictionary = dictionary default: _type = .Unknown _error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"]) } } } /// json type public var type: Type { get { return _type } } /// Error in JSON public var error: NSError? { get { return self._error } } /// The static null json @available(*, unavailable, renamed="null") public static var nullJSON: JSON { get { return null } } public static var null: JSON { get { return JSON(NSNull()) } } } // MARK: - CollectionType, SequenceType, Indexable extension JSON : Swift.CollectionType, Swift.SequenceType, Swift.Indexable { public typealias Generator = JSONGenerator public typealias Index = JSONIndex public var startIndex: JSON.Index { switch self.type { case .Array: return JSONIndex(arrayIndex: self.rawArray.startIndex) case .Dictionary: return JSONIndex(dictionaryIndex: self.rawDictionary.startIndex) default: return JSONIndex() } } public var endIndex: JSON.Index { switch self.type { case .Array: return JSONIndex(arrayIndex: self.rawArray.endIndex) case .Dictionary: return JSONIndex(dictionaryIndex: self.rawDictionary.endIndex) default: return JSONIndex() } } public subscript (position: JSON.Index) -> JSON.Generator.Element { switch self.type { case .Array: return (String(position.arrayIndex), JSON(self.rawArray[position.arrayIndex!])) case .Dictionary: let (key, value) = self.rawDictionary[position.dictionaryIndex!] return (key, JSON(value)) default: return ("", JSON.null) } } /// If `type` is `.Array` or `.Dictionary`, return `array.empty` or `dictonary.empty` otherwise return `true`. public var isEmpty: Bool { get { switch self.type { case .Array: return self.rawArray.isEmpty case .Dictionary: return self.rawDictionary.isEmpty default: return true } } } /// If `type` is `.Array` or `.Dictionary`, return `array.count` or `dictonary.count` otherwise return `0`. public var count: Int { switch self.type { case .Array: return self.rawArray.count case .Dictionary: return self.rawDictionary.count default: return 0 } } public func underestimateCount() -> Int { switch self.type { case .Array: return self.rawArray.underestimateCount() case .Dictionary: return self.rawDictionary.underestimateCount() default: return 0 } } /** If `type` is `.Array` or `.Dictionary`, return a generator over the elements like `Array` or `Dictionary`, otherwise return a generator over empty. - returns: Return a *generator* over the elements of JSON. */ public func generate() -> JSON.Generator { return JSON.Generator(self) } } public struct JSONIndex: ForwardIndexType, _Incrementable, Equatable, Comparable { let arrayIndex: Int? let dictionaryIndex: DictionaryIndex? let type: Type init(){ self.arrayIndex = nil self.dictionaryIndex = nil self.type = .Unknown } init(arrayIndex: Int) { self.arrayIndex = arrayIndex self.dictionaryIndex = nil self.type = .Array } init(dictionaryIndex: DictionaryIndex) { self.arrayIndex = nil self.dictionaryIndex = dictionaryIndex self.type = .Dictionary } public func successor() -> JSONIndex { switch self.type { case .Array: return JSONIndex(arrayIndex: self.arrayIndex!.successor()) case .Dictionary: return JSONIndex(dictionaryIndex: self.dictionaryIndex!.successor()) default: return JSONIndex() } } } public func ==(lhs: JSONIndex, rhs: JSONIndex) -> Bool { switch (lhs.type, rhs.type) { case (.Array, .Array): return lhs.arrayIndex == rhs.arrayIndex case (.Dictionary, .Dictionary): return lhs.dictionaryIndex == rhs.dictionaryIndex default: return false } } public func <(lhs: JSONIndex, rhs: JSONIndex) -> Bool { switch (lhs.type, rhs.type) { case (.Array, .Array): return lhs.arrayIndex < rhs.arrayIndex case (.Dictionary, .Dictionary): return lhs.dictionaryIndex < rhs.dictionaryIndex default: return false } } public func <=(lhs: JSONIndex, rhs: JSONIndex) -> Bool { switch (lhs.type, rhs.type) { case (.Array, .Array): return lhs.arrayIndex <= rhs.arrayIndex case (.Dictionary, .Dictionary): return lhs.dictionaryIndex <= rhs.dictionaryIndex default: return false } } public func >=(lhs: JSONIndex, rhs: JSONIndex) -> Bool { switch (lhs.type, rhs.type) { case (.Array, .Array): return lhs.arrayIndex >= rhs.arrayIndex case (.Dictionary, .Dictionary): return lhs.dictionaryIndex >= rhs.dictionaryIndex default: return false } } public func >(lhs: JSONIndex, rhs: JSONIndex) -> Bool { switch (lhs.type, rhs.type) { case (.Array, .Array): return lhs.arrayIndex > rhs.arrayIndex case (.Dictionary, .Dictionary): return lhs.dictionaryIndex > rhs.dictionaryIndex default: return false } } public struct JSONGenerator : GeneratorType { public typealias Element = (String, JSON) private let type: Type private var dictionayGenerate: DictionaryGenerator? private var arrayGenerate: IndexingGenerator<[AnyObject]>? private var arrayIndex: Int = 0 init(_ json: JSON) { self.type = json.type if type == .Array { self.arrayGenerate = json.rawArray.generate() }else { self.dictionayGenerate = json.rawDictionary.generate() } } public mutating func next() -> JSONGenerator.Element? { switch self.type { case .Array: if let o = self.arrayGenerate?.next() { return (String(self.arrayIndex++), JSON(o)) } else { return nil } case .Dictionary: if let (k, v): (String, AnyObject) = self.dictionayGenerate?.next() { return (k, JSON(v)) } else { return nil } default: return nil } } } // MARK: - Subscript /** * To mark both String and Int can be used in subscript. */ public enum JSONKey { case Index(Int) case Key(String) } public protocol JSONSubscriptType { var jsonKey:JSONKey { get } } extension Int: JSONSubscriptType { public var jsonKey:JSONKey { return JSONKey.Index(self) } } extension String: JSONSubscriptType { public var jsonKey:JSONKey { return JSONKey.Key(self) } } extension JSON { /// If `type` is `.Array`, return json which's object is `array[index]`, otherwise return null json with error. private subscript(index index: Int) -> JSON { get { if self.type != .Array { var r = JSON.null r._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] failure, It is not an array"]) return r } else if index >= 0 && index < self.rawArray.count { return JSON(self.rawArray[index]) } else { var r = JSON.null r._error = NSError(domain: ErrorDomain, code:ErrorIndexOutOfBounds , userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] is out of bounds"]) return r } } set { if self.type == .Array { if self.rawArray.count > index && newValue.error == nil { self.rawArray[index] = newValue.object } } } } /// If `type` is `.Dictionary`, return json which's object is `dictionary[key]` , otherwise return null json with error. private subscript(key key: String) -> JSON { get { var r = JSON.null if self.type == .Dictionary { if let o = self.rawDictionary[key] { r = JSON(o) } else { r._error = NSError(domain: ErrorDomain, code: ErrorNotExist, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] does not exist"]) } } else { r._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] failure, It is not an dictionary"]) } return r } set { if self.type == .Dictionary && newValue.error == nil { self.rawDictionary[key] = newValue.object } } } /// If `sub` is `Int`, return `subscript(index:)`; If `sub` is `String`, return `subscript(key:)`. private subscript(sub sub: JSONSubscriptType) -> JSON { get { switch sub.jsonKey { case .Index(let index): return self[index: index] case .Key(let key): return self[key: key] } } set { switch sub.jsonKey { case .Index(let index): self[index: index] = newValue case .Key(let key): self[key: key] = newValue } } } /** Find a json in the complex data structuresby using the Int/String's array. - parameter path: The target json's path. Example: let json = JSON[data] let path = [9,"list","person","name"] let name = json[path] The same as: let name = json[9]["list"]["person"]["name"] - returns: Return a json found by the path or a null json with error */ public subscript(path: [JSONSubscriptType]) -> JSON { get { return path.reduce(self) { $0[sub: $1] } } set { switch path.count { case 0: return case 1: self[sub:path[0]].object = newValue.object default: var aPath = path; aPath.removeAtIndex(0) var nextJSON = self[sub: path[0]] nextJSON[aPath] = newValue self[sub: path[0]] = nextJSON } } } /** Find a json in the complex data structuresby using the Int/String's array. - parameter path: The target json's path. Example: let name = json[9,"list","person","name"] The same as: let name = json[9]["list"]["person"]["name"] - returns: Return a json found by the path or a null json with error */ public subscript(path: JSONSubscriptType...) -> JSON { get { return self[path] } set { self[path] = newValue } } } // MARK: - LiteralConvertible extension JSON: Swift.StringLiteralConvertible { public init(stringLiteral value: StringLiteralType) { self.init(value) } public init(extendedGraphemeClusterLiteral value: StringLiteralType) { self.init(value) } public init(unicodeScalarLiteral value: StringLiteralType) { self.init(value) } } extension JSON: Swift.IntegerLiteralConvertible { public init(integerLiteral value: IntegerLiteralType) { self.init(value) } } extension JSON: Swift.BooleanLiteralConvertible { public init(booleanLiteral value: BooleanLiteralType) { self.init(value) } } extension JSON: Swift.FloatLiteralConvertible { public init(floatLiteral value: FloatLiteralType) { self.init(value) } } extension JSON: Swift.DictionaryLiteralConvertible { public init(dictionaryLiteral elements: (String, AnyObject)...) { self.init(elements.reduce([String : AnyObject]()){(dictionary: [String : AnyObject], element:(String, AnyObject)) -> [String : AnyObject] in var d = dictionary d[element.0] = element.1 return d }) } } extension JSON: Swift.ArrayLiteralConvertible { public init(arrayLiteral elements: AnyObject...) { self.init(elements) } } extension JSON: Swift.NilLiteralConvertible { public init(nilLiteral: ()) { self.init(NSNull()) } } // MARK: - Raw extension JSON: Swift.RawRepresentable { public init?(rawValue: AnyObject) { if JSON(rawValue).type == .Unknown { return nil } else { self.init(rawValue) } } public var rawValue: AnyObject { return self.object } public func rawData(options opt: NSJSONWritingOptions = NSJSONWritingOptions(rawValue: 0)) throws -> NSData { guard NSJSONSerialization.isValidJSONObject(self.object) else { throw NSError(domain: ErrorDomain, code: ErrorInvalidJSON, userInfo: [NSLocalizedDescriptionKey: "JSON is invalid"]) } return try NSJSONSerialization.dataWithJSONObject(self.object, options: opt) } public func rawString(encoding: UInt = NSUTF8StringEncoding, options opt: NSJSONWritingOptions = .PrettyPrinted) -> String? { switch self.type { case .Array, .Dictionary: do { let data = try self.rawData(options: opt) return NSString(data: data, encoding: encoding) as? String } catch _ { return nil } case .String: return self.rawString case .Number: return self.rawNumber.stringValue case .Bool: return self.rawNumber.boolValue.description case .Null: return "null" default: return nil } } } // MARK: - Printable, DebugPrintable extension JSON: Swift.Printable, Swift.DebugPrintable { public var description: String { if let string = self.rawString(options:.PrettyPrinted) { return string } else { return "unknown" } } public var debugDescription: String { return description } } // MARK: - Array extension JSON { //Optional [JSON] public var array: [JSON]? { get { if self.type == .Array { return self.rawArray.map{ JSON($0) } } else { return nil } } } //Non-optional [JSON] public var arrayValue: [JSON] { get { return self.array ?? [] } } //Optional [AnyObject] public var arrayObject: [AnyObject]? { get { switch self.type { case .Array: return self.rawArray default: return nil } } set { if let array = newValue { self.object = array } else { self.object = NSNull() } } } } // MARK: - Dictionary extension JSON { //Optional [String : JSON] public var dictionary: [String : JSON]? { if self.type == .Dictionary { return self.rawDictionary.reduce([String : JSON]()) { (dictionary: [String : JSON], element: (String, AnyObject)) -> [String : JSON] in var d = dictionary d[element.0] = JSON(element.1) return d } } else { return nil } } //Non-optional [String : JSON] public var dictionaryValue: [String : JSON] { return self.dictionary ?? [:] } //Optional [String : AnyObject] public var dictionaryObject: [String : AnyObject]? { get { switch self.type { case .Dictionary: return self.rawDictionary default: return nil } } set { if let v = newValue { self.object = v } else { self.object = NSNull() } } } } // MARK: - Bool extension JSON: Swift.BooleanType { //Optional bool public var bool: Bool? { get { switch self.type { case .Bool: return self.rawNumber.boolValue default: return nil } } set { if let newValue = newValue { self.object = NSNumber(bool: newValue) } else { self.object = NSNull() } } } //Non-optional bool public var boolValue: Bool { get { switch self.type { case .Bool, .Number, .String: return self.object.boolValue default: return false } } set { self.object = NSNumber(bool: newValue) } } } // MARK: - String extension JSON { //Optional string public var string: String? { get { switch self.type { case .String: return self.object as? String default: return nil } } set { if let newValue = newValue { self.object = NSString(string:newValue) } else { self.object = NSNull() } } } //Non-optional string public var stringValue: String { get { switch self.type { case .String: return self.object as? String ?? "" case .Number: return self.object.stringValue case .Bool: return (self.object as? Bool).map { String($0) } ?? "" default: return "" } } set { self.object = NSString(string:newValue) } } } // MARK: - Number extension JSON { //Optional number public var number: NSNumber? { get { switch self.type { case .Number, .Bool: return self.rawNumber default: return nil } } set { self.object = newValue ?? NSNull() } } //Non-optional number public var numberValue: NSNumber { get { switch self.type { case .String: let decimal = NSDecimalNumber(string: self.object as? String) if decimal == NSDecimalNumber.notANumber() { // indicates parse error return NSDecimalNumber.zero() } return decimal case .Number, .Bool: return self.object as? NSNumber ?? NSNumber(int: 0) default: return NSNumber(double: 0.0) } } set { self.object = newValue } } } //MARK: - Null extension JSON { public var null: NSNull? { get { switch self.type { case .Null: return self.rawNull default: return nil } } set { self.object = NSNull() } } public func isExists() -> Bool{ if let errorValue = error where errorValue.code == ErrorNotExist{ return false } return true } } //MARK: - URL extension JSON { //Optional URL public var URL: NSURL? { get { switch self.type { case .String: if let encodedString_ = self.rawString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) { return NSURL(string: encodedString_) } else { return nil } default: return nil } } set { self.object = newValue?.absoluteString ?? NSNull() } } } // MARK: - Int, Double, Float, Int8, Int16, Int32, Int64 extension JSON { public var double: Double? { get { return self.number?.doubleValue } set { if let newValue = newValue { self.object = NSNumber(double: newValue) } else { self.object = NSNull() } } } public var doubleValue: Double { get { return self.numberValue.doubleValue } set { self.object = NSNumber(double: newValue) } } public var float: Float? { get { return self.number?.floatValue } set { if let newValue = newValue { self.object = NSNumber(float: newValue) } else { self.object = NSNull() } } } public var floatValue: Float { get { return self.numberValue.floatValue } set { self.object = NSNumber(float: newValue) } } public var int: Int? { get { return self.number?.longValue } set { if let newValue = newValue { self.object = NSNumber(integer: newValue) } else { self.object = NSNull() } } } public var intValue: Int { get { return self.numberValue.integerValue } set { self.object = NSNumber(integer: newValue) } } public var uInt: UInt? { get { return self.number?.unsignedLongValue } set { if let newValue = newValue { self.object = NSNumber(unsignedLong: newValue) } else { self.object = NSNull() } } } public var uIntValue: UInt { get { return self.numberValue.unsignedLongValue } set { self.object = NSNumber(unsignedLong: newValue) } } public var int8: Int8? { get { return self.number?.charValue } set { if let newValue = newValue { self.object = NSNumber(char: newValue) } else { self.object = NSNull() } } } public var int8Value: Int8 { get { return self.numberValue.charValue } set { self.object = NSNumber(char: newValue) } } public var uInt8: UInt8? { get { return self.number?.unsignedCharValue } set { if let newValue = newValue { self.object = NSNumber(unsignedChar: newValue) } else { self.object = NSNull() } } } public var uInt8Value: UInt8 { get { return self.numberValue.unsignedCharValue } set { self.object = NSNumber(unsignedChar: newValue) } } public var int16: Int16? { get { return self.number?.shortValue } set { if let newValue = newValue { self.object = NSNumber(short: newValue) } else { self.object = NSNull() } } } public var int16Value: Int16 { get { return self.numberValue.shortValue } set { self.object = NSNumber(short: newValue) } } public var uInt16: UInt16? { get { return self.number?.unsignedShortValue } set { if let newValue = newValue { self.object = NSNumber(unsignedShort: newValue) } else { self.object = NSNull() } } } public var uInt16Value: UInt16 { get { return self.numberValue.unsignedShortValue } set { self.object = NSNumber(unsignedShort: newValue) } } public var int32: Int32? { get { return self.number?.intValue } set { if let newValue = newValue { self.object = NSNumber(int: newValue) } else { self.object = NSNull() } } } public var int32Value: Int32 { get { return self.numberValue.intValue } set { self.object = NSNumber(int: newValue) } } public var uInt32: UInt32? { get { return self.number?.unsignedIntValue } set { if let newValue = newValue { self.object = NSNumber(unsignedInt: newValue) } else { self.object = NSNull() } } } public var uInt32Value: UInt32 { get { return self.numberValue.unsignedIntValue } set { self.object = NSNumber(unsignedInt: newValue) } } public var int64: Int64? { get { return self.number?.longLongValue } set { if let newValue = newValue { self.object = NSNumber(longLong: newValue) } else { self.object = NSNull() } } } public var int64Value: Int64 { get { return self.numberValue.longLongValue } set { self.object = NSNumber(longLong: newValue) } } public var uInt64: UInt64? { get { return self.number?.unsignedLongLongValue } set { if let newValue = newValue { self.object = NSNumber(unsignedLongLong: newValue) } else { self.object = NSNull() } } } public var uInt64Value: UInt64 { get { return self.numberValue.unsignedLongLongValue } set { self.object = NSNumber(unsignedLongLong: newValue) } } } //MARK: - Comparable extension JSON : Swift.Comparable {} public func ==(lhs: JSON, rhs: JSON) -> Bool { switch (lhs.type, rhs.type) { case (.Number, .Number): return lhs.rawNumber == rhs.rawNumber case (.String, .String): return lhs.rawString == rhs.rawString case (.Bool, .Bool): return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue case (.Array, .Array): return lhs.rawArray as NSArray == rhs.rawArray as NSArray case (.Dictionary, .Dictionary): return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary case (.Null, .Null): return true default: return false } } public func <=(lhs: JSON, rhs: JSON) -> Bool { switch (lhs.type, rhs.type) { case (.Number, .Number): return lhs.rawNumber <= rhs.rawNumber case (.String, .String): return lhs.rawString <= rhs.rawString case (.Bool, .Bool): return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue case (.Array, .Array): return lhs.rawArray as NSArray == rhs.rawArray as NSArray case (.Dictionary, .Dictionary): return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary case (.Null, .Null): return true default: return false } } public func >=(lhs: JSON, rhs: JSON) -> Bool { switch (lhs.type, rhs.type) { case (.Number, .Number): return lhs.rawNumber >= rhs.rawNumber case (.String, .String): return lhs.rawString >= rhs.rawString case (.Bool, .Bool): return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue case (.Array, .Array): return lhs.rawArray as NSArray == rhs.rawArray as NSArray case (.Dictionary, .Dictionary): return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary case (.Null, .Null): return true default: return false } } public func >(lhs: JSON, rhs: JSON) -> Bool { switch (lhs.type, rhs.type) { case (.Number, .Number): return lhs.rawNumber > rhs.rawNumber case (.String, .String): return lhs.rawString > rhs.rawString default: return false } } public func <(lhs: JSON, rhs: JSON) -> Bool { switch (lhs.type, rhs.type) { case (.Number, .Number): return lhs.rawNumber < rhs.rawNumber case (.String, .String): return lhs.rawString < rhs.rawString default: return false } } private let trueNumber = NSNumber(bool: true) private let falseNumber = NSNumber(bool: false) private let trueObjCType = String.fromCString(trueNumber.objCType) private let falseObjCType = String.fromCString(falseNumber.objCType) // MARK: - NSNumber: Comparable extension NSNumber { var isBool:Bool { get { let objCType = String.fromCString(self.objCType) if (self.compare(trueNumber) == NSComparisonResult.OrderedSame && objCType == trueObjCType) || (self.compare(falseNumber) == NSComparisonResult.OrderedSame && objCType == falseObjCType){ return true } else { return false } } } } func ==(lhs: NSNumber, rhs: NSNumber) -> Bool { switch (lhs.isBool, rhs.isBool) { case (false, true): return false case (true, false): return false default: return lhs.compare(rhs) == NSComparisonResult.OrderedSame } } func !=(lhs: NSNumber, rhs: NSNumber) -> Bool { return !(lhs == rhs) } func <(lhs: NSNumber, rhs: NSNumber) -> Bool { switch (lhs.isBool, rhs.isBool) { case (false, true): return false case (true, false): return false default: return lhs.compare(rhs) == NSComparisonResult.OrderedAscending } } func >(lhs: NSNumber, rhs: NSNumber) -> Bool { switch (lhs.isBool, rhs.isBool) { case (false, true): return false case (true, false): return false default: return lhs.compare(rhs) == NSComparisonResult.OrderedDescending } } func <=(lhs: NSNumber, rhs: NSNumber) -> Bool { switch (lhs.isBool, rhs.isBool) { case (false, true): return false case (true, false): return false default: return lhs.compare(rhs) != NSComparisonResult.OrderedDescending } } func >=(lhs: NSNumber, rhs: NSNumber) -> Bool { switch (lhs.isBool, rhs.isBool) { case (false, true): return false case (true, false): return false default: return lhs.compare(rhs) != NSComparisonResult.OrderedAscending } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/SwiftyJSON.podspec ================================================ Pod::Spec.new do |s| s.name = "SwiftyJSON" s.version = "2.3.2" s.summary = "SwiftyJSON makes it easy to deal with JSON data in Swift" s.homepage = "https://github.com/SwiftyJSON/SwiftyJSON" s.license = { :type => "MIT" } s.authors = { "lingoer" => "lingoerer@gmail.com", "tangplin" => "tangplin@gmail.com" } s.requires_arc = true s.osx.deployment_target = "10.9" s.ios.deployment_target = "8.0" s.watchos.deployment_target = "2.0" s.tvos.deployment_target = "9.0" s.source = { :git => "https://github.com/SwiftyJSON/SwiftyJSON.git", :tag => "2.3.2"} s.source_files = "Source/*.swift" end ================================================ FILE: Carthage/Checkouts/SwiftyJSON/SwiftyJSON.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 2E4FEFE119575BE100351305 /* SwiftyJSON.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E4FEFE019575BE100351305 /* SwiftyJSON.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2E4FEFE719575BE100351305 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E4FEFDB19575BE100351305 /* SwiftyJSON.framework */; }; 7236B4EE1BAC14150020529B /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8491E1D19CD6DAE00CCFAE6 /* SwiftyJSON.swift */; }; 7236B4F11BAC14150020529B /* SwiftyJSON.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E4FEFE019575BE100351305 /* SwiftyJSON.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9C459EF41A910334008C9A41 /* SwiftyJSON.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E4FEFE019575BE100351305 /* SwiftyJSON.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9C459EF51A910361008C9A41 /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8491E1D19CD6DAE00CCFAE6 /* SwiftyJSON.swift */; }; 9C459EF81A9103C1008C9A41 /* Tests.json in Resources */ = {isa = PBXBuildFile; fileRef = A885D1DA19CFCFF0002FD4C3 /* Tests.json */; }; 9C459EF91A9103C1008C9A41 /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86BAA0D19EBC32B009EAAEB /* PerformanceTests.swift */; }; 9C459EFA1A9103C1008C9A41 /* BaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A885D1D119CF1EE6002FD4C3 /* BaseTests.swift */; }; 9C459EFB1A9103C1008C9A41 /* SequenceTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87080E319E3C2A600CDE086 /* SequenceTypeTests.swift */; }; 9C459EFC1A9103C1008C9A41 /* PrintableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A819C4A019E37FC600ADCC3D /* PrintableTests.swift */; }; 9C459EFD1A9103C1008C9A41 /* SubscriptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A819C49E19E2EE5B00ADCC3D /* SubscriptTests.swift */; }; 9C459EFE1A9103C1008C9A41 /* LiteralConvertibleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A819C49619E1A7DD00ADCC3D /* LiteralConvertibleTests.swift */; }; 9C459EFF1A9103C1008C9A41 /* RawRepresentableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A819C49819E1B10300ADCC3D /* RawRepresentableTests.swift */; }; 9C459F001A9103C1008C9A41 /* ComparableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87080E519E3DF7800CDE086 /* ComparableTests.swift */; }; 9C459F011A9103C1008C9A41 /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87080E919E43C0700CDE086 /* StringTests.swift */; }; 9C459F021A9103C1008C9A41 /* NumberTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87080E719E439DA00CDE086 /* NumberTests.swift */; }; 9C459F031A9103C1008C9A41 /* RawTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A863BE2719EED46F0092A41F /* RawTests.swift */; }; 9C459F041A9103C1008C9A41 /* DictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8B66C8B19E51D6500540692 /* DictionaryTests.swift */; }; 9C459F051A9103C1008C9A41 /* ArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8B66C8D19E52F4200540692 /* ArrayTests.swift */; }; 9C7DFC661A9102BD005AA3F7 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9C7DFC5B1A9102BD005AA3F7 /* SwiftyJSON.framework */; }; A819C49719E1A7DD00ADCC3D /* LiteralConvertibleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A819C49619E1A7DD00ADCC3D /* LiteralConvertibleTests.swift */; }; A819C49919E1B10300ADCC3D /* RawRepresentableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A819C49819E1B10300ADCC3D /* RawRepresentableTests.swift */; }; A819C49F19E2EE5B00ADCC3D /* SubscriptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A819C49E19E2EE5B00ADCC3D /* SubscriptTests.swift */; }; A819C4A119E37FC600ADCC3D /* PrintableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A819C4A019E37FC600ADCC3D /* PrintableTests.swift */; }; A81CBA0B1BCF6B0200A649A2 /* Tests.json in Resources */ = {isa = PBXBuildFile; fileRef = A885D1DA19CFCFF0002FD4C3 /* Tests.json */; }; A8491E1E19CD6DAE00CCFAE6 /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8491E1D19CD6DAE00CCFAE6 /* SwiftyJSON.swift */; }; A8580F791BCF5C5B00DA927B /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7236B4F61BAC14150020529B /* SwiftyJSON.framework */; }; A8580F801BCF69A000DA927B /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86BAA0D19EBC32B009EAAEB /* PerformanceTests.swift */; }; A8580F811BCF69A000DA927B /* BaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A885D1D119CF1EE6002FD4C3 /* BaseTests.swift */; }; A8580F821BCF69A000DA927B /* SequenceTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87080E319E3C2A600CDE086 /* SequenceTypeTests.swift */; }; A8580F831BCF69A000DA927B /* PrintableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A819C4A019E37FC600ADCC3D /* PrintableTests.swift */; }; A8580F841BCF69A000DA927B /* SubscriptTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A819C49E19E2EE5B00ADCC3D /* SubscriptTests.swift */; }; A8580F851BCF69A000DA927B /* LiteralConvertibleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A819C49619E1A7DD00ADCC3D /* LiteralConvertibleTests.swift */; }; A8580F861BCF69A000DA927B /* RawRepresentableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A819C49819E1B10300ADCC3D /* RawRepresentableTests.swift */; }; A8580F871BCF69A000DA927B /* ComparableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87080E519E3DF7800CDE086 /* ComparableTests.swift */; }; A8580F881BCF69A000DA927B /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87080E919E43C0700CDE086 /* StringTests.swift */; }; A8580F891BCF69A000DA927B /* NumberTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87080E719E439DA00CDE086 /* NumberTests.swift */; }; A8580F8A1BCF69A000DA927B /* RawTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A863BE2719EED46F0092A41F /* RawTests.swift */; }; A8580F8B1BCF69A000DA927B /* DictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8B66C8B19E51D6500540692 /* DictionaryTests.swift */; }; A8580F8C1BCF69A000DA927B /* ArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8B66C8D19E52F4200540692 /* ArrayTests.swift */; }; A863BE2819EED46F0092A41F /* RawTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A863BE2719EED46F0092A41F /* RawTests.swift */; }; A86BAA0E19EBC32B009EAAEB /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86BAA0D19EBC32B009EAAEB /* PerformanceTests.swift */; }; A87080E419E3C2A600CDE086 /* SequenceTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87080E319E3C2A600CDE086 /* SequenceTypeTests.swift */; }; A87080E619E3DF7800CDE086 /* ComparableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87080E519E3DF7800CDE086 /* ComparableTests.swift */; }; A87080E819E439DA00CDE086 /* NumberTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87080E719E439DA00CDE086 /* NumberTests.swift */; }; A87080EA19E43C0700CDE086 /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87080E919E43C0700CDE086 /* StringTests.swift */; }; A885D1D219CF1EE6002FD4C3 /* BaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A885D1D119CF1EE6002FD4C3 /* BaseTests.swift */; }; A885D1DC19CFCFF0002FD4C3 /* Tests.json in Resources */ = {isa = PBXBuildFile; fileRef = A885D1DA19CFCFF0002FD4C3 /* Tests.json */; }; A8B66C8C19E51D6500540692 /* DictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8B66C8B19E51D6500540692 /* DictionaryTests.swift */; }; A8B66C8E19E52F4200540692 /* ArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8B66C8D19E52F4200540692 /* ArrayTests.swift */; }; E4D7CCE01B9465A700EE7221 /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8491E1D19CD6DAE00CCFAE6 /* SwiftyJSON.swift */; }; E4D7CCE31B9465A700EE7221 /* SwiftyJSON.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E4FEFE019575BE100351305 /* SwiftyJSON.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 2E4FEFE819575BE100351305 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 2E4FEFD219575BE100351305 /* Project object */; proxyType = 1; remoteGlobalIDString = 2E4FEFDA19575BE100351305; remoteInfo = SwiftyJSON; }; 9C7DFC671A9102BD005AA3F7 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 2E4FEFD219575BE100351305 /* Project object */; proxyType = 1; remoteGlobalIDString = 9C7DFC5A1A9102BD005AA3F7; remoteInfo = "SwiftyJSON OSX"; }; A8580F7A1BCF5C5B00DA927B /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 2E4FEFD219575BE100351305 /* Project object */; proxyType = 1; remoteGlobalIDString = 7236B4EC1BAC14150020529B; remoteInfo = "SwiftyJSON tvOS"; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 030B6CDC1A6E171D00C2D4F1 /* Info-OSX.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-OSX.plist"; sourceTree = ""; }; 2E4FEFDB19575BE100351305 /* SwiftyJSON.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyJSON.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 2E4FEFDF19575BE100351305 /* Info-iOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; 2E4FEFE019575BE100351305 /* SwiftyJSON.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftyJSON.h; sourceTree = ""; }; 2E4FEFE619575BE100351305 /* SwiftyJSON iOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftyJSON iOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 7236B4F61BAC14150020529B /* SwiftyJSON.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyJSON.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7236B4F71BAC14150020529B /* Info-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-tvOS.plist"; sourceTree = ""; }; 9C459EF61A9103B1008C9A41 /* Info-OSX.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-OSX.plist"; sourceTree = ""; }; 9C7DFC5B1A9102BD005AA3F7 /* SwiftyJSON.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyJSON.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9C7DFC651A9102BD005AA3F7 /* SwiftyJSON OSX Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftyJSON OSX Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; A819C49619E1A7DD00ADCC3D /* LiteralConvertibleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LiteralConvertibleTests.swift; sourceTree = ""; }; A819C49819E1B10300ADCC3D /* RawRepresentableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RawRepresentableTests.swift; sourceTree = ""; }; A819C49E19E2EE5B00ADCC3D /* SubscriptTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubscriptTests.swift; sourceTree = ""; }; A819C4A019E37FC600ADCC3D /* PrintableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrintableTests.swift; sourceTree = ""; }; A82A1C0D19D922DC009A653D /* Info-iOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; A8491E1D19CD6DAE00CCFAE6 /* SwiftyJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyJSON.swift; sourceTree = ""; }; A8580F741BCF5C5B00DA927B /* SwiftyJSON tvOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftyJSON tvOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; A8580F781BCF5C5B00DA927B /* Info-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-tvOS.plist"; sourceTree = ""; }; A863BE2719EED46F0092A41F /* RawTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RawTests.swift; sourceTree = ""; }; A86BAA0D19EBC32B009EAAEB /* PerformanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerformanceTests.swift; sourceTree = ""; }; A87080E319E3C2A600CDE086 /* SequenceTypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SequenceTypeTests.swift; sourceTree = ""; }; A87080E519E3DF7800CDE086 /* ComparableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComparableTests.swift; sourceTree = ""; }; A87080E719E439DA00CDE086 /* NumberTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumberTests.swift; sourceTree = ""; }; A87080E919E43C0700CDE086 /* StringTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringTests.swift; sourceTree = ""; }; A885D1D119CF1EE6002FD4C3 /* BaseTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTests.swift; sourceTree = ""; }; A885D1DA19CFCFF0002FD4C3 /* Tests.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Tests.json; sourceTree = ""; }; A8B66C8B19E51D6500540692 /* DictionaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DictionaryTests.swift; sourceTree = ""; }; A8B66C8D19E52F4200540692 /* ArrayTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayTests.swift; sourceTree = ""; }; E4D7CCE81B9465A700EE7221 /* SwiftyJSON.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftyJSON.framework; sourceTree = BUILT_PRODUCTS_DIR; }; E4D7CCE91B9465A800EE7221 /* Info-watchOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-watchOS.plist"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 2E4FEFD719575BE100351305 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 2E4FEFE319575BE100351305 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 2E4FEFE719575BE100351305 /* SwiftyJSON.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 7236B4EF1BAC14150020529B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 9C7DFC571A9102BD005AA3F7 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 9C7DFC621A9102BD005AA3F7 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 9C7DFC661A9102BD005AA3F7 /* SwiftyJSON.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; A8580F711BCF5C5B00DA927B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( A8580F791BCF5C5B00DA927B /* SwiftyJSON.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; E4D7CCE11B9465A700EE7221 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 2E4FEFD119575BE100351305 = { isa = PBXGroup; children = ( 2E4FEFDD19575BE100351305 /* Source */, 2E4FEFEA19575BE100351305 /* Tests */, 2E4FEFDC19575BE100351305 /* Products */, ); sourceTree = ""; }; 2E4FEFDC19575BE100351305 /* Products */ = { isa = PBXGroup; children = ( 2E4FEFDB19575BE100351305 /* SwiftyJSON.framework */, 2E4FEFE619575BE100351305 /* SwiftyJSON iOS Tests.xctest */, 9C7DFC5B1A9102BD005AA3F7 /* SwiftyJSON.framework */, 9C7DFC651A9102BD005AA3F7 /* SwiftyJSON OSX Tests.xctest */, E4D7CCE81B9465A700EE7221 /* SwiftyJSON.framework */, 7236B4F61BAC14150020529B /* SwiftyJSON.framework */, A8580F741BCF5C5B00DA927B /* SwiftyJSON tvOS Tests.xctest */, ); name = Products; sourceTree = ""; }; 2E4FEFDD19575BE100351305 /* Source */ = { isa = PBXGroup; children = ( 2E4FEFE019575BE100351305 /* SwiftyJSON.h */, A8491E1D19CD6DAE00CCFAE6 /* SwiftyJSON.swift */, 2E4FEFDE19575BE100351305 /* Supporting Files */, ); path = Source; sourceTree = ""; }; 2E4FEFDE19575BE100351305 /* Supporting Files */ = { isa = PBXGroup; children = ( 2E4FEFDF19575BE100351305 /* Info-iOS.plist */, 030B6CDC1A6E171D00C2D4F1 /* Info-OSX.plist */, E4D7CCE91B9465A800EE7221 /* Info-watchOS.plist */, 7236B4F71BAC14150020529B /* Info-tvOS.plist */, ); name = "Supporting Files"; sourceTree = ""; }; 2E4FEFEA19575BE100351305 /* Tests */ = { isa = PBXGroup; children = ( A885D1DA19CFCFF0002FD4C3 /* Tests.json */, A86BAA0D19EBC32B009EAAEB /* PerformanceTests.swift */, A885D1D119CF1EE6002FD4C3 /* BaseTests.swift */, A87080E319E3C2A600CDE086 /* SequenceTypeTests.swift */, A819C4A019E37FC600ADCC3D /* PrintableTests.swift */, A819C49E19E2EE5B00ADCC3D /* SubscriptTests.swift */, A819C49619E1A7DD00ADCC3D /* LiteralConvertibleTests.swift */, A819C49819E1B10300ADCC3D /* RawRepresentableTests.swift */, A87080E519E3DF7800CDE086 /* ComparableTests.swift */, A87080E919E43C0700CDE086 /* StringTests.swift */, A87080E719E439DA00CDE086 /* NumberTests.swift */, A863BE2719EED46F0092A41F /* RawTests.swift */, A8B66C8B19E51D6500540692 /* DictionaryTests.swift */, A8B66C8D19E52F4200540692 /* ArrayTests.swift */, 2E4FEFEB19575BE100351305 /* Supporting Files */, ); path = Tests; sourceTree = ""; }; 2E4FEFEB19575BE100351305 /* Supporting Files */ = { isa = PBXGroup; children = ( A82A1C0D19D922DC009A653D /* Info-iOS.plist */, 9C459EF61A9103B1008C9A41 /* Info-OSX.plist */, A8580F781BCF5C5B00DA927B /* Info-tvOS.plist */, ); name = "Supporting Files"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 2E4FEFD819575BE100351305 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 2E4FEFE119575BE100351305 /* SwiftyJSON.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; 7236B4F01BAC14150020529B /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 7236B4F11BAC14150020529B /* SwiftyJSON.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; 9C7DFC581A9102BD005AA3F7 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 9C459EF41A910334008C9A41 /* SwiftyJSON.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; E4D7CCE21B9465A700EE7221 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( E4D7CCE31B9465A700EE7221 /* SwiftyJSON.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 2E4FEFDA19575BE100351305 /* SwiftyJSON iOS */ = { isa = PBXNativeTarget; buildConfigurationList = 2E4FEFF119575BE100351305 /* Build configuration list for PBXNativeTarget "SwiftyJSON iOS" */; buildPhases = ( 2E4FEFD619575BE100351305 /* Sources */, 2E4FEFD719575BE100351305 /* Frameworks */, 2E4FEFD819575BE100351305 /* Headers */, 2E4FEFD919575BE100351305 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "SwiftyJSON iOS"; productName = SwiftyJSON; productReference = 2E4FEFDB19575BE100351305 /* SwiftyJSON.framework */; productType = "com.apple.product-type.framework"; }; 2E4FEFE519575BE100351305 /* SwiftyJSON iOS Tests */ = { isa = PBXNativeTarget; buildConfigurationList = 2E4FEFF419575BE100351305 /* Build configuration list for PBXNativeTarget "SwiftyJSON iOS Tests" */; buildPhases = ( 2E4FEFE219575BE100351305 /* Sources */, 2E4FEFE319575BE100351305 /* Frameworks */, 2E4FEFE419575BE100351305 /* Resources */, ); buildRules = ( ); dependencies = ( 2E4FEFE919575BE100351305 /* PBXTargetDependency */, ); name = "SwiftyJSON iOS Tests"; productName = SwiftyJSONTests; productReference = 2E4FEFE619575BE100351305 /* SwiftyJSON iOS Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 7236B4EC1BAC14150020529B /* SwiftyJSON tvOS */ = { isa = PBXNativeTarget; buildConfigurationList = 7236B4F31BAC14150020529B /* Build configuration list for PBXNativeTarget "SwiftyJSON tvOS" */; buildPhases = ( 7236B4ED1BAC14150020529B /* Sources */, 7236B4EF1BAC14150020529B /* Frameworks */, 7236B4F01BAC14150020529B /* Headers */, 7236B4F21BAC14150020529B /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "SwiftyJSON tvOS"; productName = SwiftyJSON; productReference = 7236B4F61BAC14150020529B /* SwiftyJSON.framework */; productType = "com.apple.product-type.framework"; }; 9C7DFC5A1A9102BD005AA3F7 /* SwiftyJSON OSX */ = { isa = PBXNativeTarget; buildConfigurationList = 9C7DFC6E1A9102BD005AA3F7 /* Build configuration list for PBXNativeTarget "SwiftyJSON OSX" */; buildPhases = ( 9C7DFC561A9102BD005AA3F7 /* Sources */, 9C7DFC571A9102BD005AA3F7 /* Frameworks */, 9C7DFC581A9102BD005AA3F7 /* Headers */, 9C7DFC591A9102BD005AA3F7 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "SwiftyJSON OSX"; productName = "SwiftyJSON OSX"; productReference = 9C7DFC5B1A9102BD005AA3F7 /* SwiftyJSON.framework */; productType = "com.apple.product-type.framework"; }; 9C7DFC641A9102BD005AA3F7 /* SwiftyJSON OSX Tests */ = { isa = PBXNativeTarget; buildConfigurationList = 9C7DFC711A9102BD005AA3F7 /* Build configuration list for PBXNativeTarget "SwiftyJSON OSX Tests" */; buildPhases = ( 9C7DFC611A9102BD005AA3F7 /* Sources */, 9C7DFC621A9102BD005AA3F7 /* Frameworks */, 9C7DFC631A9102BD005AA3F7 /* Resources */, ); buildRules = ( ); dependencies = ( 9C7DFC681A9102BD005AA3F7 /* PBXTargetDependency */, ); name = "SwiftyJSON OSX Tests"; productName = "SwiftyJSON OSXTests"; productReference = 9C7DFC651A9102BD005AA3F7 /* SwiftyJSON OSX Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; A8580F731BCF5C5B00DA927B /* SwiftyJSON tvOS Tests */ = { isa = PBXNativeTarget; buildConfigurationList = A8580F7C1BCF5C5B00DA927B /* Build configuration list for PBXNativeTarget "SwiftyJSON tvOS Tests" */; buildPhases = ( A8580F701BCF5C5B00DA927B /* Sources */, A8580F711BCF5C5B00DA927B /* Frameworks */, A8580F721BCF5C5B00DA927B /* Resources */, ); buildRules = ( ); dependencies = ( A8580F7B1BCF5C5B00DA927B /* PBXTargetDependency */, ); name = "SwiftyJSON tvOS Tests"; productName = "SwiftyJSON tvOS Tests"; productReference = A8580F741BCF5C5B00DA927B /* SwiftyJSON tvOS Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; E4D7CCDE1B9465A700EE7221 /* SwiftyJSON watchOS */ = { isa = PBXNativeTarget; buildConfigurationList = E4D7CCE51B9465A700EE7221 /* Build configuration list for PBXNativeTarget "SwiftyJSON watchOS" */; buildPhases = ( E4D7CCDF1B9465A700EE7221 /* Sources */, E4D7CCE11B9465A700EE7221 /* Frameworks */, E4D7CCE21B9465A700EE7221 /* Headers */, E4D7CCE41B9465A700EE7221 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "SwiftyJSON watchOS"; productName = SwiftyJSON; productReference = E4D7CCE81B9465A700EE7221 /* SwiftyJSON.framework */; productType = "com.apple.product-type.framework"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 2E4FEFD219575BE100351305 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0710; LastUpgradeCheck = 0700; TargetAttributes = { 2E4FEFDA19575BE100351305 = { CreatedOnToolsVersion = 6.0; }; 2E4FEFE519575BE100351305 = { CreatedOnToolsVersion = 6.0; TestTargetID = 2E4FEFDA19575BE100351305; }; 9C7DFC5A1A9102BD005AA3F7 = { CreatedOnToolsVersion = 6.1.1; }; 9C7DFC641A9102BD005AA3F7 = { CreatedOnToolsVersion = 6.1.1; }; A8580F731BCF5C5B00DA927B = { CreatedOnToolsVersion = 7.1; }; }; }; buildConfigurationList = 2E4FEFD519575BE100351305 /* Build configuration list for PBXProject "SwiftyJSON" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = 2E4FEFD119575BE100351305; productRefGroup = 2E4FEFDC19575BE100351305 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 2E4FEFDA19575BE100351305 /* SwiftyJSON iOS */, 2E4FEFE519575BE100351305 /* SwiftyJSON iOS Tests */, 9C7DFC5A1A9102BD005AA3F7 /* SwiftyJSON OSX */, 9C7DFC641A9102BD005AA3F7 /* SwiftyJSON OSX Tests */, E4D7CCDE1B9465A700EE7221 /* SwiftyJSON watchOS */, 7236B4EC1BAC14150020529B /* SwiftyJSON tvOS */, A8580F731BCF5C5B00DA927B /* SwiftyJSON tvOS Tests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 2E4FEFD919575BE100351305 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 2E4FEFE419575BE100351305 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( A885D1DC19CFCFF0002FD4C3 /* Tests.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 7236B4F21BAC14150020529B /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 9C7DFC591A9102BD005AA3F7 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 9C7DFC631A9102BD005AA3F7 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 9C459EF81A9103C1008C9A41 /* Tests.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; A8580F721BCF5C5B00DA927B /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( A81CBA0B1BCF6B0200A649A2 /* Tests.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; E4D7CCE41B9465A700EE7221 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 2E4FEFD619575BE100351305 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( A8491E1E19CD6DAE00CCFAE6 /* SwiftyJSON.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 2E4FEFE219575BE100351305 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( A87080E819E439DA00CDE086 /* NumberTests.swift in Sources */, A87080E419E3C2A600CDE086 /* SequenceTypeTests.swift in Sources */, A86BAA0E19EBC32B009EAAEB /* PerformanceTests.swift in Sources */, A819C49919E1B10300ADCC3D /* RawRepresentableTests.swift in Sources */, A819C49F19E2EE5B00ADCC3D /* SubscriptTests.swift in Sources */, A863BE2819EED46F0092A41F /* RawTests.swift in Sources */, A885D1D219CF1EE6002FD4C3 /* BaseTests.swift in Sources */, A8B66C8E19E52F4200540692 /* ArrayTests.swift in Sources */, A8B66C8C19E51D6500540692 /* DictionaryTests.swift in Sources */, A819C4A119E37FC600ADCC3D /* PrintableTests.swift in Sources */, A819C49719E1A7DD00ADCC3D /* LiteralConvertibleTests.swift in Sources */, A87080EA19E43C0700CDE086 /* StringTests.swift in Sources */, A87080E619E3DF7800CDE086 /* ComparableTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 7236B4ED1BAC14150020529B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 7236B4EE1BAC14150020529B /* SwiftyJSON.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 9C7DFC561A9102BD005AA3F7 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 9C459EF51A910361008C9A41 /* SwiftyJSON.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 9C7DFC611A9102BD005AA3F7 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 9C459EFB1A9103C1008C9A41 /* SequenceTypeTests.swift in Sources */, 9C459F001A9103C1008C9A41 /* ComparableTests.swift in Sources */, 9C459F021A9103C1008C9A41 /* NumberTests.swift in Sources */, 9C459EFF1A9103C1008C9A41 /* RawRepresentableTests.swift in Sources */, 9C459EFA1A9103C1008C9A41 /* BaseTests.swift in Sources */, 9C459F041A9103C1008C9A41 /* DictionaryTests.swift in Sources */, 9C459EF91A9103C1008C9A41 /* PerformanceTests.swift in Sources */, 9C459EFE1A9103C1008C9A41 /* LiteralConvertibleTests.swift in Sources */, 9C459EFC1A9103C1008C9A41 /* PrintableTests.swift in Sources */, 9C459F011A9103C1008C9A41 /* StringTests.swift in Sources */, 9C459F031A9103C1008C9A41 /* RawTests.swift in Sources */, 9C459F051A9103C1008C9A41 /* ArrayTests.swift in Sources */, 9C459EFD1A9103C1008C9A41 /* SubscriptTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; A8580F701BCF5C5B00DA927B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( A8580F801BCF69A000DA927B /* PerformanceTests.swift in Sources */, A8580F811BCF69A000DA927B /* BaseTests.swift in Sources */, A8580F821BCF69A000DA927B /* SequenceTypeTests.swift in Sources */, A8580F831BCF69A000DA927B /* PrintableTests.swift in Sources */, A8580F841BCF69A000DA927B /* SubscriptTests.swift in Sources */, A8580F851BCF69A000DA927B /* LiteralConvertibleTests.swift in Sources */, A8580F861BCF69A000DA927B /* RawRepresentableTests.swift in Sources */, A8580F871BCF69A000DA927B /* ComparableTests.swift in Sources */, A8580F881BCF69A000DA927B /* StringTests.swift in Sources */, A8580F891BCF69A000DA927B /* NumberTests.swift in Sources */, A8580F8A1BCF69A000DA927B /* RawTests.swift in Sources */, A8580F8B1BCF69A000DA927B /* DictionaryTests.swift in Sources */, A8580F8C1BCF69A000DA927B /* ArrayTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; E4D7CCDF1B9465A700EE7221 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E4D7CCE01B9465A700EE7221 /* SwiftyJSON.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 2E4FEFE919575BE100351305 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 2E4FEFDA19575BE100351305 /* SwiftyJSON iOS */; targetProxy = 2E4FEFE819575BE100351305 /* PBXContainerItemProxy */; }; 9C7DFC681A9102BD005AA3F7 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 9C7DFC5A1A9102BD005AA3F7 /* SwiftyJSON OSX */; targetProxy = 9C7DFC671A9102BD005AA3F7 /* PBXContainerItemProxy */; }; A8580F7B1BCF5C5B00DA927B /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 7236B4EC1BAC14150020529B /* SwiftyJSON tvOS */; targetProxy = A8580F7A1BCF5C5B00DA927B /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ 2E4FEFEF19575BE100351305 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; 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; IPHONEOS_DEPLOYMENT_TARGET = 7.0; MACOSX_DEPLOYMENT_TARGET = 10.9; METAL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; 2E4FEFF019575BE100351305 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = YES; CURRENT_PROJECT_VERSION = 1; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; 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; IPHONEOS_DEPLOYMENT_TARGET = 7.0; MACOSX_DEPLOYMENT_TARGET = 10.9; METAL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Release; }; 2E4FEFF219575BE100351305 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; BITCODE_GENERATION_MODE = bitcode; CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "Source/Info-iOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftyJSON; SKIP_INSTALL = YES; }; name = Debug; }; 2E4FEFF319575BE100351305 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; BITCODE_GENERATION_MODE = bitcode; CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "Source/Info-iOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftyJSON; SKIP_INSTALL = YES; }; name = Release; }; 2E4FEFF519575BE100351305 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = "Tests/Info-iOS.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; METAL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 2E4FEFF619575BE100351305 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { INFOPLIST_FILE = "Tests/Info-iOS.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; METAL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; 7236B4F41BAC14150020529B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "Source/Info-tvOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftyJSON; SDKROOT = appletvos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; }; 7236B4F51BAC14150020529B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "Source/Info-tvOS.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftyJSON; SDKROOT = appletvos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = 3; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Release; }; 9C7DFC6F1A9102BD005AA3F7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = "Source/Info-OSX.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; PLIST_FILE_OUTPUT_FORMAT = binary; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(PROJECT_NAME)"; SDKROOT = macosx; SKIP_INSTALL = YES; }; name = Debug; }; 9C7DFC701A9102BD005AA3F7 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; FRAMEWORK_VERSION = A; INFOPLIST_FILE = "Source/Info-OSX.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; PLIST_FILE_OUTPUT_FORMAT = binary; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(PROJECT_NAME)"; SDKROOT = macosx; SKIP_INSTALL = YES; }; name = Release; }; 9C7DFC721A9102BD005AA3F7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ""; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = "Tests/Info-OSX.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; }; name = Debug; }; 9C7DFC731A9102BD005AA3F7 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = ""; INFOPLIST_FILE = "Tests/Info-OSX.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; }; name = Release; }; A8580F7D1BCF5C5B00DA927B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { DEBUG_INFORMATION_FORMAT = dwarf; GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = "Tests/Info-tvOS.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.tangplin.SwiftyJSON-tvOS-Tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Debug; }; A8580F7E1BCF5C5B00DA927B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = "Tests/Info-tvOS.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.tangplin.SwiftyJSON-tvOS-Tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; TVOS_DEPLOYMENT_TARGET = 9.0; }; name = Release; }; E4D7CCE61B9465A700EE7221 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; BITCODE_GENERATION_MODE = bitcode; CODE_SIGN_IDENTITY = "iPhone Developer"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "Source/Info-OSX.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftyJSON; SDKROOT = watchos; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "watchsimulator watchos"; TARGETED_DEVICE_FAMILY = 4; }; name = Debug; }; E4D7CCE71B9465A700EE7221 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; BITCODE_GENERATION_MODE = bitcode; CODE_SIGN_IDENTITY = "iPhone Developer"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "Source/Info-OSX.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.swiftyjson.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = SwiftyJSON; SDKROOT = watchos; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "watchsimulator watchos"; TARGETED_DEVICE_FAMILY = 4; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 2E4FEFD519575BE100351305 /* Build configuration list for PBXProject "SwiftyJSON" */ = { isa = XCConfigurationList; buildConfigurations = ( 2E4FEFEF19575BE100351305 /* Debug */, 2E4FEFF019575BE100351305 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 2E4FEFF119575BE100351305 /* Build configuration list for PBXNativeTarget "SwiftyJSON iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 2E4FEFF219575BE100351305 /* Debug */, 2E4FEFF319575BE100351305 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 2E4FEFF419575BE100351305 /* Build configuration list for PBXNativeTarget "SwiftyJSON iOS Tests" */ = { isa = XCConfigurationList; buildConfigurations = ( 2E4FEFF519575BE100351305 /* Debug */, 2E4FEFF619575BE100351305 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 7236B4F31BAC14150020529B /* Build configuration list for PBXNativeTarget "SwiftyJSON tvOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 7236B4F41BAC14150020529B /* Debug */, 7236B4F51BAC14150020529B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 9C7DFC6E1A9102BD005AA3F7 /* Build configuration list for PBXNativeTarget "SwiftyJSON OSX" */ = { isa = XCConfigurationList; buildConfigurations = ( 9C7DFC6F1A9102BD005AA3F7 /* Debug */, 9C7DFC701A9102BD005AA3F7 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 9C7DFC711A9102BD005AA3F7 /* Build configuration list for PBXNativeTarget "SwiftyJSON OSX Tests" */ = { isa = XCConfigurationList; buildConfigurations = ( 9C7DFC721A9102BD005AA3F7 /* Debug */, 9C7DFC731A9102BD005AA3F7 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; A8580F7C1BCF5C5B00DA927B /* Build configuration list for PBXNativeTarget "SwiftyJSON tvOS Tests" */ = { isa = XCConfigurationList; buildConfigurations = ( A8580F7D1BCF5C5B00DA927B /* Debug */, A8580F7E1BCF5C5B00DA927B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; E4D7CCE51B9465A700EE7221 /* Build configuration list for PBXNativeTarget "SwiftyJSON watchOS" */ = { isa = XCConfigurationList; buildConfigurations = ( E4D7CCE61B9465A700EE7221 /* Debug */, E4D7CCE71B9465A700EE7221 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 2E4FEFD219575BE100351305 /* Project object */; } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/SwiftyJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Carthage/Checkouts/SwiftyJSON/SwiftyJSON.xcodeproj/xcshareddata/xcschemes/SwiftyJSON OSX.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/SwiftyJSON/SwiftyJSON.xcodeproj/xcshareddata/xcschemes/SwiftyJSON iOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/SwiftyJSON/SwiftyJSON.xcodeproj/xcshareddata/xcschemes/SwiftyJSON tvOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/SwiftyJSON/SwiftyJSON.xcodeproj/xcshareddata/xcschemes/SwiftyJSON watchOS.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/SwiftyJSON/SwiftyJSON.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Carthage/Checkouts/SwiftyJSON/SwiftyJSON.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings ================================================ IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Tests/ArrayTests.swift ================================================ // ArrayTests.swift // // Copyright (c) 2014 Pinglin Tang // // 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. import XCTest import SwiftyJSON class ArrayTests: XCTestCase { func testSingleDimensionalArraysGetter() { let array = ["1","2", "a", "B", "D"] let json = JSON(array) XCTAssertEqual((json.array![0] as JSON).string!, "1") XCTAssertEqual((json.array![1] as JSON).string!, "2") XCTAssertEqual((json.array![2] as JSON).string!, "a") XCTAssertEqual((json.array![3] as JSON).string!, "B") XCTAssertEqual((json.array![4] as JSON).string!, "D") } func testSingleDimensionalArraysSetter() { let array = ["1","2", "a", "B", "D"] var json = JSON(array) json.arrayObject = ["111", "222"] XCTAssertEqual((json.array![0] as JSON).string!, "111") XCTAssertEqual((json.array![1] as JSON).string!, "222") } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Tests/BaseTests.swift ================================================ // BaseTests.swift // // Copyright (c) 2014 Ruoyu Fu, Pinglin Tang // // 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. import XCTest @testable import SwiftyJSON class BaseTests: XCTestCase { var testData: NSData! override func setUp() { super.setUp() if let file = NSBundle(forClass:BaseTests.self).pathForResource("Tests", ofType: "json") { self.testData = NSData(contentsOfFile: file) } else { XCTFail("Can't find the test JSON file") } } override func tearDown() { super.tearDown() } func testInit() { let json0 = JSON(data:self.testData) XCTAssertEqual(json0.array!.count, 3) XCTAssertEqual(JSON("123").description, "123") XCTAssertEqual(JSON(["1":"2"])["1"].string!, "2") let dictionary = NSMutableDictionary() dictionary.setObject(NSNumber(double: 1.0), forKey: "number" as NSString) dictionary.setObject(NSNull(), forKey: "null" as NSString) _ = JSON(dictionary) do { let object: AnyObject = try NSJSONSerialization.JSONObjectWithData(self.testData, options: []) let json2 = JSON(object) XCTAssertEqual(json0, json2) } catch _ { } } func testCompare() { XCTAssertNotEqual(JSON("32.1234567890"), JSON(32.1234567890)) XCTAssertNotEqual(JSON("9876543210987654321"),JSON(NSNumber(unsignedLongLong:9876543210987654321))) XCTAssertNotEqual(JSON("9876543210987654321.12345678901234567890"), JSON(9876543210987654321.12345678901234567890)) XCTAssertEqual(JSON("😊"), JSON("😊")) XCTAssertNotEqual(JSON("😱"), JSON("😁")) XCTAssertEqual(JSON([123,321,456]), JSON([123,321,456])) XCTAssertNotEqual(JSON([123,321,456]), JSON(123456789)) XCTAssertNotEqual(JSON([123,321,456]), JSON("string")) XCTAssertNotEqual(JSON(["1":123,"2":321,"3":456]), JSON("string")) XCTAssertEqual(JSON(["1":123,"2":321,"3":456]), JSON(["2":321,"1":123,"3":456])) XCTAssertEqual(JSON(NSNull()),JSON(NSNull())) XCTAssertNotEqual(JSON(NSNull()), JSON(123)) } func testJSONDoesProduceValidWithCorrectKeyPath() { let json = JSON(data:self.testData) let tweets = json let tweets_array = json.array let tweets_1 = json[1] _ = tweets_1[1] let tweets_1_user_name = tweets_1["user"]["name"] let tweets_1_user_name_string = tweets_1["user"]["name"].string XCTAssertNotEqual(tweets.type, Type.Null) XCTAssert(tweets_array != nil) XCTAssertNotEqual(tweets_1.type, Type.Null) XCTAssertEqual(tweets_1_user_name, JSON("Raffi Krikorian")) XCTAssertEqual(tweets_1_user_name_string!, "Raffi Krikorian") let tweets_1_coordinates = tweets_1["coordinates"] let tweets_1_coordinates_coordinates = tweets_1_coordinates["coordinates"] let tweets_1_coordinates_coordinates_point_0_double = tweets_1_coordinates_coordinates[0].double let tweets_1_coordinates_coordinates_point_1_float = tweets_1_coordinates_coordinates[1].float let new_tweets_1_coordinates_coordinates = JSON([-122.25831,37.871609] as NSArray) XCTAssertEqual(tweets_1_coordinates_coordinates, new_tweets_1_coordinates_coordinates) XCTAssertEqual(tweets_1_coordinates_coordinates_point_0_double!, -122.25831) XCTAssertTrue(tweets_1_coordinates_coordinates_point_1_float! == 37.871609) let tweets_1_coordinates_coordinates_point_0_string = tweets_1_coordinates_coordinates[0].stringValue let tweets_1_coordinates_coordinates_point_1_string = tweets_1_coordinates_coordinates[1].stringValue XCTAssertEqual(tweets_1_coordinates_coordinates_point_0_string, "-122.25831") XCTAssertEqual(tweets_1_coordinates_coordinates_point_1_string, "37.871609") let tweets_1_coordinates_coordinates_point_0 = tweets_1_coordinates_coordinates[0] let tweets_1_coordinates_coordinates_point_1 = tweets_1_coordinates_coordinates[1] XCTAssertEqual(tweets_1_coordinates_coordinates_point_0, JSON(-122.25831)) XCTAssertEqual(tweets_1_coordinates_coordinates_point_1, JSON(37.871609)) let created_at = json[0]["created_at"].string let id_str = json[0]["id_str"].string let favorited = json[0]["favorited"].bool let id = json[0]["id"].int64 let in_reply_to_user_id_str = json[0]["in_reply_to_user_id_str"] XCTAssertEqual(created_at!, "Tue Aug 28 21:16:23 +0000 2012") XCTAssertEqual(id_str!,"240558470661799936") XCTAssertFalse(favorited!) XCTAssertEqual(id!,240558470661799936) XCTAssertEqual(in_reply_to_user_id_str.type, Type.Null) let user = json[0]["user"] let user_name = user["name"].string let user_profile_image_url = user["profile_image_url"].URL XCTAssert(user_name == "OAuth Dancer") XCTAssert(user_profile_image_url == NSURL(string: "http://a0.twimg.com/profile_images/730275945/oauth-dancer_normal.jpg")) let user_dictionary = json[0]["user"].dictionary let user_dictionary_name = user_dictionary?["name"]?.string let user_dictionary_name_profile_image_url = user_dictionary?["profile_image_url"]?.URL XCTAssert(user_dictionary_name == "OAuth Dancer") XCTAssert(user_dictionary_name_profile_image_url == NSURL(string: "http://a0.twimg.com/profile_images/730275945/oauth-dancer_normal.jpg")) } func testSequenceType() { let json = JSON(data:self.testData) XCTAssertEqual(json.count, 3) for (_, aJson) in json { XCTAssertEqual(aJson, json[0]) break } let index = 0 let keys = (json[1].dictionaryObject! as NSDictionary).allKeys as! [String] for (aKey, aJson) in json[1] { XCTAssertEqual(aKey, keys[index]) XCTAssertEqual(aJson, json[1][keys[index]]) break } } func testJSONNumberCompare() { XCTAssertEqual(JSON(12376352.123321), JSON(12376352.123321)) XCTAssertGreaterThan(JSON(20.211), JSON(20.112)) XCTAssertGreaterThanOrEqual(JSON(30.211), JSON(20.112)) XCTAssertGreaterThanOrEqual(JSON(65232), JSON(65232)) XCTAssertLessThan(JSON(-82320.211), JSON(20.112)) XCTAssertLessThanOrEqual(JSON(-320.211), JSON(123.1)) XCTAssertLessThanOrEqual(JSON(-8763), JSON(-8763)) XCTAssertEqual(JSON(12376352.123321), JSON(12376352.123321)) XCTAssertGreaterThan(JSON(20.211), JSON(20.112)) XCTAssertGreaterThanOrEqual(JSON(30.211), JSON(20.112)) XCTAssertGreaterThanOrEqual(JSON(65232), JSON(65232)) XCTAssertLessThan(JSON(-82320.211), JSON(20.112)) XCTAssertLessThanOrEqual(JSON(-320.211), JSON(123.1)) XCTAssertLessThanOrEqual(JSON(-8763), JSON(-8763)) } func testNumberConvertToString(){ XCTAssertEqual(JSON(true).stringValue, "true") XCTAssertEqual(JSON(999.9823).stringValue, "999.9823") XCTAssertEqual(JSON(true).number!.stringValue, "1") XCTAssertEqual(JSON(false).number!.stringValue, "0") XCTAssertEqual(JSON("hello").numberValue.stringValue, "0") XCTAssertEqual(JSON(NSNull()).numberValue.stringValue, "0") XCTAssertEqual(JSON(["a","b","c","d"]).numberValue.stringValue, "0") XCTAssertEqual(JSON(["a":"b","c":"d"]).numberValue.stringValue, "0") } func testNumberPrint(){ XCTAssertEqual(JSON(false).description,"false") XCTAssertEqual(JSON(true).description,"true") XCTAssertEqual(JSON(1).description,"1") XCTAssertEqual(JSON(22).description,"22") #if (arch(x86_64) || arch(arm64)) XCTAssertEqual(JSON(9.22337203685478E18).description,"9.22337203685478e+18") #elseif (arch(i386) || arch(arm)) XCTAssertEqual(JSON(2147483647).description,"2147483647") #endif XCTAssertEqual(JSON(-1).description,"-1") XCTAssertEqual(JSON(-934834834).description,"-934834834") XCTAssertEqual(JSON(-2147483648).description,"-2147483648") XCTAssertEqual(JSON(1.5555).description,"1.5555") XCTAssertEqual(JSON(-9.123456789).description,"-9.123456789") XCTAssertEqual(JSON(-0.00000000000000001).description,"-1e-17") XCTAssertEqual(JSON(-999999999999999999999999.000000000000000000000001).description,"-1e+24") XCTAssertEqual(JSON(-9999999991999999999999999.88888883433343439438493483483943948341).stringValue,"-9.999999991999999e+24") XCTAssertEqual(JSON(Int(Int.max)).description,"\(Int.max)") XCTAssertEqual(JSON(NSNumber(long: Int.min)).description,"\(Int.min)") XCTAssertEqual(JSON(NSNumber(unsignedLong: UInt.max)).description,"\(UInt.max)") XCTAssertEqual(JSON(NSNumber(unsignedLongLong: UInt64.max)).description,"\(UInt64.max)") XCTAssertEqual(JSON(NSNumber(longLong: Int64.max)).description,"\(Int64.max)") XCTAssertEqual(JSON(NSNumber(unsignedLongLong: UInt64.max)).description,"\(UInt64.max)") XCTAssertEqual(JSON(Double.infinity).description,"inf") XCTAssertEqual(JSON(-Double.infinity).description,"-inf") XCTAssertEqual(JSON(Double.NaN).description,"nan") XCTAssertEqual(JSON(1.0/0.0).description,"inf") XCTAssertEqual(JSON(-1.0/0.0).description,"-inf") XCTAssertEqual(JSON(0.0/0.0).description,"nan") } func testNullJSON() { XCTAssertEqual(JSON(NSNull()).debugDescription,"null") let json:JSON = nil XCTAssertEqual(json.debugDescription,"null") XCTAssertNil(json.error) let json1:JSON = JSON(NSNull()) if json1 != nil { XCTFail("json1 should be nil") } } func testExistance() { let dictionary = ["number":1111] let json = JSON(dictionary) XCTAssertFalse(json["unspecifiedValue"].isExists()) XCTAssertTrue(json["number"].isExists()) } func testErrorHandle() { let json = JSON(data:self.testData) if let _ = json["wrong-type"].string { XCTFail("Should not run into here") } else { XCTAssertEqual(json["wrong-type"].error!.code, SwiftyJSON.ErrorWrongType) } if let _ = json[0]["not-exist"].string { XCTFail("Should not run into here") } else { XCTAssertEqual(json[0]["not-exist"].error!.code, SwiftyJSON.ErrorNotExist) } let wrongJSON = JSON(NSObject()) if let error = wrongJSON.error { XCTAssertEqual(error.code, SwiftyJSON.ErrorUnsupportedType) } } func testReturnObject() { let json = JSON(data:self.testData) XCTAssertNotNil(json.object) } func testNumberCompare(){ XCTAssertEqual(NSNumber(double: 888332), NSNumber(int:888332)) XCTAssertNotEqual(NSNumber(double: 888332.1), NSNumber(int:888332)) XCTAssertLessThan(NSNumber(int: 888332).doubleValue, NSNumber(double:888332.1).doubleValue) XCTAssertGreaterThan(NSNumber(double: 888332.1).doubleValue, NSNumber(int:888332).doubleValue) XCTAssertFalse(NSNumber(double: 1) == NSNumber(bool:true)) XCTAssertFalse(NSNumber(int: 0) == NSNumber(bool:false)) XCTAssertEqual(NSNumber(bool: false), NSNumber(bool:false)) XCTAssertEqual(NSNumber(bool: true), NSNumber(bool:true)) } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Tests/ComparableTests.swift ================================================ // ComparableTests.swift // // Copyright (c) 2014 Pinglin Tang // // 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. import XCTest import SwiftyJSON class ComparableTests: XCTestCase { func testNumberEqual() { let jsonL1:JSON = 1234567890.876623 let jsonR1:JSON = JSON(1234567890.876623) XCTAssertEqual(jsonL1, jsonR1) XCTAssertTrue(jsonL1 == 1234567890.876623) let jsonL2:JSON = 987654321 let jsonR2:JSON = JSON(987654321) XCTAssertEqual(jsonL2, jsonR2) XCTAssertTrue(jsonR2 == 987654321) let jsonL3:JSON = JSON(NSNumber(double:87654321.12345678)) let jsonR3:JSON = JSON(NSNumber(double:87654321.12345678)) XCTAssertEqual(jsonL3, jsonR3) XCTAssertTrue(jsonR3 == 87654321.12345678) } func testNumberNotEqual() { let jsonL1:JSON = 1234567890.876623 let jsonR1:JSON = JSON(123.123) XCTAssertNotEqual(jsonL1, jsonR1) XCTAssertFalse(jsonL1 == 34343) let jsonL2:JSON = 8773 let jsonR2:JSON = JSON(123.23) XCTAssertNotEqual(jsonL2, jsonR2) XCTAssertFalse(jsonR1 == 454352) let jsonL3:JSON = JSON(NSNumber(double:87621.12345678)) let jsonR3:JSON = JSON(NSNumber(double:87654321.45678)) XCTAssertNotEqual(jsonL3, jsonR3) XCTAssertFalse(jsonL3 == 4545.232) } func testNumberGreaterThanOrEqual() { let jsonL1:JSON = 1234567890.876623 let jsonR1:JSON = JSON(123.123) XCTAssertGreaterThanOrEqual(jsonL1, jsonR1) XCTAssertTrue(jsonL1 >= -37434) let jsonL2:JSON = 8773 let jsonR2:JSON = JSON(-87343) XCTAssertGreaterThanOrEqual(jsonL2, jsonR2) XCTAssertTrue(jsonR2 >= -988343) let jsonL3:JSON = JSON(NSNumber(double:87621.12345678)) let jsonR3:JSON = JSON(NSNumber(double:87621.12345678)) XCTAssertGreaterThanOrEqual(jsonL3, jsonR3) XCTAssertTrue(jsonR3 >= 0.3232) } func testNumberLessThanOrEqual() { let jsonL1:JSON = 1234567890.876623 let jsonR1:JSON = JSON(123.123) XCTAssertLessThanOrEqual(jsonR1, jsonL1) XCTAssertFalse(83487343.3493 <= jsonR1) let jsonL2:JSON = 8773 let jsonR2:JSON = JSON(-123.23) XCTAssertLessThanOrEqual(jsonR2, jsonL2) XCTAssertFalse(9348343 <= jsonR2) let jsonL3:JSON = JSON(NSNumber(double:87621.12345678)) let jsonR3:JSON = JSON(NSNumber(double:87621.12345678)) XCTAssertLessThanOrEqual(jsonR3, jsonL3) XCTAssertTrue(87621.12345678 <= jsonR3) } func testNumberGreaterThan() { let jsonL1:JSON = 1234567890.876623 let jsonR1:JSON = JSON(123.123) XCTAssertGreaterThan(jsonL1, jsonR1) XCTAssertFalse(jsonR1 > 192388843.0988) let jsonL2:JSON = 8773 let jsonR2:JSON = JSON(123.23) XCTAssertGreaterThan(jsonL2, jsonR2) XCTAssertFalse(jsonR2 > 877434) let jsonL3:JSON = JSON(NSNumber(double:87621.12345678)) let jsonR3:JSON = JSON(NSNumber(double:87621.1234567)) XCTAssertGreaterThan(jsonL3, jsonR3) XCTAssertFalse(-7799 > jsonR3) } func testNumberLessThan() { let jsonL1:JSON = 1234567890.876623 let jsonR1:JSON = JSON(123.123) XCTAssertLessThan(jsonR1, jsonL1) XCTAssertTrue(jsonR1 < 192388843.0988) let jsonL2:JSON = 8773 let jsonR2:JSON = JSON(123.23) XCTAssertLessThan(jsonR2, jsonL2) XCTAssertTrue(jsonR2 < 877434) let jsonL3:JSON = JSON(NSNumber(double:87621.12345678)) let jsonR3:JSON = JSON(NSNumber(double:87621.1234567)) XCTAssertLessThan(jsonR3, jsonL3) XCTAssertTrue(-7799 < jsonR3) } func testBoolEqual() { let jsonL1:JSON = true let jsonR1:JSON = JSON(true) XCTAssertEqual(jsonL1, jsonR1) XCTAssertTrue(jsonL1 == true) let jsonL2:JSON = false let jsonR2:JSON = JSON(false) XCTAssertEqual(jsonL2, jsonR2) XCTAssertTrue(jsonL2 == false) } func testBoolNotEqual() { let jsonL1:JSON = true let jsonR1:JSON = JSON(false) XCTAssertNotEqual(jsonL1, jsonR1) XCTAssertTrue(jsonL1 != false) let jsonL2:JSON = false let jsonR2:JSON = JSON(true) XCTAssertNotEqual(jsonL2, jsonR2) XCTAssertTrue(jsonL2 != true) } func testBoolGreaterThanOrEqual() { let jsonL1:JSON = true let jsonR1:JSON = JSON(true) XCTAssertGreaterThanOrEqual(jsonL1, jsonR1) XCTAssertTrue(jsonL1 >= true) let jsonL2:JSON = false let jsonR2:JSON = JSON(false) XCTAssertGreaterThanOrEqual(jsonL2, jsonR2) XCTAssertFalse(jsonL2 >= true) } func testBoolLessThanOrEqual() { let jsonL1:JSON = true let jsonR1:JSON = JSON(true) XCTAssertLessThanOrEqual(jsonL1, jsonR1) XCTAssertTrue(true <= jsonR1) let jsonL2:JSON = false let jsonR2:JSON = JSON(false) XCTAssertLessThanOrEqual(jsonL2, jsonR2) XCTAssertFalse(jsonL2 <= true) } func testBoolGreaterThan() { let jsonL1:JSON = true let jsonR1:JSON = JSON(true) XCTAssertFalse(jsonL1 > jsonR1) XCTAssertFalse(jsonL1 > true) XCTAssertFalse(jsonR1 > false) let jsonL2:JSON = false let jsonR2:JSON = JSON(false) XCTAssertFalse(jsonL2 > jsonR2) XCTAssertFalse(jsonL2 > false) XCTAssertFalse(jsonR2 > true) let jsonL3:JSON = true let jsonR3:JSON = JSON(false) XCTAssertFalse(jsonL3 > jsonR3) XCTAssertFalse(jsonL3 > false) XCTAssertFalse(jsonR3 > true) let jsonL4:JSON = false let jsonR4:JSON = JSON(true) XCTAssertFalse(jsonL4 > jsonR4) XCTAssertFalse(jsonL4 > false) XCTAssertFalse(jsonR4 > true) } func testBoolLessThan() { let jsonL1:JSON = true let jsonR1:JSON = JSON(true) XCTAssertFalse(jsonL1 < jsonR1) XCTAssertFalse(jsonL1 < true) XCTAssertFalse(jsonR1 < false) let jsonL2:JSON = false let jsonR2:JSON = JSON(false) XCTAssertFalse(jsonL2 < jsonR2) XCTAssertFalse(jsonL2 < false) XCTAssertFalse(jsonR2 < true) let jsonL3:JSON = true let jsonR3:JSON = JSON(false) XCTAssertFalse(jsonL3 < jsonR3) XCTAssertFalse(jsonL3 < false) XCTAssertFalse(jsonR3 < true) let jsonL4:JSON = false let jsonR4:JSON = JSON(true) XCTAssertFalse(jsonL4 < jsonR4) XCTAssertFalse(jsonL4 < false) XCTAssertFalse(true < jsonR4) } func testStringEqual() { let jsonL1:JSON = "abcdefg 123456789 !@#$%^&*()" let jsonR1:JSON = JSON("abcdefg 123456789 !@#$%^&*()") XCTAssertEqual(jsonL1, jsonR1) XCTAssertTrue(jsonL1 == "abcdefg 123456789 !@#$%^&*()") } func testStringNotEqual() { let jsonL1:JSON = "abcdefg 123456789 !@#$%^&*()" let jsonR1:JSON = JSON("-=[]\\\"987654321") XCTAssertNotEqual(jsonL1, jsonR1) XCTAssertTrue(jsonL1 != "not equal") } func testStringGreaterThanOrEqual() { let jsonL1:JSON = "abcdefg 123456789 !@#$%^&*()" let jsonR1:JSON = JSON("abcdefg 123456789 !@#$%^&*()") XCTAssertGreaterThanOrEqual(jsonL1, jsonR1) XCTAssertTrue(jsonL1 >= "abcdefg 123456789 !@#$%^&*()") let jsonL2:JSON = "z-+{}:" let jsonR2:JSON = JSON("a<>?:") XCTAssertGreaterThanOrEqual(jsonL2, jsonR2) XCTAssertTrue(jsonL2 >= "mnbvcxz") } func testStringLessThanOrEqual() { let jsonL1:JSON = "abcdefg 123456789 !@#$%^&*()" let jsonR1:JSON = JSON("abcdefg 123456789 !@#$%^&*()") XCTAssertLessThanOrEqual(jsonL1, jsonR1) XCTAssertTrue(jsonL1 <= "abcdefg 123456789 !@#$%^&*()") let jsonL2:JSON = "z-+{}:" let jsonR2:JSON = JSON("a<>?:") XCTAssertLessThanOrEqual(jsonR2, jsonL2) XCTAssertTrue("mnbvcxz" <= jsonL2) } func testStringGreaterThan() { let jsonL1:JSON = "abcdefg 123456789 !@#$%^&*()" let jsonR1:JSON = JSON("abcdefg 123456789 !@#$%^&*()") XCTAssertFalse(jsonL1 > jsonR1) XCTAssertFalse(jsonL1 > "abcdefg 123456789 !@#$%^&*()") let jsonL2:JSON = "z-+{}:" let jsonR2:JSON = JSON("a<>?:") XCTAssertGreaterThan(jsonL2, jsonR2) XCTAssertFalse("87663434" > jsonL2) } func testStringLessThan() { let jsonL1:JSON = "abcdefg 123456789 !@#$%^&*()" let jsonR1:JSON = JSON("abcdefg 123456789 !@#$%^&*()") XCTAssertFalse(jsonL1 < jsonR1) XCTAssertFalse(jsonL1 < "abcdefg 123456789 !@#$%^&*()") let jsonL2:JSON = "98774" let jsonR2:JSON = JSON("123456") XCTAssertLessThan(jsonR2, jsonL2) XCTAssertFalse(jsonL2 < "09") } func testNil() { let jsonL1:JSON = nil let jsonR1:JSON = JSON(NSNull()) XCTAssertEqual(jsonL1, jsonR1) XCTAssertTrue(jsonL1 != "123") XCTAssertFalse(jsonL1 > "abcd") XCTAssertFalse(jsonR1 < "*&^") XCTAssertFalse(jsonL1 >= "jhfid") XCTAssertFalse(jsonR1 <= "你好") XCTAssertTrue(jsonL1 >= jsonR1) XCTAssertTrue(jsonL1 <= jsonR1) } func testArray() { let jsonL1:JSON = [1,2,"4",5,"6"] let jsonR1:JSON = JSON([1,2,"4",5,"6"]) XCTAssertEqual(jsonL1, jsonR1) XCTAssertTrue(jsonL1 == [1,2,"4",5,"6"]) XCTAssertTrue(jsonL1 != ["abcd","efg"]) XCTAssertTrue(jsonL1 >= jsonR1) XCTAssertTrue(jsonL1 <= jsonR1) XCTAssertFalse(jsonL1 > ["abcd",""]) XCTAssertFalse(jsonR1 < []) XCTAssertFalse(jsonL1 >= [:]) } func testDictionary() { let jsonL1:JSON = ["2": 2, "name": "Jack", "List": ["a", 1.09, NSNull()]] let jsonR1:JSON = JSON(["2": 2, "name": "Jack", "List": ["a", 1.09, NSNull()]]) XCTAssertEqual(jsonL1, jsonR1) XCTAssertTrue(jsonL1 != ["1":2,"Hello":"World","Koo":"Foo"]) XCTAssertTrue(jsonL1 >= jsonR1) XCTAssertTrue(jsonL1 <= jsonR1) XCTAssertFalse(jsonL1 >= [:]) XCTAssertFalse(jsonR1 <= ["999":"aaaa"]) XCTAssertFalse(jsonL1 > [")(*&^":1234567]) XCTAssertFalse(jsonR1 < ["MNHH":"JUYTR"]) } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Tests/DictionaryTests.swift ================================================ // DictionaryTests.swift // // Copyright (c) 2014 Pinglin Tang // // 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. import XCTest import SwiftyJSON class DictionaryTests: XCTestCase { func testGetter() { let dictionary = ["number":9823.212, "name":"NAME", "list":[1234, 4.212], "object":["sub_number":877.2323, "sub_name":"sub_name"], "bool":true] let json = JSON(dictionary) //dictionary XCTAssertEqual((json.dictionary!["number"]! as JSON).double!, 9823.212) XCTAssertEqual((json.dictionary!["name"]! as JSON).string!, "NAME") XCTAssertEqual(((json.dictionary!["list"]! as JSON).array![0] as JSON).int!, 1234) XCTAssertEqual(((json.dictionary!["list"]! as JSON).array![1] as JSON).double!, 4.212) XCTAssertEqual((((json.dictionary!["object"]! as JSON).dictionaryValue)["sub_number"]! as JSON).double!, 877.2323) XCTAssertTrue(json.dictionary!["null"] == nil) //dictionaryValue XCTAssertEqual(((((json.dictionaryValue)["object"]! as JSON).dictionaryValue)["sub_name"]! as JSON).string!, "sub_name") XCTAssertEqual((json.dictionaryValue["bool"]! as JSON).bool!, true) XCTAssertTrue(json.dictionaryValue["null"] == nil) XCTAssertTrue(JSON.null.dictionaryValue == [:]) //dictionaryObject XCTAssertEqual(json.dictionaryObject!["number"]! as? Double, 9823.212) XCTAssertTrue(json.dictionaryObject!["null"] == nil) XCTAssertTrue(JSON.null.dictionaryObject == nil) } func testSetter() { var json:JSON = ["test":"case"] XCTAssertEqual(json.dictionaryObject! as! [String : String], ["test":"case"]) json.dictionaryObject = ["name":"NAME"] XCTAssertEqual(json.dictionaryObject! as! [String : String], ["name":"NAME"]) } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Tests/Info-OSX.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Tests/Info-iOS.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Tests/Info-tvOS.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Tests/LiteralConvertibleTests.swift ================================================ // LiteralConvertibleTests.swift // // Copyright (c) 2014 Pinglin Tang // // 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. import XCTest import SwiftyJSON class LiteralConvertibleTests: XCTestCase { func testNumber() { var json:JSON = 1234567890.876623 XCTAssertEqual(json.int!, 1234567890) XCTAssertEqual(json.intValue, 1234567890) XCTAssertEqual(json.double!, 1234567890.876623) XCTAssertEqual(json.doubleValue, 1234567890.876623) XCTAssertTrue(json.float! == 1234567890.876623) XCTAssertTrue(json.floatValue == 1234567890.876623) } func testBool() { var jsonTrue:JSON = true XCTAssertEqual(jsonTrue.bool!, true) XCTAssertEqual(jsonTrue.boolValue, true) var jsonFalse:JSON = false XCTAssertEqual(jsonFalse.bool!, false) XCTAssertEqual(jsonFalse.boolValue, false) } func testString() { var json:JSON = "abcd efg, HIJK;LMn" XCTAssertEqual(json.string!, "abcd efg, HIJK;LMn") XCTAssertEqual(json.stringValue, "abcd efg, HIJK;LMn") } func testNil() { let jsonNil_1:JSON = nil XCTAssert(jsonNil_1 == nil) let jsonNil_2:JSON = JSON(NSNull) XCTAssert(jsonNil_2 != nil) let jsonNil_3:JSON = JSON([1:2]) XCTAssert(jsonNil_3 != nil) } func testArray() { let json:JSON = [1,2,"4",5,"6"] XCTAssertEqual(json.array!, [1,2,"4",5,"6"]) XCTAssertEqual(json.arrayValue, [1,2,"4",5,"6"]) } func testDictionary() { let json:JSON = ["1":2,"2":2,"three":3,"list":["aa","bb","dd"]] XCTAssertEqual(json.dictionary!, ["1":2,"2":2,"three":3,"list":["aa","bb","dd"]]) XCTAssertEqual(json.dictionaryValue, ["1":2,"2":2,"three":3,"list":["aa","bb","dd"]]) } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Tests/NumberTests.swift ================================================ // NumberTests.swift // // Copyright (c) 2014 Pinglin Tang // // 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. import XCTest import SwiftyJSON class NumberTests: XCTestCase { func testNumber() { //getter var json = JSON(NSNumber(double: 9876543210.123456789)) XCTAssertEqual(json.number!, 9876543210.123456789) XCTAssertEqual(json.numberValue, 9876543210.123456789) XCTAssertEqual(json.stringValue, "9876543210.123457") json.string = "1000000000000000000000000000.1" XCTAssertNil(json.number) XCTAssertEqual(json.numberValue.description, "1000000000000000000000000000.1") json.string = "1e+27" XCTAssertEqual(json.numberValue.description, "1000000000000000000000000000") //setter json.number = NSNumber(double: 123456789.0987654321) XCTAssertEqual(json.number!, 123456789.0987654321) XCTAssertEqual(json.numberValue, 123456789.0987654321) json.number = nil XCTAssertEqual(json.numberValue, 0) XCTAssertEqual(json.object as? NSNull, NSNull()) XCTAssertTrue(json.number == nil) json.numberValue = 2.9876 XCTAssertEqual(json.number!, 2.9876) } func testBool() { var json = JSON(true) XCTAssertEqual(json.bool!, true) XCTAssertEqual(json.boolValue, true) XCTAssertEqual(json.numberValue, true as NSNumber) XCTAssertEqual(json.stringValue, "true") json.bool = false XCTAssertEqual(json.bool!, false) XCTAssertEqual(json.boolValue, false) XCTAssertEqual(json.numberValue, false as NSNumber) json.bool = nil XCTAssertTrue(json.bool == nil) XCTAssertEqual(json.boolValue, false) XCTAssertEqual(json.numberValue, 0) json.boolValue = true XCTAssertEqual(json.bool!, true) XCTAssertEqual(json.boolValue, true) XCTAssertEqual(json.numberValue, true as NSNumber) } func testDouble() { var json = JSON(9876543210.123456789) XCTAssertEqual(json.double!, 9876543210.123456789) XCTAssertEqual(json.doubleValue, 9876543210.123456789) XCTAssertEqual(json.numberValue, 9876543210.123456789) XCTAssertEqual(json.stringValue, "9876543210.123457") json.double = 2.8765432 XCTAssertEqual(json.double!, 2.8765432) XCTAssertEqual(json.doubleValue, 2.8765432) XCTAssertEqual(json.numberValue, 2.8765432) json.doubleValue = 89.0987654 XCTAssertEqual(json.double!, 89.0987654) XCTAssertEqual(json.doubleValue, 89.0987654) XCTAssertEqual(json.numberValue, 89.0987654) json.double = nil XCTAssertEqual(json.boolValue, false) XCTAssertEqual(json.doubleValue, 0.0) XCTAssertEqual(json.numberValue, 0) } func testFloat() { var json = JSON(54321.12345) XCTAssertTrue(json.float! == 54321.12345) XCTAssertTrue(json.floatValue == 54321.12345) print(json.numberValue.doubleValue) XCTAssertEqual(json.numberValue, 54321.12345) XCTAssertEqual(json.stringValue, "54321.12345") json.float = 23231.65 XCTAssertTrue(json.float! == 23231.65) XCTAssertTrue(json.floatValue == 23231.65) XCTAssertEqual(json.numberValue, NSNumber(float:23231.65)) json.floatValue = -98766.23 XCTAssertEqual(json.float!, -98766.23) XCTAssertEqual(json.floatValue, -98766.23) XCTAssertEqual(json.numberValue, NSNumber(float:-98766.23)) } func testInt() { var json = JSON(123456789) XCTAssertEqual(json.int!, 123456789) XCTAssertEqual(json.intValue, 123456789) XCTAssertEqual(json.numberValue, NSNumber(integer: 123456789)) XCTAssertEqual(json.stringValue, "123456789") json.int = nil XCTAssertTrue(json.boolValue == false) XCTAssertTrue(json.intValue == 0) XCTAssertEqual(json.numberValue, 0) XCTAssertEqual(json.object as? NSNull, NSNull()) XCTAssertTrue(json.int == nil) json.intValue = 76543 XCTAssertEqual(json.int!, 76543) XCTAssertEqual(json.intValue, 76543) XCTAssertEqual(json.numberValue, NSNumber(integer: 76543)) json.intValue = 98765421 XCTAssertEqual(json.int!, 98765421) XCTAssertEqual(json.intValue, 98765421) XCTAssertEqual(json.numberValue, NSNumber(integer: 98765421)) } func testUInt() { var json = JSON(123456789) XCTAssertTrue(json.uInt! == 123456789) XCTAssertTrue(json.uIntValue == 123456789) XCTAssertEqual(json.numberValue, NSNumber(unsignedInteger: 123456789)) XCTAssertEqual(json.stringValue, "123456789") json.uInt = nil XCTAssertTrue(json.boolValue == false) XCTAssertTrue(json.uIntValue == 0) XCTAssertEqual(json.numberValue, 0) XCTAssertEqual(json.object as? NSNull, NSNull()) XCTAssertTrue(json.uInt == nil) json.uIntValue = 76543 XCTAssertTrue(json.uInt! == 76543) XCTAssertTrue(json.uIntValue == 76543) XCTAssertEqual(json.numberValue, NSNumber(unsignedInteger: 76543)) json.uIntValue = 98765421 XCTAssertTrue(json.uInt! == 98765421) XCTAssertTrue(json.uIntValue == 98765421) XCTAssertEqual(json.numberValue, NSNumber(unsignedInteger: 98765421)) } func testInt8() { let n127 = NSNumber(char: 127) var json = JSON(n127) XCTAssertTrue(json.int8! == n127.charValue) XCTAssertTrue(json.int8Value == n127.charValue) XCTAssertTrue(json.number! == n127) XCTAssertEqual(json.numberValue, n127) XCTAssertEqual(json.stringValue, "127") let nm128 = NSNumber(char: -128) json.int8Value = nm128.charValue XCTAssertTrue(json.int8! == nm128.charValue) XCTAssertTrue(json.int8Value == nm128.charValue) XCTAssertTrue(json.number! == nm128) XCTAssertEqual(json.numberValue, nm128) XCTAssertEqual(json.stringValue, "-128") let n0 = NSNumber(char: 0 as Int8) json.int8Value = n0.charValue XCTAssertTrue(json.int8! == n0.charValue) XCTAssertTrue(json.int8Value == n0.charValue) print(json.number) XCTAssertTrue(json.number! == n0) XCTAssertEqual(json.numberValue, n0) #if (arch(x86_64) || arch(arm64)) XCTAssertEqual(json.stringValue, "false") #elseif (arch(i386) || arch(arm)) XCTAssertEqual(json.stringValue, "0") #endif let n1 = NSNumber(char: 1 as Int8) json.int8Value = n1.charValue XCTAssertTrue(json.int8! == n1.charValue) XCTAssertTrue(json.int8Value == n1.charValue) XCTAssertTrue(json.number! == n1) XCTAssertEqual(json.numberValue, n1) #if (arch(x86_64) || arch(arm64)) XCTAssertEqual(json.stringValue, "true") #elseif (arch(i386) || arch(arm)) XCTAssertEqual(json.stringValue, "1") #endif } func testUInt8() { let n255 = NSNumber(unsignedChar: 255) var json = JSON(n255) XCTAssertTrue(json.uInt8! == n255.unsignedCharValue) XCTAssertTrue(json.uInt8Value == n255.unsignedCharValue) XCTAssertTrue(json.number! == n255) XCTAssertEqual(json.numberValue, n255) XCTAssertEqual(json.stringValue, "255") let nm2 = NSNumber(unsignedChar: 2) json.uInt8Value = nm2.unsignedCharValue XCTAssertTrue(json.uInt8! == nm2.unsignedCharValue) XCTAssertTrue(json.uInt8Value == nm2.unsignedCharValue) XCTAssertTrue(json.number! == nm2) XCTAssertEqual(json.numberValue, nm2) XCTAssertEqual(json.stringValue, "2") let nm0 = NSNumber(unsignedChar: 0) json.uInt8Value = nm0.unsignedCharValue XCTAssertTrue(json.uInt8! == nm0.unsignedCharValue) XCTAssertTrue(json.uInt8Value == nm0.unsignedCharValue) XCTAssertTrue(json.number! == nm0) XCTAssertEqual(json.numberValue, nm0) XCTAssertEqual(json.stringValue, "0") let nm1 = NSNumber(unsignedChar: 1) json.uInt8 = nm1.unsignedCharValue XCTAssertTrue(json.uInt8! == nm1.unsignedCharValue) XCTAssertTrue(json.uInt8Value == nm1.unsignedCharValue) XCTAssertTrue(json.number! == nm1) XCTAssertEqual(json.numberValue, nm1) XCTAssertEqual(json.stringValue, "1") } func testInt16() { let n32767 = NSNumber(short: 32767) var json = JSON(n32767) XCTAssertTrue(json.int16! == n32767.shortValue) XCTAssertTrue(json.int16Value == n32767.shortValue) XCTAssertTrue(json.number! == n32767) XCTAssertEqual(json.numberValue, n32767) XCTAssertEqual(json.stringValue, "32767") let nm32768 = NSNumber(short: -32768) json.int16Value = nm32768.shortValue XCTAssertTrue(json.int16! == nm32768.shortValue) XCTAssertTrue(json.int16Value == nm32768.shortValue) XCTAssertTrue(json.number! == nm32768) XCTAssertEqual(json.numberValue, nm32768) XCTAssertEqual(json.stringValue, "-32768") let n0 = NSNumber(short: 0) json.int16Value = n0.shortValue XCTAssertTrue(json.int16! == n0.shortValue) XCTAssertTrue(json.int16Value == n0.shortValue) print(json.number) XCTAssertTrue(json.number! == n0) XCTAssertEqual(json.numberValue, n0) XCTAssertEqual(json.stringValue, "0") let n1 = NSNumber(short: 1) json.int16 = n1.shortValue XCTAssertTrue(json.int16! == n1.shortValue) XCTAssertTrue(json.int16Value == n1.shortValue) XCTAssertTrue(json.number! == n1) XCTAssertEqual(json.numberValue, n1) XCTAssertEqual(json.stringValue, "1") } func testUInt16() { let n65535 = NSNumber(unsignedInteger: 65535) var json = JSON(n65535) XCTAssertTrue(json.uInt16! == n65535.unsignedShortValue) XCTAssertTrue(json.uInt16Value == n65535.unsignedShortValue) XCTAssertTrue(json.number! == n65535) XCTAssertEqual(json.numberValue, n65535) XCTAssertEqual(json.stringValue, "65535") let n32767 = NSNumber(unsignedInteger: 32767) json.uInt16 = n32767.unsignedShortValue XCTAssertTrue(json.uInt16! == n32767.unsignedShortValue) XCTAssertTrue(json.uInt16Value == n32767.unsignedShortValue) XCTAssertTrue(json.number! == n32767) XCTAssertEqual(json.numberValue, n32767) XCTAssertEqual(json.stringValue, "32767") } func testInt32() { let n2147483647 = NSNumber(int: 2147483647) var json = JSON(n2147483647) XCTAssertTrue(json.int32! == n2147483647.intValue) XCTAssertTrue(json.int32Value == n2147483647.intValue) XCTAssertTrue(json.number! == n2147483647) XCTAssertEqual(json.numberValue, n2147483647) XCTAssertEqual(json.stringValue, "2147483647") let n32767 = NSNumber(int: 32767) json.int32 = n32767.intValue XCTAssertTrue(json.int32! == n32767.intValue) XCTAssertTrue(json.int32Value == n32767.intValue) XCTAssertTrue(json.number! == n32767) XCTAssertEqual(json.numberValue, n32767) XCTAssertEqual(json.stringValue, "32767") let nm2147483648 = NSNumber(int: -2147483648) json.int32Value = nm2147483648.intValue XCTAssertTrue(json.int32! == nm2147483648.intValue) XCTAssertTrue(json.int32Value == nm2147483648.intValue) XCTAssertTrue(json.number! == nm2147483648) XCTAssertEqual(json.numberValue, nm2147483648) XCTAssertEqual(json.stringValue, "-2147483648") } func testUInt32() { let n2147483648 = NSNumber(unsignedInt: 2147483648) var json = JSON(n2147483648) XCTAssertTrue(json.uInt32! == n2147483648.unsignedIntValue) XCTAssertTrue(json.uInt32Value == n2147483648.unsignedIntValue) XCTAssertTrue(json.number! == n2147483648) XCTAssertEqual(json.numberValue, n2147483648) XCTAssertEqual(json.stringValue, "2147483648") let n32767 = NSNumber(unsignedInt: 32767) json.uInt32 = n32767.unsignedIntValue XCTAssertTrue(json.uInt32! == n32767.unsignedIntValue) XCTAssertTrue(json.uInt32Value == n32767.unsignedIntValue) XCTAssertTrue(json.number! == n32767) XCTAssertEqual(json.numberValue, n32767) XCTAssertEqual(json.stringValue, "32767") let n0 = NSNumber(unsignedInt: 0) json.uInt32Value = n0.unsignedIntValue XCTAssertTrue(json.uInt32! == n0.unsignedIntValue) XCTAssertTrue(json.uInt32Value == n0.unsignedIntValue) XCTAssertTrue(json.number! == n0) XCTAssertEqual(json.numberValue, n0) XCTAssertEqual(json.stringValue, "0") } func testInt64() { let int64Max = NSNumber(longLong: INT64_MAX) var json = JSON(int64Max) XCTAssertTrue(json.int64! == int64Max.longLongValue) XCTAssertTrue(json.int64Value == int64Max.longLongValue) XCTAssertTrue(json.number! == int64Max) XCTAssertEqual(json.numberValue, int64Max) XCTAssertEqual(json.stringValue, int64Max.stringValue) let n32767 = NSNumber(longLong: 32767) json.int64 = n32767.longLongValue XCTAssertTrue(json.int64! == n32767.longLongValue) XCTAssertTrue(json.int64Value == n32767.longLongValue) XCTAssertTrue(json.number! == n32767) XCTAssertEqual(json.numberValue, n32767) XCTAssertEqual(json.stringValue, "32767") let int64Min = NSNumber(longLong: (INT64_MAX-1) * -1) json.int64Value = int64Min.longLongValue XCTAssertTrue(json.int64! == int64Min.longLongValue) XCTAssertTrue(json.int64Value == int64Min.longLongValue) XCTAssertTrue(json.number! == int64Min) XCTAssertEqual(json.numberValue, int64Min) XCTAssertEqual(json.stringValue, int64Min.stringValue) } func testUInt64() { let uInt64Max = NSNumber(unsignedLongLong: UINT64_MAX) var json = JSON(uInt64Max) XCTAssertTrue(json.uInt64! == uInt64Max.unsignedLongLongValue) XCTAssertTrue(json.uInt64Value == uInt64Max.unsignedLongLongValue) XCTAssertTrue(json.number! == uInt64Max) XCTAssertEqual(json.numberValue, uInt64Max) XCTAssertEqual(json.stringValue, uInt64Max.stringValue) let n32767 = NSNumber(longLong: 32767) json.int64 = n32767.longLongValue XCTAssertTrue(json.int64! == n32767.longLongValue) XCTAssertTrue(json.int64Value == n32767.longLongValue) XCTAssertTrue(json.number! == n32767) XCTAssertEqual(json.numberValue, n32767) XCTAssertEqual(json.stringValue, "32767") } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Tests/PerformanceTests.swift ================================================ // PerformanceTests.swift // // Copyright (c) 2014 Pinglin Tang // // 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. import XCTest import SwiftyJSON class PerformanceTests: XCTestCase { var testData: NSData! override func setUp() { super.setUp() if let file = NSBundle(forClass:PerformanceTests.self).pathForResource("Tests", ofType: "json") { self.testData = NSData(contentsOfFile: file) } else { XCTFail("Can't find the test JSON file") } } override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() } func testInitPerformance() { self.measureBlock() { for _ in 1...100 { let json = JSON(data:self.testData) XCTAssertTrue(json != JSON.null) } } } func testObjectMethodPerformance() { var json = JSON(data:self.testData) self.measureBlock() { for _ in 1...100 { let object:AnyObject? = json.object XCTAssertTrue(object != nil) } } } func testArrayMethodPerformance() { let json = JSON(data:self.testData) self.measureBlock() { for _ in 1...100 { autoreleasepool{ let array = json.array XCTAssertTrue(array?.count > 0) } } } } func testDictionaryMethodPerformance() { let json = JSON(data:testData)[0] self.measureBlock() { for _ in 1...100 { autoreleasepool{ let dictionary = json.dictionary XCTAssertTrue(dictionary?.count > 0) } } } } func testRawStringMethodPerformance() { let json = JSON(data:testData) self.measureBlock() { for _ in 1...100 { autoreleasepool{ let string = json.rawString() XCTAssertTrue(string != nil) } } } } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Tests/PrintableTests.swift ================================================ // PrintableTests.swift // // Copyright (c) 2014 Pinglin Tang // // 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. import XCTest import SwiftyJSON class PrintableTests: XCTestCase { func testNumber() { let json:JSON = 1234567890.876623 XCTAssertEqual(json.description, "1234567890.876623") XCTAssertEqual(json.debugDescription, "1234567890.876623") } func testBool() { let jsonTrue:JSON = true XCTAssertEqual(jsonTrue.description, "true") XCTAssertEqual(jsonTrue.debugDescription, "true") let jsonFalse:JSON = false XCTAssertEqual(jsonFalse.description, "false") XCTAssertEqual(jsonFalse.debugDescription, "false") } func testString() { let json:JSON = "abcd efg, HIJK;LMn" XCTAssertEqual(json.description, "abcd efg, HIJK;LMn") XCTAssertEqual(json.debugDescription, "abcd efg, HIJK;LMn") } func testNil() { let jsonNil_1:JSON = nil XCTAssertEqual(jsonNil_1.description, "null") XCTAssertEqual(jsonNil_1.debugDescription, "null") let jsonNil_2:JSON = JSON(NSNull()) XCTAssertEqual(jsonNil_2.description, "null") XCTAssertEqual(jsonNil_2.debugDescription, "null") } func testArray() { let json:JSON = [1,2,"4",5,"6"] var description = json.description.stringByReplacingOccurrencesOfString("\n", withString: "") description = description.stringByReplacingOccurrencesOfString(" ", withString: "") XCTAssertEqual(description, "[1,2,\"4\",5,\"6\"]") XCTAssertTrue(json.description.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) > 0) XCTAssertTrue(json.debugDescription.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) > 0) } func testDictionary() { let json:JSON = ["1":2,"2":"two", "3":3] var debugDescription = json.debugDescription.stringByReplacingOccurrencesOfString("\n", withString: "") debugDescription = debugDescription.stringByReplacingOccurrencesOfString(" ", withString: "") XCTAssertTrue(json.description.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) > 0) XCTAssertTrue(debugDescription.rangeOfString("\"1\":2", options: NSStringCompareOptions.CaseInsensitiveSearch) != nil) XCTAssertTrue(debugDescription.rangeOfString("\"2\":\"two\"", options: NSStringCompareOptions.CaseInsensitiveSearch) != nil) XCTAssertTrue(debugDescription.rangeOfString("\"3\":3", options: NSStringCompareOptions.CaseInsensitiveSearch) != nil) } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Tests/RawRepresentableTests.swift ================================================ // RawRepresentableTests.swift // // Copyright (c) 2014 Pinglin Tang // // 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. import XCTest import SwiftyJSON class RawRepresentableTests: XCTestCase { func testNumber() { var json:JSON = JSON(rawValue: 948394394.347384 as NSNumber)! XCTAssertEqual(json.int!, 948394394) XCTAssertEqual(json.intValue, 948394394) XCTAssertEqual(json.double!, 948394394.347384) XCTAssertEqual(json.doubleValue, 948394394.347384) XCTAssertTrue(json.float! == 948394394.347384) XCTAssertTrue(json.floatValue == 948394394.347384) let object: AnyObject = json.rawValue XCTAssertEqual(object as? Int, 948394394) XCTAssertEqual(object as? Double, 948394394.347384) XCTAssertTrue(object as! Float == 948394394.347384) XCTAssertEqual(object as? NSNumber, 948394394.347384) } func testBool() { var jsonTrue:JSON = JSON(rawValue: true as NSNumber)! XCTAssertEqual(jsonTrue.bool!, true) XCTAssertEqual(jsonTrue.boolValue, true) var jsonFalse:JSON = JSON(rawValue: false)! XCTAssertEqual(jsonFalse.bool!, false) XCTAssertEqual(jsonFalse.boolValue, false) let objectTrue: AnyObject = jsonTrue.rawValue XCTAssertEqual(objectTrue as? Int, 1) XCTAssertEqual(objectTrue as? Double, 1.0) XCTAssertEqual(objectTrue as? Bool, true) XCTAssertEqual(objectTrue as? NSNumber, NSNumber(bool: true)) let objectFalse: AnyObject = jsonFalse.rawValue XCTAssertEqual(objectFalse as? Int, 0) XCTAssertEqual(objectFalse as? Double, 0.0) XCTAssertEqual(objectFalse as? Bool, false) XCTAssertEqual(objectFalse as? NSNumber, NSNumber(bool: false)) } func testString() { let string = "The better way to deal with JSON data in Swift." if let json:JSON = JSON(rawValue: string) { XCTAssertEqual(json.string!, string) XCTAssertEqual(json.stringValue, string) XCTAssertTrue(json.array == nil) XCTAssertTrue(json.dictionary == nil) XCTAssertTrue(json.null == nil) XCTAssertTrue(json.error == nil) XCTAssertTrue(json.type == .String) XCTAssertEqual(json.object as? String, string) } else { XCTFail("Should not run into here") } let object: AnyObject = JSON(rawValue: string)!.rawValue XCTAssertEqual(object as? String, string) } func testNil() { if let _ = JSON(rawValue: NSObject()) { XCTFail("Should not run into here") } } func testArray() { let array = [1,2,"3",4102,"5632", "abocde", "!@# $%^&*()"] as NSArray if let json:JSON = JSON(rawValue: array) { XCTAssertEqual(json, JSON(array)) } let object: AnyObject = JSON(rawValue: array)!.rawValue XCTAssertTrue(array == object as! NSArray) } func testDictionary() { let dictionary = ["1":2,"2":2,"three":3,"list":["aa","bb","dd"]] as NSDictionary if let json:JSON = JSON(rawValue: dictionary) { XCTAssertEqual(json, JSON(dictionary)) } let object: AnyObject = JSON(rawValue: dictionary)!.rawValue XCTAssertTrue(dictionary == object as! NSDictionary) } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Tests/RawTests.swift ================================================ // RawTests.swift // // Copyright (c) 2014 Pinglin Tang // // 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. import XCTest import SwiftyJSON class RawTests: XCTestCase { func testRawData() { let json: JSON = ["somekey" : "some string value"] let expectedRawData = "{\"somekey\":\"some string value\"}".dataUsingEncoding(NSUTF8StringEncoding) do { let data: NSData = try json.rawData() XCTAssertEqual(expectedRawData, data) } catch _ { XCTFail() } } func testInvalidJSONForRawData() { let json: JSON = "...xyz" do { try json.rawData() } catch let error as NSError { XCTAssertEqual(error.code, ErrorInvalidJSON) } } func testArray() { let json:JSON = [1, "2", 3.12, NSNull(), true, ["name": "Jack"]] let data: NSData? do { data = try json.rawData() } catch _ { data = nil } let string = json.rawString() XCTAssertTrue (data != nil) XCTAssertTrue (string!.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) > 0) print(string!) } func testDictionary() { let json:JSON = ["number":111111.23456789, "name":"Jack", "list":[1,2,3,4], "bool":false, "null":NSNull()] let data: NSData? do { data = try json.rawData() } catch _ { data = nil } let string = json.rawString() XCTAssertTrue (data != nil) XCTAssertTrue (string!.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) > 0) print(string!) } func testString() { let json:JSON = "I'm a json" print(json.rawString()) XCTAssertTrue(json.rawString() == "I'm a json") } func testNumber() { let json:JSON = 123456789.123 print(json.rawString()) XCTAssertTrue(json.rawString() == "123456789.123") } func testBool() { let json:JSON = true print(json.rawString()) XCTAssertTrue(json.rawString() == "true") } func testNull() { let json:JSON = nil print(json.rawString()) XCTAssertTrue(json.rawString() == "null") } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Tests/SequenceTypeTests.swift ================================================ // // SequenceTypeTests.swift // // Copyright (c) 2014 Pinglin Tang // // 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. import XCTest import SwiftyJSON class SequenceTypeTests: XCTestCase { func testJSONFile() { if let file = NSBundle(forClass:BaseTests.self).pathForResource("Tests", ofType: "json") { let testData = NSData(contentsOfFile: file) let json = JSON(data:testData!) for (index, sub) in json { switch (index as NSString).integerValue { case 0: XCTAssertTrue(sub["id_str"] == "240558470661799936") case 1: XCTAssertTrue(sub["id_str"] == "240556426106372096") case 2: XCTAssertTrue(sub["id_str"] == "240539141056638977") default:0 } } } else { XCTFail("Can't find the test JSON file") } } func testArrayAllNumber() { var json:JSON = [1,2.0,3.3,123456789,987654321.123456789] XCTAssertEqual(json.count, 5) var index = 0 var array = [NSNumber]() for (i, sub) in json { XCTAssertEqual(sub, json[index]) XCTAssertEqual(i, "\(index)") array.append(sub.number!) index++ } XCTAssertEqual(index, 5) XCTAssertEqual(array, [1,2.0,3.3,123456789,987654321.123456789]) } func testArrayAllBool() { var json:JSON = JSON([true, false, false, true, true]) XCTAssertEqual(json.count, 5) var index = 0 var array = [Bool]() for (i, sub) in json { XCTAssertEqual(sub, json[index]) XCTAssertEqual(i, "\(index)") array.append(sub.bool!) index++ } XCTAssertEqual(index, 5) XCTAssertEqual(array, [true, false, false, true, true]) } func testArrayAllString() { var json:JSON = JSON(rawValue: ["aoo","bpp","zoo"] as NSArray)! XCTAssertEqual(json.count, 3) var index = 0 var array = [String]() for (i, sub) in json { XCTAssertEqual(sub, json[index]) XCTAssertEqual(i, "\(index)") array.append(sub.string!) index++ } XCTAssertEqual(index, 3) XCTAssertEqual(array, ["aoo","bpp","zoo"]) } func testArrayWithNull() { var json:JSON = JSON(rawValue: ["aoo","bpp", NSNull() ,"zoo"] as NSArray)! XCTAssertEqual(json.count, 4) var index = 0 var array = [AnyObject]() for (i, sub) in json { XCTAssertEqual(sub, json[index]) XCTAssertEqual(i, "\(index)") array.append(sub.object) index++ } XCTAssertEqual(index, 4) XCTAssertEqual(array[0] as? String, "aoo") XCTAssertEqual(array[2] as? NSNull, NSNull()) } func testArrayAllDictionary() { var json:JSON = [["1":1, "2":2], ["a":"A", "b":"B"], ["null":NSNull()]] XCTAssertEqual(json.count, 3) var index = 0 var array = [AnyObject]() for (i, sub) in json { XCTAssertEqual(sub, json[index]) XCTAssertEqual(i, "\(index)") array.append(sub.object) index++ } XCTAssertEqual(index, 3) XCTAssertEqual((array[0] as! [String : Int])["1"]!, 1) XCTAssertEqual((array[0] as! [String : Int])["2"]!, 2) XCTAssertEqual((array[1] as! [String : String])["a"]!, "A") XCTAssertEqual((array[1] as! [String : String])["b"]!, "B") XCTAssertEqual((array[2] as! [String : NSNull])["null"]!, NSNull()) } func testDictionaryAllNumber() { var json:JSON = ["double":1.11111, "int":987654321] XCTAssertEqual(json.count, 2) var index = 0 var dictionary = [String:NSNumber]() for (key, sub) in json { XCTAssertEqual(sub, json[key]) dictionary[key] = sub.number! index++ } XCTAssertEqual(index, 2) XCTAssertEqual(dictionary["double"]! as NSNumber, 1.11111) XCTAssertEqual(dictionary["int"]! as NSNumber, 987654321) } func testDictionaryAllBool() { var json:JSON = ["t":true, "f":false, "false":false, "tr":true, "true":true] XCTAssertEqual(json.count, 5) var index = 0 var dictionary = [String:Bool]() for (key, sub) in json { XCTAssertEqual(sub, json[key]) dictionary[key] = sub.bool! index++ } XCTAssertEqual(index, 5) XCTAssertEqual(dictionary["t"]! as Bool, true) XCTAssertEqual(dictionary["false"]! as Bool, false) } func testDictionaryAllString() { var json:JSON = JSON(rawValue: ["a":"aoo","bb":"bpp","z":"zoo"] as NSDictionary)! XCTAssertEqual(json.count, 3) var index = 0 var dictionary = [String:String]() for (key, sub) in json { XCTAssertEqual(sub, json[key]) dictionary[key] = sub.string! index++ } XCTAssertEqual(index, 3) XCTAssertEqual(dictionary["a"]! as String, "aoo") XCTAssertEqual(dictionary["bb"]! as String, "bpp") } func testDictionaryWithNull() { var json:JSON = JSON(rawValue: ["a":"aoo","bb":"bpp","null":NSNull(), "z":"zoo"] as NSDictionary)! XCTAssertEqual(json.count, 4) var index = 0 var dictionary = [String:AnyObject]() for (key, sub) in json { XCTAssertEqual(sub, json[key]) dictionary[key] = sub.object index++ } XCTAssertEqual(index, 4) XCTAssertEqual(dictionary["a"]! as? String, "aoo") XCTAssertEqual(dictionary["bb"]! as? String, "bpp") XCTAssertEqual(dictionary["null"]! as? NSNull, NSNull()) } func testDictionaryAllArray() { var json:JSON = JSON (["Number":[NSNumber(integer:1),NSNumber(double:2.123456),NSNumber(int:123456789)], "String":["aa","bbb","cccc"], "Mix":[true, "766", NSNull(), 655231.9823]]) XCTAssertEqual(json.count, 3) var index = 0 var dictionary = [String:AnyObject]() for (key, sub) in json { XCTAssertEqual(sub, json[key]) dictionary[key] = sub.object index++ } XCTAssertEqual(index, 3) XCTAssertEqual((dictionary["Number"] as! NSArray)[0] as? Int, 1) XCTAssertEqual((dictionary["Number"] as! NSArray)[1] as? Double, 2.123456) XCTAssertEqual((dictionary["String"] as! NSArray)[0] as? String, "aa") XCTAssertEqual((dictionary["Mix"] as! NSArray)[0] as? Bool, true) XCTAssertEqual((dictionary["Mix"] as! NSArray)[1] as? String, "766") XCTAssertEqual((dictionary["Mix"] as! NSArray)[2] as? NSNull, NSNull()) XCTAssertEqual((dictionary["Mix"] as! NSArray)[3] as? Double, 655231.9823) } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Tests/StringTests.swift ================================================ // StringTests.swift // // Copyright (c) 2014 Pinglin Tang // // 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. import XCTest import SwiftyJSON class StringTests: XCTestCase { func testString() { //getter var json = JSON("abcdefg hijklmn;opqrst.?+_()") XCTAssertEqual(json.string!, "abcdefg hijklmn;opqrst.?+_()") XCTAssertEqual(json.stringValue, "abcdefg hijklmn;opqrst.?+_()") json.string = "12345?67890.@#" XCTAssertEqual(json.string!, "12345?67890.@#") XCTAssertEqual(json.stringValue, "12345?67890.@#") } func testURL() { let json = JSON("http://github.com") XCTAssertEqual(json.URL!, NSURL(string:"http://github.com")!) } func testURLPercentEscapes() { let emDash = "\\u2014" let urlString = "http://examble.com/unencoded" + emDash + "string" let encodedURLString = urlString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) let json = JSON(urlString) XCTAssertEqual(json.URL!, NSURL(string: encodedURLString!)!, "Wrong unpacked ") } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Tests/SubscriptTests.swift ================================================ // SubscriptTests.swift // // Copyright (c) 2014 Pinglin Tang // // 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. import XCTest import SwiftyJSON class SubscriptTests: XCTestCase { func testArrayAllNumber() { var json:JSON = [1,2.0,3.3,123456789,987654321.123456789] XCTAssertTrue(json == [1,2.0,3.3,123456789,987654321.123456789]) XCTAssertTrue(json[0] == 1) XCTAssertEqual(json[1].double!, 2.0) XCTAssertTrue(json[2].floatValue == 3.3) XCTAssertEqual(json[3].int!, 123456789) XCTAssertEqual(json[4].doubleValue, 987654321.123456789) json[0] = 1.9 json[1] = 2.899 json[2] = 3.567 json[3] = 0.999 json[4] = 98732 XCTAssertTrue(json[0] == 1.9) XCTAssertEqual(json[1].doubleValue, 2.899) XCTAssertTrue(json[2] == 3.567) XCTAssertTrue(json[3].float! == 0.999) XCTAssertTrue(json[4].intValue == 98732) } func testArrayAllBool() { var json:JSON = [true, false, false, true, true] XCTAssertTrue(json == [true, false, false, true, true]) XCTAssertTrue(json[0] == true) XCTAssertTrue(json[1] == false) XCTAssertTrue(json[2] == false) XCTAssertTrue(json[3] == true) XCTAssertTrue(json[4] == true) json[0] = false json[4] = true XCTAssertTrue(json[0] == false) XCTAssertTrue(json[4] == true) } func testArrayAllString() { var json:JSON = JSON(rawValue: ["aoo","bpp","zoo"] as NSArray)! XCTAssertTrue(json == ["aoo","bpp","zoo"]) XCTAssertTrue(json[0] == "aoo") XCTAssertTrue(json[1] == "bpp") XCTAssertTrue(json[2] == "zoo") json[1] = "update" XCTAssertTrue(json[0] == "aoo") XCTAssertTrue(json[1] == "update") XCTAssertTrue(json[2] == "zoo") } func testArrayWithNull() { var json:JSON = JSON(rawValue: ["aoo","bpp", NSNull() ,"zoo"] as NSArray)! XCTAssertTrue(json[0] == "aoo") XCTAssertTrue(json[1] == "bpp") XCTAssertNil(json[2].string) XCTAssertNotNil(json[2].null) XCTAssertTrue(json[3] == "zoo") json[2] = "update" json[3] = JSON(NSNull()) XCTAssertTrue(json[0] == "aoo") XCTAssertTrue(json[1] == "bpp") XCTAssertTrue(json[2] == "update") XCTAssertNil(json[3].string) XCTAssertNotNil(json[3].null) } func testArrayAllDictionary() { var json:JSON = [["1":1, "2":2], ["a":"A", "b":"B"], ["null":NSNull()]] XCTAssertTrue(json[0] == ["1":1, "2":2]) XCTAssertEqual(json[1].dictionary!, ["a":"A", "b":"B"]) XCTAssertEqual(json[2], JSON(["null":NSNull()])) XCTAssertTrue(json[0]["1"] == 1) XCTAssertTrue(json[0]["2"] == 2) XCTAssertEqual(json[1]["a"], JSON(rawValue: "A")!) XCTAssertEqual(json[1]["b"], JSON("B")) XCTAssertNotNil(json[2]["null"].null) XCTAssertNotNil(json[2,"null"].null) let keys:[JSONSubscriptType] = [1, "a"] XCTAssertEqual(json[keys], JSON(rawValue: "A")!) } func testDictionaryAllNumber() { var json:JSON = ["double":1.11111, "int":987654321] XCTAssertEqual(json["double"].double!, 1.11111) XCTAssertTrue(json["int"] == 987654321) json["double"] = 2.2222 json["int"] = 123456789 json["add"] = 7890 XCTAssertTrue(json["double"] == 2.2222) XCTAssertEqual(json["int"].doubleValue, 123456789.0) XCTAssertEqual(json["add"].intValue, 7890) } func testDictionaryAllBool() { var json:JSON = ["t":true, "f":false, "false":false, "tr":true, "true":true] XCTAssertTrue(json["t"] == true) XCTAssertTrue(json["f"] == false) XCTAssertTrue(json["false"] == false) XCTAssertTrue(json["tr"] == true) XCTAssertTrue(json["true"] == true) json["f"] = true json["tr"] = false XCTAssertTrue(json["f"] == true) XCTAssertTrue(json["tr"] == JSON(false)) } func testDictionaryAllString() { var json:JSON = JSON(rawValue: ["a":"aoo","bb":"bpp","z":"zoo"] as NSDictionary)! XCTAssertTrue(json["a"] == "aoo") XCTAssertEqual(json["bb"], JSON("bpp")) XCTAssertTrue(json["z"] == "zoo") json["bb"] = "update" XCTAssertTrue(json["a"] == "aoo") XCTAssertTrue(json["bb"] == "update") XCTAssertTrue(json["z"] == "zoo") } func testDictionaryWithNull() { var json:JSON = JSON(rawValue: ["a":"aoo","bb":"bpp","null":NSNull(), "z":"zoo"] as NSDictionary)! XCTAssertTrue(json["a"] == "aoo") XCTAssertEqual(json["bb"], JSON("bpp")) XCTAssertEqual(json["null"], JSON(NSNull())) XCTAssertTrue(json["z"] == "zoo") json["null"] = "update" XCTAssertTrue(json["a"] == "aoo") XCTAssertTrue(json["null"] == "update") XCTAssertTrue(json["z"] == "zoo") } func testDictionaryAllArray() { //Swift bug: [1, 2.01,3.09] is convert to [1, 2, 3] (Array) let json:JSON = JSON ([[NSNumber(integer:1),NSNumber(double:2.123456),NSNumber(int:123456789)], ["aa","bbb","cccc"], [true, "766", NSNull(), 655231.9823]] as NSArray) XCTAssertTrue(json[0] == [1,2.123456,123456789]) XCTAssertEqual(json[0][1].double!, 2.123456) XCTAssertTrue(json[0][2] == 123456789) XCTAssertTrue(json[1][0] == "aa") XCTAssertTrue(json[1] == ["aa","bbb","cccc"]) XCTAssertTrue(json[2][0] == true) XCTAssertTrue(json[2][1] == "766") XCTAssertTrue(json[[2,1]] == "766") XCTAssertEqual(json[2][2], JSON(NSNull())) XCTAssertEqual(json[2,2], JSON(NSNull())) XCTAssertEqual(json[2][3], JSON(655231.9823)) XCTAssertEqual(json[2,3], JSON(655231.9823)) XCTAssertEqual(json[[2,3]], JSON(655231.9823)) } func testOutOfBounds() { let json:JSON = JSON ([[NSNumber(integer:1),NSNumber(double:2.123456),NSNumber(int:123456789)], ["aa","bbb","cccc"], [true, "766", NSNull(), 655231.9823]] as NSArray) XCTAssertEqual(json[9], JSON.null) XCTAssertEqual(json[-2].error!.code, ErrorIndexOutOfBounds) XCTAssertEqual(json[6].error!.code, ErrorIndexOutOfBounds) XCTAssertEqual(json[9][8], JSON.null) XCTAssertEqual(json[8][7].error!.code, ErrorIndexOutOfBounds) XCTAssertEqual(json[8,7].error!.code, ErrorIndexOutOfBounds) XCTAssertEqual(json[999].error!.code, ErrorIndexOutOfBounds) } func testErrorWrongType() { let json = JSON(12345) XCTAssertEqual(json[9], JSON.null) XCTAssertEqual(json[9].error!.code, ErrorWrongType) XCTAssertEqual(json[8][7].error!.code, ErrorWrongType) XCTAssertEqual(json["name"], JSON.null) XCTAssertEqual(json["name"].error!.code, ErrorWrongType) XCTAssertEqual(json[0]["name"].error!.code, ErrorWrongType) XCTAssertEqual(json["type"]["name"].error!.code, ErrorWrongType) XCTAssertEqual(json["name"][99].error!.code, ErrorWrongType) XCTAssertEqual(json[1,"Value"].error!.code, ErrorWrongType) XCTAssertEqual(json[1, 2,"Value"].error!.code, ErrorWrongType) XCTAssertEqual(json[[1, 2,"Value"]].error!.code, ErrorWrongType) } func testErrorNotExist() { let json:JSON = ["name":"NAME", "age":15] XCTAssertEqual(json["Type"], JSON.null) XCTAssertEqual(json["Type"].error!.code, ErrorNotExist) XCTAssertEqual(json["Type"][1].error!.code, ErrorNotExist) XCTAssertEqual(json["Type", 1].error!.code, ErrorNotExist) XCTAssertEqual(json["Type"]["Value"].error!.code, ErrorNotExist) XCTAssertEqual(json["Type","Value"].error!.code, ErrorNotExist) } func testMultilevelGetter() { let json:JSON = [[[[["one":1]]]]] XCTAssertEqual(json[[0, 0, 0, 0, "one"]].int!, 1) XCTAssertEqual(json[0, 0, 0, 0, "one"].int!, 1) XCTAssertEqual(json[0][0][0][0]["one"].int!, 1) } func testMultilevelSetter1() { var json:JSON = [[[[["num":1]]]]] json[0, 0, 0, 0, "num"] = 2 XCTAssertEqual(json[[0, 0, 0, 0, "num"]].intValue, 2) json[0, 0, 0, 0, "num"] = nil XCTAssertEqual(json[0, 0, 0, 0, "num"].null!, NSNull()) json[0, 0, 0, 0, "num"] = 100.009 XCTAssertEqual(json[0][0][0][0]["num"].doubleValue, 100.009) json[[0, 0, 0, 0]] = ["name":"Jack"] XCTAssertEqual(json[0,0,0,0,"name"].stringValue, "Jack") XCTAssertEqual(json[0][0][0][0]["name"].stringValue, "Jack") XCTAssertEqual(json[[0,0,0,0,"name"]].stringValue, "Jack") json[[0,0,0,0,"name"]].string = "Mike" XCTAssertEqual(json[0,0,0,0,"name"].stringValue, "Mike") let path:[JSONSubscriptType] = [0,0,0,0,"name"] json[path].string = "Jim" XCTAssertEqual(json[path].stringValue, "Jim") } func testMultilevelSetter2() { var json:JSON = ["user":["id":987654, "info":["name":"jack","email":"jack@gmail.com"], "feeds":[98833,23443,213239,23232]]] json["user","info","name"] = "jim" XCTAssertEqual(json["user","id"], 987654) XCTAssertEqual(json["user","info","name"], "jim") XCTAssertEqual(json["user","info","email"], "jack@gmail.com") XCTAssertEqual(json["user","feeds"], [98833,23443,213239,23232]) json["user","info","email"] = "jim@hotmail.com" XCTAssertEqual(json["user","id"], 987654) XCTAssertEqual(json["user","info","name"], "jim") XCTAssertEqual(json["user","info","email"], "jim@hotmail.com") XCTAssertEqual(json["user","feeds"], [98833,23443,213239,23232]) json["user","info"] = ["name":"tom","email":"tom@qq.com"] XCTAssertEqual(json["user","id"], 987654) XCTAssertEqual(json["user","info","name"], "tom") XCTAssertEqual(json["user","info","email"], "tom@qq.com") XCTAssertEqual(json["user","feeds"], [98833,23443,213239,23232]) json["user","feeds"] = [77323,2313,4545,323] XCTAssertEqual(json["user","id"], 987654) XCTAssertEqual(json["user","info","name"], "tom") XCTAssertEqual(json["user","info","email"], "tom@qq.com") XCTAssertEqual(json["user","feeds"], [77323,2313,4545,323]) } } ================================================ FILE: Carthage/Checkouts/SwiftyJSON/Tests/Tests.json ================================================ [ { "coordinates":null, "truncated":false, "created_at":"Tue Aug 28 21:16:23 +0000 2012", "favorited":false, "id_str":"240558470661799936", "in_reply_to_user_id_str":null, "entities":{ "urls":[ ], "hashtags":[ ], "user_mentions":[ ] }, "text":"just another test", "contributors":null, "id":240558470661799936, "retweet_count":0, "in_reply_to_status_id_str":null, "geo":null, "retweeted":false, "in_reply_to_user_id":null, "place":null, "source":"<a href=\"//realitytechnicians.com\" rel=\"\"nofollow\"\">OAuth Dancer Reborn</a>", "user":{ "name":"OAuth Dancer", "profile_sidebar_fill_color":"DDEEF6", "profile_background_tile":true, "profile_sidebar_border_color":"C0DEED", "profile_image_url":"http://a0.twimg.com/profile_images/730275945/oauth-dancer_normal.jpg", "created_at":"Wed Mar 03 19:37:35 +0000 2010", "location":"San Francisco, CA", "follow_request_sent":false, "id_str":"119476949", "is_translator":false, "profile_link_color":"0084B4", "entities":{ "url":{ "urls":[ { "expanded_url":null, "url":"http://bit.ly/oauth-dancer", "indices":[ 0, 26 ], "display_url":null } ] }, "description":null }, "default_profile":false, "url":"http://bit.ly/oauth-dancer", "contributors_enabled":false, "favourites_count":7, "utc_offset":null, "profile_image_url_https":"https://si0.twimg.com/profile_images/730275945/oauth-dancer_normal.jpg", "id":119476949, "listed_count":1, "profile_use_background_image":true, "profile_text_color":"333333", "followers_count":28, "lang":"en", "protected":false, "geo_enabled":true, "notifications":false, "description":"", "profile_background_color":"C0DEED", "verified":false, "time_zone":null, "profile_background_image_url_https":"https://si0.twimg.com/profile_background_images/80151733/oauth-dance.png", "statuses_count":166, "profile_background_image_url":"http://a0.twimg.com/profile_background_images/80151733/oauth-dance.png", "default_profile_image":false, "friends_count":14, "following":false, "show_all_inline_media":false, "screen_name":"oauth_dancer" }, "in_reply_to_screen_name":null, "in_reply_to_status_id":null }, { "coordinates":{ "coordinates":[ -122.25831, 37.871609 ], "type":"Point" }, "truncated":false, "created_at":"Tue Aug 28 21:08:15 +0000 2012", "favorited":false, "id_str":"240556426106372096", "in_reply_to_user_id_str":null, "entities":{ "urls":[ { "expanded_url":"http://blogs.ischool.berkeley.edu/i290-abdt-s12/", "url":"http://t.co/bfj7zkDJ", "indices":[ 79, 99 ], "display_url":"blogs.ischool.berkeley.edu/i290-abdt-s12/" } ], "hashtags":[ ], "user_mentions":[ { "name":"Cal", "id_str":"17445752", "id":17445752, "indices":[ 60, 64 ], "screen_name":"Cal" }, { "name":"Othman Laraki", "id_str":"20495814", "id":20495814, "indices":[ 70, 77 ], "screen_name":"othman" } ] }, "text":"lecturing at the \"analyzing big data with twitter\" class at @cal with @othman http://t.co/bfj7zkDJ", "contributors":null, "id":240556426106372096, "retweet_count":3, "in_reply_to_status_id_str":null, "geo":{ "coordinates":[ 37.871609, -122.25831 ], "type":"Point" }, "retweeted":false, "possibly_sensitive":false, "in_reply_to_user_id":null, "place":{ "name":"Berkeley", "country_code":"US", "country":"United States", "attributes":{ }, "url":"http://api.twitter.com/1/geo/id/5ef5b7f391e30aff.json", "id":"5ef5b7f391e30aff", "bounding_box":{ "coordinates":[ [ [ -122.367781, 37.835727 ], [ -122.234185, 37.835727 ], [ -122.234185, 37.905824 ], [ -122.367781, 37.905824 ] ] ], "type":"Polygon" }, "full_name":"Berkeley, CA", "place_type":"city" }, "source":"<a href=\"//www.apple.com\"\" rel=\"\"nofollow\"\">Safari on iOS</a>", "user":{ "name":"Raffi Krikorian", "profile_sidebar_fill_color":"DDEEF6", "profile_background_tile":false, "profile_sidebar_border_color":"C0DEED", "profile_image_url":"http://a0.twimg.com/profile_images/1270234259/raffi-headshot-casual_normal.png", "created_at":"Sun Aug 19 14:24:06 +0000 2007", "location":"San Francisco, California", "follow_request_sent":false, "id_str":"8285392", "is_translator":false, "profile_link_color":"0084B4", "entities":{ "url":{ "urls":[ { "expanded_url":"http://about.me/raffi.krikorian", "url":"http://t.co/eNmnM6q", "indices":[ 0, 19 ], "display_url":"about.me/raffi.krikorian" } ] }, "description":{ "urls":[ ] } }, "default_profile":true, "url":"http://t.co/eNmnM6q", "contributors_enabled":false, "favourites_count":724, "utc_offset":-28800, "profile_image_url_https":"https://si0.twimg.com/profile_images/1270234259/raffi-headshot-casual_normal.png", "id":8285392, "listed_count":619, "profile_use_background_image":true, "profile_text_color":"333333", "followers_count":18752, "lang":"en", "protected":false, "geo_enabled":true, "notifications":false, "description":"Director of @twittereng's Platform Services. I break things.", "profile_background_color":"C0DEED", "verified":false, "time_zone":"Pacific Time (US & Canada)", "profile_background_image_url_https":"https://si0.twimg.com/images/themes/theme1/bg.png", "statuses_count":5007, "profile_background_image_url":"http://a0.twimg.com/images/themes/theme1/bg.png", "default_profile_image":false, "friends_count":701, "following":true, "show_all_inline_media":true, "screen_name":"raffi" }, "in_reply_to_screen_name":null, "in_reply_to_status_id":null }, { "coordinates":null, "truncated":false, "created_at":"Tue Aug 28 19:59:34 +0000 2012", "favorited":false, "id_str":"240539141056638977", "in_reply_to_user_id_str":null, "entities":{ "urls":[ ], "hashtags":[ ], "user_mentions":[ ] }, "text":"You'd be right more often if you thought you were wrong.", "contributors":null, "id":240539141056638977, "retweet_count":1, "in_reply_to_status_id_str":null, "geo":null, "retweeted":false, "in_reply_to_user_id":null, "place":null, "source":"web", "user":{ "name":"Taylor Singletary", "profile_sidebar_fill_color":"FBFBFB", "profile_background_tile":true, "profile_sidebar_border_color":"000000", "profile_image_url":"http://a0.twimg.com/profile_images/2546730059/f6a8zq58mg1hn0ha8vie_normal.jpeg", "created_at":"Wed Mar 07 22:23:19 +0000 2007", "location":"San Francisco, CA", "follow_request_sent":false, "id_str":"819797", "is_translator":false, "profile_link_color":"c71818", "entities":{ "url":{ "urls":[ { "expanded_url":"http://www.rebelmouse.com/episod/", "url":"http://t.co/Lxw7upbN", "indices":[ 0, 20 ], "display_url":"rebelmouse.com/episod/" } ] }, "description":{ "urls":[ ] } }, "default_profile":false, "url":"http://t.co/Lxw7upbN", "contributors_enabled":false, "favourites_count":15990, "utc_offset":-28800, "profile_image_url_https":"https://si0.twimg.com/profile_images/2546730059/f6a8zq58mg1hn0ha8vie_normal.jpeg", "id":819797, "listed_count":340, "profile_use_background_image":true, "profile_text_color":"D20909", "followers_count":7126, "lang":"en", "protected":false, "geo_enabled":true, "notifications":false, "description":"Reality Technician, Twitter API team, synthesizer enthusiast; a most excellent adventure in timelines. I know it's hard to believe in something you can't see.", "profile_background_color":"000000", "verified":false, "time_zone":"Pacific Time (US & Canada)", "profile_background_image_url_https":"https://si0.twimg.com/profile_background_images/643655842/hzfv12wini4q60zzrthg.png", "statuses_count":18076, "profile_background_image_url":"http://a0.twimg.com/profile_background_images/643655842/hzfv12wini4q60zzrthg.png", "default_profile_image":false, "friends_count":5444, "following":true, "show_all_inline_media":true, "screen_name":"episod" }, "in_reply_to_screen_name":null, "in_reply_to_status_id":null } ] ================================================ FILE: Carthage/Checkouts/SwiftyJSON/scripts/ci.sh ================================================ #!/usr/bin/env bash set -e xcodebuild -workspace SwiftyJSON.xcworkspace -scheme "SwiftyJSON iOS" -destination "platform=iOS Simulator,name=iPhone 6" test xcodebuild -workspace SwiftyJSON.xcworkspace -scheme "SwiftyJSON OSX" test xcodebuild -workspace SwiftyJSON.xcworkspace -scheme "SwiftyJSON tvOS" -destination "platform=tvOS Simulator,name=Apple TV 1080p" test ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/.gitignore ================================================ # Xcode build/* *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata profile *.moved-aside .DS_Store # `make test` artifacts *.o *.out testparser.sh testparser unparse-date unparse-ordinaldate unparse-weekdate ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/.hgtags ================================================ e190de54c50791dcfdcaa32ce978a684a9fff236 0.4 0082342cb70688b993b311340df4e4fb9c99531d 0.5 37825820b1c1140188fc1542b2b543bf5f45be42 0.6 ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/.travis.yml ================================================ language: objective-c before_install: - sudo easy_install cpp-coveralls before_script: - cd ISO8601ForCocoa script: - xcodebuild test -scheme 'ISO8601ForCocoa' SRCROOT=../build OBJROOT=../build SHARED_PRECOMPS_DIR=../build - xcodebuild test -scheme 'ISO8601ForCocoaTouch' -destination 'name=iPhone 5s' SRCROOT=../build OBJROOT=../build SHARED_PRECOMPS_DIR=../build after_success: - cd .. - coveralls -x '.m' ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/AppledocSettings.plist ================================================ --company-id org.boredzo --project-company Peter Hosey --project-name ISO 8601 Date Formatter ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601DateFormatter.h ================================================ /*ISO8601DateFormatter.h * *Created by Peter Hosey on 2009-04-11. *Copyright 2009–2013 Peter Hosey. All rights reserved. */ #import ///Which of ISO 8601's three date formats the formatter should produce. typedef NS_ENUM(NSUInteger, ISO8601DateFormat) { ///YYYY-MM-DD. ISO8601DateFormatCalendar, ///YYYY-DDD, where DDD ranges from 1 to 366; for example, 2009-32 is 2009-02-01. ISO8601DateFormatOrdinal, ///YYYY-Www-D, where ww ranges from 1 to 53 (the 'W' is literal) and D ranges from 1 to 7; for example, 2009-W05-07. ISO8601DateFormatWeek, }; ///The default separator for time values. Currently, this is ':'. extern const unichar ISO8601DefaultTimeSeparatorCharacter; /*! * @brief This class converts dates to and from ISO 8601 strings. * * @details TL;DR: You want to use ISO 8601 for any and all dates you send or receive over the internet, unless the spec for the protocol or format you're working with specifically tells you otherwise. See http://xkcd.com/1179/ . * * ISO 8601 is most recognizable as “year-month-date” strings, such as “2013-09-08T15:06:11-0800”. Of course, as you might expect of a formal standard, it's more sophisticated (some might say complicated) than that. * * For one thing, ISO 8601 actually defines *three* different date formats. The most common one, shown above, is called the calendar date format. The other two are week dates, where the month is replaced by a week of the year and the day is a day-of-the-week (1 being Monday) rather than day-of-month, and ordinal dates, where the middle segment is dispensed with entirely and the day component is day-of-year (1–366). * * The week format is the most bizarre of them, since 7 × 52 ≠ 365. The start and end of the year for purposes of week dates usually don't line up with the start and end of the calendar year. As a result, the first and/or last day of a year in the week-date “calendar” more often than not is on a different year from the first and/or last day of that year on the actual Gregorian calendar. * * In practice, almost all ISO 8601 dates you see in the wild will be in the calendar format. * * At any rate, this formatter can both parse and unparse dates in all three formats. (By “unparse”, I mean “produce a string from”—the reverse of parsing.) * * For a good and more detailed introduction to ISO 8601, see [“A summary of the international standard date and time notation” by Markus Kuhn](http://www.cl.cam.ac.uk/~mgk25/iso-time.html). The actual standard itself can be found in PDF format online with a well-crafted web search. */ @interface ISO8601DateFormatter: NSFormatter { NSString *lastUsedFormatString; NSDateFormatter *unparsingFormatter; NSCalendar *parsingCalendar, *unparsingCalendar; NSTimeZone *defaultTimeZone; ISO8601DateFormat format; unichar timeSeparator; unichar timeZoneSeparator; BOOL includeTime; BOOL useMillisecondPrecision; BOOL parsesStrictly; } @property(nonatomic, retain) NSTimeZone *defaultTimeZone; #pragma mark Parsing /*! * @name Parsing */ //As a formatter, this object converts strings to dates. /*! * @brief Disables various leniencies in how the formatter parses strings. * * @details By default, the parser allows these extensions to the ISO 8601 standard: * * - Whitespace is allowed before the date. * - Numbers don't have to be within range for a component. For example, you can have a string that refers to the 56th day of the hundredth month. * - Since 0.6, allows a single whitespace character before the time-zone specification. This extension provides compatibility with NSDate output (`description`) and input (`dateWithString:`). * - “Superfluous” hyphens in date specifications such as “`--DDD`” (where DDD is an ordinal day-of-year number and the year is implied) are allowed. (The standard recommends writing such a date as “`-DDD`”, with only a single hyphen. This is consistent with ordinal dates having only two components: the year and the day-of-year, separated by one hyphen.) * - The same goes for week dates such as “`--Www-DD`”. Again, the extra hyphen really is superfluous, but is allowed as an extension. * - Calendar dates with no separator between month and day-of-month are allowed, at least when they total four digits. (For example, 2013-0908, which would be interpreted as 2013-09-08.) * - Single-digit components are allowed. (If you wish to specify a date in a single-digit year with the strict parser, pad it with zeroes.) * - “YYYY-W” (without a week number after the 'W') is allowed, interpreted as “YYYY-W01-01”. * * Setting this property to `YES` will disable all of those extensions. * * These extensions are intended to help you process degenerate input (received from programs and services that use broken date-formatting libraries); whenever *you* create ISO 8601 strings, you should generate strictly-conforming ones. * * This property does not affect unparsing. The formatter always creates valid ISO 8601 strings. Any invalid string (loosely, any string that would require turning this property off to re-parse) should be considered a bug; please report it. */ @property BOOL parsesStrictly; /*! * @brief Parse a string into individual date components. * * @param string The string to parse. Must represent a date in one of the ISO 8601 formats. * @returns An NSDateComponents object containing most of the information parsed from the string, aside from the fraction of second and time zone (which are lost). * @sa dateComponentsFromString:timeZone: * @sa dateComponentsFromString:timeZone:range:fractionOfSecond: */ - (NSDateComponents *) dateComponentsFromString:(NSString *)string; /*! * @brief Parse a string into individual date components. * * @param string The string to parse. Must represent a date in one of the ISO 8601 formats. * @param outTimeZone If non-`NULL`, an NSTimeZone object or `nil` will be stored here, depending on whether the string specified a time zone. * @returns An NSDateComponents object containing most of the information parsed from the string, aside from the fraction of second (which is lost) and time zone. * @sa dateComponentsFromString: * @sa dateComponentsFromString:timeZone:range:fractionOfSecond: */ - (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone; /*! * @brief Parse a string into individual date components. * * @param string The string to parse. Must represent a date in one of the ISO 8601 formats. * @param outTimeZone If non-`NULL`, an NSTimeZone object or `nil` will be stored here, depending on whether the string specified a time zone. * @param outRange If non-`NULL`, an NSRange structure will be stored here, identifying the substring of `string` that specified the date. * @param outFractionOfSecond If non-`NULL`, an NSTimeInterval value will be stored here, containing the fraction of a second, if the string specified one. If it didn't, this will be set to zero. * @returns An NSDateComponents object containing most of the information parsed from the string, aside from the fraction of second and time zone. * @sa dateComponentsFromString: * @sa dateComponentsFromString:timeZone: */ - (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone range:(out NSRange *)outRange fractionOfSecond:(NSTimeInterval *)outFractionOfSecond; /*! * @brief Parse a string. * * @param string The string to parse. Must represent a date in one of the ISO 8601 formats. * @returns An NSDate object containing most of the information parsed from the string, aside from the time zone (which is lost). * @sa dateComponentsFromString: * @sa dateFromString:timeZone: * @sa dateFromString:timeZone:range: */ - (NSDate *) dateFromString:(NSString *)string; /*! * @brief Parse a string. * * @param string The string to parse. Must represent a date in one of the ISO 8601 formats. * @param outTimeZone If non-`NULL`, an NSTimeZone object or `nil` will be stored here, depending on whether the string specified a time zone. * @returns An NSDate object containing most of the information parsed from the string, aside from the time zone. * @sa dateComponentsFromString:timeZone: * @sa dateFromString: * @sa dateFromString:timeZone:range: */ - (NSDate *) dateFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone; /*! * @brief Parse a string into a single date, identified by an NSDate object. * * @param string The string to parse. Must represent a date in one of the ISO 8601 formats. * @param outTimeZone If non-`NULL`, an NSTimeZone object or `nil` will be stored here, depending on whether the string specified a time zone. * @param outRange If non-`NULL`, an NSRange structure will be stored here, identifying the substring of `string` that specified the date. * @returns An NSDate object containing most of the information parsed from the string, aside from the time zone. * @sa dateComponentsFromString:timeZone:range:fractionOfSecond: * @sa dateFromString: * @sa dateFromString:timeZone: */ - (NSDate *) dateFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone range:(out NSRange *)outRange; #pragma mark Unparsing /*! * @name Unparsing */ /*! * @brief Which ISO 8601 format to format dates in. * * @details See ISO8601DateFormat for possible values. */ @property ISO8601DateFormat format; /*! * @brief Whether strings should include time of day. * * @details If `NO`, strings include only the date, nothing after it. * * @sa timeSeparator * @sa timeZoneSeparator */ @property BOOL includeTime; /*! * @brief Whether strings should include millisecond precision time. * * @details If `YES`, strings include three millisecond digits. Only has an effect if `includeTime` is `YES` * */ @property BOOL useMillisecondPrecision; /*! * @brief The character to use to separate components of the time of day. * * @details This is used in both parsing and unparsing. * * The default value is ISO8601DefaultTimeSeparatorCharacter. * * When parsesStrictly is set to `YES`, this property is ignored. Otherwise, the parser will raise an exception if this is set to zero. * * @sa includeTime * @sa timeZoneSeparator */ @property unichar timeSeparator; /*! * @brief The character to use to separate the hour and minute in a time zone specification. * * @details This is used in both parsing and unparsing. * * If zero, no separator is inserted into time zone specifications. * * The default value is zero (no separator). * * @sa includeTime * @sa timeSeparator */ @property unichar timeZoneSeparator; /*! * @brief Produce a string that represents a date in UTC. * * @param date The string to parse. Must represent a date in one of the ISO 8601 formats. * @returns A string that represents the date in UTC. * @sa stringFromDate:timeZone: */ - (NSString *) stringFromDate:(NSDate *)date; /*! * @brief Produce a string that represents a date. * * @param date The string to parse. Must represent a date in one of the ISO 8601 formats. * @param timeZone An NSTimeZone object identifying the time zone in which to specify the date. * @returns A string that represents the date in the requested time zone, if possible. * * @details Not all dates are representable in all time zones (because of historical calendar changes, such as transitions from the Julian to the Gregorian calendar). * For an example, see http://stackoverflow.com/questions/18663407/date-formatter-returns-nil-for-june . * This method *should* return `nil` in such cases. * * @sa stringFromDate: */ - (NSString *) stringFromDate:(NSDate *)date timeZone:(NSTimeZone *)timeZone; @end ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601DateFormatter.m ================================================ /*ISO8601DateFormatter.m * *Created by Peter Hosey on 2009-04-11. *Copyright 2009–2013 Peter Hosey. All rights reserved. */ #import #import #if TARGET_OS_IPHONE # import #endif #import "ISO8601DateFormatter.h" #ifndef DEFAULT_TIME_SEPARATOR # define DEFAULT_TIME_SEPARATOR ':' #endif const unichar ISO8601DefaultTimeSeparatorCharacter = DEFAULT_TIME_SEPARATOR; //Unicode date formats. #define ISO_CALENDAR_DATE_FORMAT @"yyyy-MM-dd" //#define ISO_WEEK_DATE_FORMAT @"YYYY-'W'ww-ee" //Doesn't actually work because NSDateComponents counts the weekday starting at 1. #define ISO_ORDINAL_DATE_FORMAT @"yyyy-DDD" #define ISO_TIME_FORMAT @"HH:mm:ss" #define ISO_TIME_FORMAT_MS_PRECISION @"HH:mm:ss.SSS" //printf formats. #define ISO_TIMEZONE_UTC_FORMAT @"Z" #define ISO_TIMEZONE_OFFSET_FORMAT_NO_SEPARATOR @"%+.2d%.2d" #define ISO_TIMEZONE_OFFSET_FORMAT_WITH_SEPARATOR @"%+.2d%C%.2d" static NSString * const ISO8601TwoCharIntegerFormat = @"%.2d"; @interface ISO8601DateFormatter(UnparsingPrivate) - (NSString *) replaceColonsInString:(NSString *)timeFormat withTimeSeparator:(unichar)timeSep; - (NSString *) stringFromDate:(NSDate *)date formatString:(NSString *)dateFormat timeZone:(NSTimeZone *)timeZone; - (NSString *) weekDateStringForDate:(NSDate *)date timeZone:(NSTimeZone *)timeZone; @end static NSCache *timeZonesByOffset; @implementation ISO8601DateFormatter + (void) initialize { timeZonesByOffset = [[NSCache alloc] init]; } + (void) purgeGlobalCaches { [timeZonesByOffset removeAllObjects]; } - (NSCalendar *) makeCalendarWithDesiredConfiguration { NSCalendar *calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian] autorelease]; calendar.firstWeekday = 2; //Monday calendar.timeZone = [NSTimeZone defaultTimeZone]; return calendar; } - (id) init { if ((self = [super init])) { parsingCalendar = [[self makeCalendarWithDesiredConfiguration] retain]; unparsingCalendar = [[self makeCalendarWithDesiredConfiguration] retain]; format = ISO8601DateFormatCalendar; timeSeparator = ISO8601DefaultTimeSeparatorCharacter; includeTime = NO; parsesStrictly = NO; useMillisecondPrecision = NO; } return self; } - (void) dealloc { [defaultTimeZone release]; [unparsingFormatter release]; [lastUsedFormatString release]; [parsingCalendar release]; [unparsingCalendar release]; [super dealloc]; } @synthesize defaultTimeZone; - (void) setDefaultTimeZone:(NSTimeZone *)tz { if (defaultTimeZone != tz) { [defaultTimeZone release]; defaultTimeZone = [tz retain]; unparsingCalendar.timeZone = defaultTimeZone; } } //The following properties are only here because GCC doesn't like @synthesize in category implementations. #pragma mark Parsing @synthesize parsesStrictly; static NSUInteger read_segment(const unichar *str, const unichar **next, NSUInteger *out_num_digits); static NSUInteger read_segment_4digits(const unichar *str, const unichar **next, NSUInteger *out_num_digits); static NSUInteger read_segment_2digits(const unichar *str, const unichar **next); static double read_double(const unichar *str, const unichar **next); static BOOL is_leap_year(NSUInteger year); /*Valid ISO 8601 date formats: * *YYYYMMDD *YYYY-MM-DD *YYYY-MM *YYYY *YY //century * //Implied century: YY is 00-99 * YYMMDD * YY-MM-DD * -YYMM * -YY-MM * -YY * //Implied year * --MMDD * --MM-DD * --MM * //Implied year and month * ---DD * //Ordinal dates: DDD is the number of the day in the year (1-366) *YYYYDDD *YYYY-DDD * YYDDD * YY-DDD * -DDD * //Week-based dates: ww is the number of the week, and d is the number (1-7) of the day in the week *yyyyWwwd *yyyy-Www-d *yyyyWww *yyyy-Www *yyWwwd *yy-Www-d *yyWww *yy-Www * //Year of the implied decade *-yWwwd *-y-Www-d *-yWww *-y-Www * //Week and day of implied year * -Wwwd * -Www-d * //Week only of implied year * -Www * //Day only of implied week * -W-d */ - (NSDateComponents *) dateComponentsFromString:(NSString *)string { return [self dateComponentsFromString:string timeZone:NULL]; } - (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone { return [self dateComponentsFromString:string timeZone:outTimeZone range:NULL fractionOfSecond:NULL]; } - (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone range:(out NSRange *)outRange fractionOfSecond:(out NSTimeInterval *)outFractionOfSecond { if (string == nil) return nil; // Bail if the string contains a slash delimiter (we don't yet support ISO 8601 intervals and we don't support slash-separated dates) if ([string rangeOfString:@"/"].location != NSNotFound) return nil; NSDate *now = [NSDate date]; NSDateComponents *components = [[[NSDateComponents alloc] init] autorelease]; NSDateComponents *nowComponents = [parsingCalendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:now]; NSUInteger //Date year = 0U, month_or_week = 0U, day = 0U, //Time hour = 0U; NSTimeInterval minute = 0.0, second = 0.0; //Time zone NSInteger tz_hour = 0; NSInteger tz_minute = 0; enum { monthAndDate, week, dateOnly } dateSpecification = monthAndDate; BOOL strict = self.parsesStrictly; unichar timeSep = self.timeSeparator; if (strict) timeSep = ISO8601DefaultTimeSeparatorCharacter; NSAssert(timeSep != '\0', @"Time separator must not be NUL."); BOOL isValidDate = ([string length] > 0U); NSTimeZone *timeZone = nil; const unichar *ch = (const unichar *)[string cStringUsingEncoding:NSUnicodeStringEncoding]; NSRange range = { 0U, 0U }; const unichar *start_of_date = NULL; if (strict && isspace(*ch)) { range.location = NSNotFound; isValidDate = NO; } else { //Skip leading whitespace. NSUInteger i = 0U; while (isspace(ch[i])) ++i; range.location = i; ch += i; start_of_date = ch; NSUInteger segment; NSUInteger num_leading_hyphens = 0U, num_digits = 0U; if (*ch == 'T') { //There is no date here, only a time. Set the date to now; then we'll parse the time. isValidDate = isdigit(*++ch); year = nowComponents.year; month_or_week = nowComponents.month; day = nowComponents.day; } else { while(*ch == '-') { ++num_leading_hyphens; ++ch; } segment = read_segment(ch, &ch, &num_digits); switch(num_digits) { case 0: if (*ch == 'W') { if ((ch[1] == '-') && isdigit(ch[2]) && ((num_leading_hyphens == 1U) || ((num_leading_hyphens == 2U) && !strict))) { year = nowComponents.year; month_or_week = 1U; ch += 2; goto parseDayAfterWeek; } else if (num_leading_hyphens == 1U) { year = nowComponents.year; goto parseWeekAndDay; } else isValidDate = NO; } else isValidDate = NO; break; case 8: //YYYY MM DD if (num_leading_hyphens > 0U) isValidDate = NO; else { day = segment % 100U; segment /= 100U; month_or_week = segment % 100U; year = segment / 100U; } break; case 6: //YYMMDD (implicit century) if (num_leading_hyphens > 0U || strict) isValidDate = NO; else { day = segment % 100U; segment /= 100U; month_or_week = segment % 100U; year = nowComponents.year; year -= (year % 100U); year += segment / 100U; } break; case 4: switch(num_leading_hyphens) { case 0: //YYYY year = segment; if (*ch == '-') ++ch; if (!isdigit(*ch)) { if (*ch == 'W') goto parseWeekAndDay; else month_or_week = day = 1U; } else { segment = read_segment(ch, &ch, &num_digits); switch(num_digits) { case 4: //MMDD if (strict) isValidDate = NO; else { day = segment % 100U; month_or_week = segment / 100U; } break; case 2: //MM month_or_week = segment; if (*ch == '-') ++ch; if (!isdigit(*ch)) day = 1U; else day = read_segment(ch, &ch, NULL); break; case 3: //DDD day = segment % 1000U; dateSpecification = dateOnly; if (strict && (day > (365U + is_leap_year(year)))) isValidDate = NO; break; default: isValidDate = NO; } } break; case 1: //YYMM month_or_week = segment % 100U; year = segment / 100U; if (*ch == '-') ++ch; if (!isdigit(*ch)) day = 1U; else day = read_segment(ch, &ch, NULL); break; case 2: //MMDD day = segment % 100U; month_or_week = segment / 100U; year = nowComponents.year; break; default: isValidDate = NO; } //switch(num_leading_hyphens) (4 digits) break; case 1: if (strict) { //Two digits only - never just one. if (num_leading_hyphens == 1U) { if (*ch == '-') ++ch; if (*++ch == 'W') { year = nowComponents.year; year -= (year % 10U); year += segment; goto parseWeekAndDay; } else isValidDate = NO; } else isValidDate = NO; break; } case 2: switch(num_leading_hyphens) { case 0: if (*ch == '-') { //Implicit century year = nowComponents.year; year -= (year % 100U); year += segment; if (*++ch == 'W') goto parseWeekAndDay; else if (!isdigit(*ch)) { goto centuryOnly; } else { //Get month and/or date. segment = read_segment_4digits(ch, &ch, &num_digits); NSLog(@"(%@) parsing month; segment is %lu and ch is %@", string, (unsigned long)segment, [NSString stringWithCString:(const char *)ch encoding:NSUnicodeStringEncoding]); switch(num_digits) { case 4: //YY-MMDD day = segment % 100U; month_or_week = segment / 100U; break; case 1: //YY-M; YY-M-DD (extension) if (strict) { isValidDate = NO; break; } case 2: //YY-MM; YY-MM-DD month_or_week = segment; if (*ch == '-') { if (isdigit(*++ch)) day = read_segment_2digits(ch, &ch); else day = 1U; } else day = 1U; break; case 3: //Ordinal date. day = segment; dateSpecification = dateOnly; break; } } } else if (*ch == 'W') { year = nowComponents.year; year -= (year % 100U); year += segment; parseWeekAndDay: //*ch should be 'W' here. if (!isdigit(*++ch)) { //Not really a week-based date; just a year followed by '-W'. if (strict) isValidDate = NO; else month_or_week = day = 1U; } else { month_or_week = read_segment_2digits(ch, &ch); if (*ch == '-') ++ch; parseDayAfterWeek: day = isdigit(*ch) ? read_segment_2digits(ch, &ch) : 1U; dateSpecification = week; } } else { //Century only. Assume current year. centuryOnly: year = segment * 100U + nowComponents.year % 100U; month_or_week = day = 1U; } break; case 1:; //-YY; -YY-MM (implicit century) NSLog(@"(%@) found %lu digits and one hyphen, so this is either -YY or -YY-MM; segment (year) is %lu", string, (unsigned long)num_digits, (unsigned long)segment); NSUInteger current_year = nowComponents.year; NSUInteger current_century = (current_year % 100U); year = segment + (current_year - current_century); if (num_digits == 1U) //implied decade year += current_century - (current_year % 10U); if (*ch == '-') { ++ch; month_or_week = read_segment_2digits(ch, &ch); NSLog(@"(%@) month is %lu", string, (unsigned long)month_or_week); } day = 1U; break; case 2: //--MM; --MM-DD year = nowComponents.year; month_or_week = segment; if (*ch == '-') { ++ch; day = read_segment_2digits(ch, &ch); } break; case 3: //---DD year = nowComponents.year; month_or_week = nowComponents.month; day = segment; break; default: isValidDate = NO; } //switch(num_leading_hyphens) (2 digits) break; case 7: //YYYY DDD (ordinal date) if (num_leading_hyphens > 0U) isValidDate = NO; else { day = segment % 1000U; year = segment / 1000U; dateSpecification = dateOnly; if (strict && (day > (365U + is_leap_year(year)))) isValidDate = NO; } break; case 3: //--DDD (ordinal date, implicit year) //Technically, the standard only allows one hyphen. But it says that two hyphens is the logical implementation, and one was dropped for brevity. So I have chosen to allow the missing hyphen. if ((num_leading_hyphens < 1U) || ((num_leading_hyphens > 2U) && !strict)) isValidDate = NO; else { day = segment; year = nowComponents.year; dateSpecification = dateOnly; if (strict && (day > (365U + is_leap_year(year)))) isValidDate = NO; } break; default: isValidDate = NO; } } if (isValidDate) { if (isspace(*ch) || (*ch == 'T')) ++ch; if (isdigit(*ch)) { hour = read_segment_2digits(ch, &ch); if (*ch == timeSep) { ++ch; if ((timeSep == ',') || (timeSep == '.')) { //We can't do fractional minutes when '.' is the segment separator. //Only allow whole minutes and whole seconds. minute = read_segment_2digits(ch, &ch); if (*ch == timeSep) { ++ch; second = read_segment_2digits(ch, &ch); } } else { //Allow a fractional minute. //If we don't get a fraction, look for a seconds segment. //Otherwise, the fraction of a minute is the seconds. minute = read_double(ch, &ch); second = modf(minute, &minute); if (second > DBL_EPSILON) second *= 60.0; //Convert fraction (e.g. .5) into seconds (e.g. 30). else if (*ch == timeSep) { ++ch; second = read_double(ch, &ch); } } } if (!strict) { if (isspace(*ch)) ++ch; } switch(*ch) { case 'Z': timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; ++ch; //So that the Z is included in the range. break; case '+': case '-':; BOOL negative = (*ch == '-'); if (isdigit(*++ch)) { //Read hour offset. segment = *ch - '0'; if (isdigit(*++ch)) { segment *= 10U; segment += *(ch++) - '0'; } tz_hour = (NSInteger)segment; if (negative) tz_hour = -tz_hour; //Optional separator. if (*ch == self.timeZoneSeparator) ++ch; if (isdigit(*ch)) { //Read minute offset. segment = *ch - '0'; if (isdigit(*++ch)) { segment *= 10U; segment += *ch - '0'; } tz_minute = segment; if (negative) tz_minute = -tz_minute; } NSInteger timeZoneOffset = (tz_hour * 3600) + (tz_minute * 60); NSNumber *offsetNum = [NSNumber numberWithInteger:timeZoneOffset]; timeZone = [timeZonesByOffset objectForKey:offsetNum]; if (!timeZone) { timeZone = [NSTimeZone timeZoneForSecondsFromGMT:timeZoneOffset]; if (timeZone) { [timeZonesByOffset setObject:timeZone forKey:offsetNum]; } } } } } } if (isValidDate) { components.year = year; components.day = day; components.hour = hour; components.minute = (NSInteger)minute; components.second = (NSInteger)second; if (outFractionOfSecond != NULL) { NSTimeInterval fractionOfSecond = second - components.second; if (fractionOfSecond > 0.0) { *outFractionOfSecond = fractionOfSecond; } } switch(dateSpecification) { case monthAndDate: components.month = month_or_week; break; case week:; //Adapted from . //This works by converting the week date into an ordinal date, then letting the next case handle it. NSUInteger prevYear = year - 1U; NSUInteger YY = prevYear % 100U; NSUInteger C = prevYear - YY; NSUInteger G = YY + YY / 4U; NSUInteger isLeapYear = (((C / 100U) % 4U) * 5U); NSUInteger Jan1Weekday = (isLeapYear + G) % 7U; enum { monday, tuesday, wednesday, thursday/*, friday, saturday, sunday*/ }; components.day = ((8U - Jan1Weekday) + (7U * (Jan1Weekday > thursday))) + (day - 1U) + (7U * (month_or_week - 2)); case dateOnly: //An "ordinal date". break; } } } //if (!(strict && isdigit(ch[0]))) if (outRange) { if (isValidDate) range.length = ch - start_of_date; else range.location = NSNotFound; *outRange = range; } if (outTimeZone) { *outTimeZone = timeZone; } return isValidDate ? components : nil; } - (NSDate *) dateFromString:(NSString *)string { return [self dateFromString:string timeZone:NULL]; } - (NSDate *) dateFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone { return [self dateFromString:string timeZone:outTimeZone range:NULL]; } - (NSDate *) dateFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone range:(out NSRange *)outRange { NSTimeZone *timeZone = nil; NSTimeInterval parsedFractionOfSecond = 0.0; NSDateComponents *components = [self dateComponentsFromString:string timeZone:&timeZone range:outRange fractionOfSecond:&parsedFractionOfSecond]; if (outTimeZone) *outTimeZone = timeZone; if (components == nil) return nil; parsingCalendar.timeZone = timeZone; NSDate *parsedDate = [parsingCalendar dateFromComponents:components]; if (parsedFractionOfSecond > 0.0) { parsedDate = [parsedDate dateByAddingTimeInterval:parsedFractionOfSecond]; } return parsedDate; } - (BOOL)getObjectValue:(id *)outValue forString:(NSString *)string errorDescription:(NSString **)error { NSDate *date = [self dateFromString:string]; if (outValue) *outValue = date; return (date != nil); } #pragma mark Unparsing @synthesize format; @synthesize includeTime; @synthesize useMillisecondPrecision; @synthesize timeSeparator; @synthesize timeZoneSeparator; - (NSString *) replaceColonsInString:(NSString *)timeFormat withTimeSeparator:(unichar)timeSep { if (timeSep != ':') { NSMutableString *timeFormatMutable = [[timeFormat mutableCopy] autorelease]; [timeFormatMutable replaceOccurrencesOfString:@":" withString:[NSString stringWithCharacters:&timeSep length:1U] options:NSBackwardsSearch | NSLiteralSearch range:(NSRange){ 0UL, [timeFormat length] }]; timeFormat = timeFormatMutable; } return timeFormat; } - (NSString *) stringFromDate:(NSDate *)date { NSTimeZone *timeZone = self.defaultTimeZone; if (!timeZone) timeZone = [NSTimeZone defaultTimeZone]; return [self stringFromDate:date timeZone:timeZone]; } - (NSString *) stringFromDate:(NSDate *)date timeZone:(NSTimeZone *)timeZone { switch (self.format) { case ISO8601DateFormatCalendar: return [self stringFromDate:date formatString:ISO_CALENDAR_DATE_FORMAT timeZone:timeZone]; case ISO8601DateFormatWeek: return [self weekDateStringForDate:date timeZone:timeZone]; case ISO8601DateFormatOrdinal: return [self stringFromDate:date formatString:ISO_ORDINAL_DATE_FORMAT timeZone:timeZone]; default: [NSException raise:NSInternalInconsistencyException format:@"self.format was %tu, not calendar (%tu), week (%tu), or ordinal (%tu)", self.format, ISO8601DateFormatCalendar, ISO8601DateFormatWeek, ISO8601DateFormatOrdinal]; return nil; } } - (NSString *) stringFromDate:(NSDate *)date formatString:(NSString *)dateFormat timeZone:(NSTimeZone *)timeZone { if (includeTime){ NSString *timeFormat = self.useMillisecondPrecision ? ISO_TIME_FORMAT_MS_PRECISION : ISO_TIME_FORMAT; dateFormat = [dateFormat stringByAppendingFormat:@"'T'%@", [self replaceColonsInString:timeFormat withTimeSeparator:self.timeSeparator]]; } if ([dateFormat isEqualToString:lastUsedFormatString] == NO) { [unparsingFormatter release]; unparsingFormatter = nil; [lastUsedFormatString release]; lastUsedFormatString = [dateFormat retain]; } if (!unparsingFormatter) { unparsingFormatter = [[NSDateFormatter alloc] init]; unparsingFormatter.formatterBehavior = NSDateFormatterBehavior10_4; unparsingFormatter.dateFormat = dateFormat; unparsingFormatter.calendar = unparsingCalendar; unparsingFormatter.locale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]; } unparsingCalendar.timeZone = timeZone; unparsingFormatter.timeZone = timeZone; NSString *str = [unparsingFormatter stringForObjectValue:date]; if (includeTime) { NSInteger offset = [timeZone secondsFromGMTForDate:date]; offset /= 60; //bring down to minutes if (offset == 0) str = [str stringByAppendingString:ISO_TIMEZONE_UTC_FORMAT]; else { int timeZoneOffsetHour = abs((int)(offset / 60)); int timeZoneOffsetMinute = abs((int)(offset % 60)); if (offset > 0) str = [str stringByAppendingString:@"+"]; else str = [str stringByAppendingString:@"-"]; str = [str stringByAppendingFormat:ISO8601TwoCharIntegerFormat, timeZoneOffsetHour]; if (self.timeZoneSeparator) str = [str stringByAppendingFormat:@"%C", self.timeZoneSeparator]; str = [str stringByAppendingFormat:ISO8601TwoCharIntegerFormat, timeZoneOffsetMinute]; } } //Undo the change we made earlier unparsingCalendar.timeZone = self.defaultTimeZone; unparsingFormatter.timeZone = self.defaultTimeZone; return str; } - (NSString *) stringForObjectValue:(id)value { if ( ! [value isKindOfClass:[NSDate class]]) { NSLog(@"%s: Can only format NSDate objects, not objects like %@", __func__, value); return nil; } return [self stringFromDate:(NSDate *)value]; } /*Adapted from: * Algorithm for Converting Gregorian Dates to ISO 8601 Week Date * Rick McCarty, 1999 * http://personal.ecu.edu/mccartyr/ISOwdALG.txt */ - (NSString *) weekDateStringForDate:(NSDate *)date timeZone:(NSTimeZone *)timeZone { unparsingCalendar.timeZone = timeZone; NSDateComponents *components = [unparsingCalendar components:NSCalendarUnitYear | NSCalendarUnitWeekday | NSCalendarUnitDay fromDate:date]; //Determine the ordinal date. NSDateComponents *startOfYearComponents = [unparsingCalendar components:NSCalendarUnitYear fromDate:date]; startOfYearComponents.month = 1; startOfYearComponents.day = 1; NSDateComponents *ordinalComponents = [unparsingCalendar components:NSCalendarUnitDay fromDate:[unparsingCalendar dateFromComponents:startOfYearComponents] toDate:date options:0]; ordinalComponents.day += 1; enum { monday, tuesday, wednesday, thursday, friday, saturday, sunday }; enum { january = 1, february, march, april, may, june, july, august, september, october, november, december }; NSInteger year = components.year; NSInteger week = 0; //The old unparser added 6 to [calendarDate dayOfWeek], which was zero-based; components.weekday is one-based, so we now add only 5. NSInteger dayOfWeek = (components.weekday + 5) % 7; NSInteger dayOfYear = ordinalComponents.day; NSInteger prevYear = year - 1; BOOL yearIsLeapYear = is_leap_year(year); BOOL prevYearIsLeapYear = is_leap_year(prevYear); NSInteger YY = prevYear % 100; NSInteger C = prevYear - YY; NSInteger G = YY + YY / 4; NSInteger Jan1Weekday = (((((C / 100) % 4) * 5) + G) % 7); NSInteger weekday = ((dayOfYear + Jan1Weekday) - 1) % 7; if((dayOfYear <= (7 - Jan1Weekday)) && (Jan1Weekday > thursday)) { week = 52 + ((Jan1Weekday == friday) || ((Jan1Weekday == saturday) && prevYearIsLeapYear)); --year; } else { NSInteger lengthOfYear = 365 + yearIsLeapYear; if((lengthOfYear - dayOfYear) < (thursday - weekday)) { ++year; week = 1; } else { NSInteger J = dayOfYear + (sunday - weekday) + Jan1Weekday; week = J / 7 - (Jan1Weekday > thursday); } } NSString *string = [NSString stringWithFormat:@"%lu-W%02lu-%02lu", (unsigned long)year, (unsigned long)week, ((unsigned long)dayOfWeek) + 1U]; NSString *timeString; if(includeTime) { NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; unichar timeSep = self.timeSeparator; if (!timeSep) timeSep = ISO8601DefaultTimeSeparatorCharacter; NSString *timeFormat = self.useMillisecondPrecision ? ISO_TIME_FORMAT_MS_PRECISION : ISO_TIME_FORMAT; formatter.dateFormat = [self replaceColonsInString:timeFormat withTimeSeparator:timeSep]; formatter.locale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]; formatter.timeZone = timeZone; timeString = [formatter stringForObjectValue:date]; [formatter release]; //TODO: This is copied from the calendar-date code. It should be isolated in a method. NSInteger offset = [timeZone secondsFromGMTForDate:date]; offset /= 60; //bring down to minutes if (offset == 0) timeString = [timeString stringByAppendingString:ISO_TIMEZONE_UTC_FORMAT]; else { int timeZoneOffsetHour = (int)(offset / 60); int timeZoneOffsetMinute = (int)(offset % 60); if (self.timeZoneSeparator) timeString = [timeString stringByAppendingFormat:ISO_TIMEZONE_OFFSET_FORMAT_WITH_SEPARATOR, timeZoneOffsetHour, self.timeZoneSeparator, timeZoneOffsetMinute]; else timeString = [timeString stringByAppendingFormat:ISO_TIMEZONE_OFFSET_FORMAT_NO_SEPARATOR, timeZoneOffsetHour, timeZoneOffsetMinute]; } string = [string stringByAppendingFormat:@"T%@", timeString]; } return string; } @end static NSUInteger read_segment(const unichar *str, const unichar **next, NSUInteger *out_num_digits) { NSUInteger num_digits = 0U; NSUInteger value = 0U; while(isdigit(*str)) { value *= 10U; value += *str - '0'; ++num_digits; ++str; } if (next) *next = str; if (out_num_digits) *out_num_digits = num_digits; return value; } static NSUInteger read_segment_4digits(const unichar *str, const unichar **next, NSUInteger *out_num_digits) { NSUInteger num_digits = 0U; NSUInteger value = 0U; if (isdigit(*str)) { value += *(str++) - '0'; ++num_digits; } if (isdigit(*str)) { value *= 10U; value += *(str++) - '0'; ++num_digits; } if (isdigit(*str)) { value *= 10U; value += *(str++) - '0'; ++num_digits; } if (isdigit(*str)) { value *= 10U; value += *(str++) - '0'; ++num_digits; } if (next) *next = str; if (out_num_digits) *out_num_digits = num_digits; return value; } static NSUInteger read_segment_2digits(const unichar *str, const unichar **next) { NSUInteger value = 0U; if (isdigit(*str)) value += *str - '0'; if (isdigit(*++str)) { value *= 10U; value += *(str++) - '0'; } if (next) *next = str; return value; } //strtod doesn't support ',' as a separator. This does. static double read_double(const unichar *str, const unichar **next) { double value = 0.0; if (str) { NSUInteger int_value = 0; while(isdigit(*str)) { int_value *= 10U; int_value += (*(str++) - '0'); } value = int_value; if (((*str == ',') || (*str == '.'))) { ++str; register double multiplier, multiplier_multiplier; multiplier = multiplier_multiplier = 0.1; while(isdigit(*str)) { value += (*(str++) - '0') * multiplier; multiplier *= multiplier_multiplier; } } } if (next) *next = str; return value; } static BOOL is_leap_year(NSUInteger year) { return \ ((year % 4U) == 0U) && (((year % 100U) != 0U) || ((year % 400U) == 0U)); } ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601DateFormatter/ISO8601.h ================================================ // // ISO8601.h // ISO8601 // // Created by Agnes Vasarhelyi on 30/12/14. // Copyright (c) 2014 Peter Hosey. All rights reserved. // #import //! Project version number for ISO8601DateFormatter. FOUNDATION_EXPORT double ISO8601DateFormatterVersionNumber; //! Project version string for ISO8601DateFormatter. FOUNDATION_EXPORT const unsigned char ISO8601DateFormatterVersionString[]; #import ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601DateFormatter/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoa/ISO8601ForCocoa-Prefix.pch ================================================ // // Prefix header for all source files of the 'ISO8601ForCocoa' target in the 'ISO8601ForCocoa' project // #include #include #ifdef __OBJC__ # define NS_ENABLE_CALENDAR_NEW_API 1 # import #endif ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoa.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 027E31BD1A52DFCE00802098 /* ISO8601.h in Headers */ = {isa = PBXBuildFile; fileRef = 027E31BC1A52DFCE00802098 /* ISO8601.h */; settings = {ATTRIBUTES = (Public, ); }; }; 027E31D11A52DFE200802098 /* ISO8601DateFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 31AEAFF517546BFA00BD292F /* ISO8601DateFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 027E31D21A52DFEC00802098 /* ISO8601DateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 31AEAFF617546BFA00BD292F /* ISO8601DateFormatter.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 3119ABEF17FCF8F0003412AE /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3119ABEE17FCF8F0003412AE /* UIKit.framework */; }; 312D4C441B9CA7D300FF3602 /* ISO8601Testing.m in Sources */ = {isa = PBXBuildFile; fileRef = 312D4C431B9CA7D300FF3602 /* ISO8601Testing.m */; }; 312D4C451B9CA7D600FF3602 /* ISO8601Testing.m in Sources */ = {isa = PBXBuildFile; fileRef = 312D4C431B9CA7D300FF3602 /* ISO8601Testing.m */; }; 31419D9717E08256007B02E2 /* ISO8601ForCocoaWeekDateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 31419D9617E08256007B02E2 /* ISO8601ForCocoaWeekDateTests.m */; }; 31419D9817E08256007B02E2 /* ISO8601ForCocoaWeekDateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 31419D9617E08256007B02E2 /* ISO8601ForCocoaWeekDateTests.m */; }; 3198826517FCF2B0005FB1DA /* ISO8601MemoryWarningTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3198826417FCF2B0005FB1DA /* ISO8601MemoryWarningTests.m */; }; 31A271B717CE9B5A00E3FA7D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 31A271B617CE9B5A00E3FA7D /* Foundation.framework */; }; 31A271C817CE9B5B00E3FA7D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 31A271B617CE9B5A00E3FA7D /* Foundation.framework */; }; 31A271CB17CE9B5B00E3FA7D /* libISO8601ForCocoaTouch.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31A271B517CE9B5A00E3FA7D /* libISO8601ForCocoaTouch.a */; }; 31A271D117CE9B5B00E3FA7D /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 31A271CF17CE9B5B00E3FA7D /* InfoPlist.strings */; }; 31A271DB17CE9C3A00E3FA7D /* ISO8601ForCocoaCalendarDateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 31AEAFEB17546BC900BD292F /* ISO8601ForCocoaCalendarDateTests.m */; }; 31A271DC17CE9C5E00E3FA7D /* ISO8601DateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 31AEAFF617546BFA00BD292F /* ISO8601DateFormatter.m */; }; 31A271DD17CE9E3500E3FA7D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 31AEAFD117546BC800BD292F /* Foundation.framework */; }; 31AEAFE317546BC800BD292F /* libISO8601ForCocoa.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31AEAFC917546BC800BD292F /* libISO8601ForCocoa.a */; }; 31AEAFE917546BC800BD292F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 31AEAFE717546BC800BD292F /* InfoPlist.strings */; }; 31AEAFEC17546BC900BD292F /* ISO8601ForCocoaCalendarDateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 31AEAFEB17546BC900BD292F /* ISO8601ForCocoaCalendarDateTests.m */; }; 31AEAFF717546BFB00BD292F /* ISO8601DateFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 31AEAFF517546BFA00BD292F /* ISO8601DateFormatter.h */; }; 31AEAFF817546BFB00BD292F /* ISO8601DateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 31AEAFF617546BFA00BD292F /* ISO8601DateFormatter.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 3904FF2717CF34AE003603D1 /* MBMockLocale.m in Sources */ = {isa = PBXBuildFile; fileRef = 3904FF2417CF34AE003603D1 /* MBMockLocale.m */; }; 3904FF2817CF34AE003603D1 /* MBMockLocale.m in Sources */ = {isa = PBXBuildFile; fileRef = 3904FF2417CF34AE003603D1 /* MBMockLocale.m */; }; 3904FF2917CF34AE003603D1 /* NSLocale+UnitTestSwizzling.m in Sources */ = {isa = PBXBuildFile; fileRef = 3904FF2617CF34AE003603D1 /* NSLocale+UnitTestSwizzling.m */; }; 3904FF2A17CF34AE003603D1 /* NSLocale+UnitTestSwizzling.m in Sources */ = {isa = PBXBuildFile; fileRef = 3904FF2617CF34AE003603D1 /* NSLocale+UnitTestSwizzling.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 31A271C917CE9B5B00E3FA7D /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 31AEAFC117546BC800BD292F /* Project object */; proxyType = 1; remoteGlobalIDString = 31A271B417CE9B5A00E3FA7D; remoteInfo = ISO8601ForCocoaTouch; }; 31AEAFE117546BC800BD292F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 31AEAFC117546BC800BD292F /* Project object */; proxyType = 1; remoteGlobalIDString = 31AEAFC817546BC800BD292F; remoteInfo = ISO8601ForCocoa; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 31A271B317CE9B5A00E3FA7D /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = "include/${PRODUCT_NAME}"; dstSubfolderSpec = 16; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 027E31BB1A52DFCE00802098 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 027E31BC1A52DFCE00802098 /* ISO8601.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ISO8601.h; sourceTree = ""; }; 1B2A62BE59D932056840CE25 /* PRHNamedCharacter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PRHNamedCharacter.h; sourceTree = ""; }; 3119ABEE17FCF8F0003412AE /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; 312D4C421B9CA7D300FF3602 /* ISO8601Testing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ISO8601Testing.h; sourceTree = ""; }; 312D4C431B9CA7D300FF3602 /* ISO8601Testing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ISO8601Testing.m; sourceTree = ""; }; 31419D9517E08256007B02E2 /* ISO8601ForCocoaWeekDateTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ISO8601ForCocoaWeekDateTests.h; sourceTree = ""; }; 31419D9617E08256007B02E2 /* ISO8601ForCocoaWeekDateTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ISO8601ForCocoaWeekDateTests.m; sourceTree = ""; }; 3179B3EB17E94D5000CE9D95 /* ISO8601ForCocoaTimeOnlyTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ISO8601ForCocoaTimeOnlyTests.h; sourceTree = ""; }; 3179B3EC17E94D5000CE9D95 /* ISO8601ForCocoaTimeOnlyTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ISO8601ForCocoaTimeOnlyTests.m; sourceTree = ""; }; 3198826317FCF2B0005FB1DA /* ISO8601MemoryWarningTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ISO8601MemoryWarningTests.h; sourceTree = ""; }; 3198826417FCF2B0005FB1DA /* ISO8601MemoryWarningTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ISO8601MemoryWarningTests.m; sourceTree = ""; }; 31A271B517CE9B5A00E3FA7D /* libISO8601ForCocoaTouch.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libISO8601ForCocoaTouch.a; sourceTree = BUILT_PRODUCTS_DIR; }; 31A271B617CE9B5A00E3FA7D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 31A271BA17CE9B5B00E3FA7D /* ISO8601ForCocoaTouch-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ISO8601ForCocoaTouch-Prefix.pch"; sourceTree = ""; }; 31A271C417CE9B5B00E3FA7D /* ISO8601ForCocoaTouchTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ISO8601ForCocoaTouchTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 31A271CE17CE9B5B00E3FA7D /* ISO8601ForCocoaTouchTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ISO8601ForCocoaTouchTests-Info.plist"; sourceTree = ""; }; 31A271D017CE9B5B00E3FA7D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 31AEAFC917546BC800BD292F /* libISO8601ForCocoa.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libISO8601ForCocoa.a; sourceTree = BUILT_PRODUCTS_DIR; }; 31AEAFCF17546BC800BD292F /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 31AEAFD017546BC800BD292F /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 31AEAFD117546BC800BD292F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 31AEAFD417546BC800BD292F /* ISO8601ForCocoa-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ISO8601ForCocoa-Prefix.pch"; sourceTree = ""; }; 31AEAFDD17546BC800BD292F /* ISO8601ForCocoaTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ISO8601ForCocoaTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 31AEAFE617546BC800BD292F /* ISO8601ForCocoaTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ISO8601ForCocoaTests-Info.plist"; sourceTree = ""; }; 31AEAFE817546BC800BD292F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 31AEAFEA17546BC800BD292F /* ISO8601ForCocoaCalendarDateTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ISO8601ForCocoaCalendarDateTests.h; sourceTree = ""; }; 31AEAFEB17546BC900BD292F /* ISO8601ForCocoaCalendarDateTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ISO8601ForCocoaCalendarDateTests.m; sourceTree = ""; }; 31AEAFF517546BFA00BD292F /* ISO8601DateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ISO8601DateFormatter.h; path = ../ISO8601DateFormatter.h; sourceTree = ""; }; 31AEAFF617546BFA00BD292F /* ISO8601DateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ISO8601DateFormatter.m; path = ../ISO8601DateFormatter.m; sourceTree = ""; }; 31D981F31B9E5A35007CF1DA /* ISO8601.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ISO8601.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3904FF2317CF34AE003603D1 /* MBMockLocale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBMockLocale.h; sourceTree = ""; }; 3904FF2417CF34AE003603D1 /* MBMockLocale.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBMockLocale.m; sourceTree = ""; }; 3904FF2517CF34AE003603D1 /* NSLocale+UnitTestSwizzling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSLocale+UnitTestSwizzling.h"; sourceTree = ""; }; 3904FF2617CF34AE003603D1 /* NSLocale+UnitTestSwizzling.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSLocale+UnitTestSwizzling.m"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 027E31B41A52DFCE00802098 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 31A271B217CE9B5A00E3FA7D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 31A271B717CE9B5A00E3FA7D /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 31A271C017CE9B5B00E3FA7D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 3119ABEF17FCF8F0003412AE /* UIKit.framework in Frameworks */, 31A271C817CE9B5B00E3FA7D /* Foundation.framework in Frameworks */, 31A271CB17CE9B5B00E3FA7D /* libISO8601ForCocoaTouch.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 31AEAFC617546BC800BD292F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 31A271DD17CE9E3500E3FA7D /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 31AEAFD917546BC800BD292F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 31AEAFE317546BC800BD292F /* libISO8601ForCocoa.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 027E31B91A52DFCE00802098 /* ISO8601 */ = { isa = PBXGroup; children = ( 027E31BC1A52DFCE00802098 /* ISO8601.h */, 027E31BA1A52DFCE00802098 /* Supporting Files */, ); name = ISO8601; path = ISO8601DateFormatter; sourceTree = ""; }; 027E31BA1A52DFCE00802098 /* Supporting Files */ = { isa = PBXGroup; children = ( 027E31BB1A52DFCE00802098 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; 31A271B817CE9B5B00E3FA7D /* ISO8601ForCocoaTouch */ = { isa = PBXGroup; children = ( 31A271B917CE9B5B00E3FA7D /* Supporting Files */, ); path = ISO8601ForCocoaTouch; sourceTree = ""; }; 31A271B917CE9B5B00E3FA7D /* Supporting Files */ = { isa = PBXGroup; children = ( 31A271BA17CE9B5B00E3FA7D /* ISO8601ForCocoaTouch-Prefix.pch */, ); name = "Supporting Files"; sourceTree = ""; }; 31A271CC17CE9B5B00E3FA7D /* ISO8601ForCocoaTouchTests */ = { isa = PBXGroup; children = ( 3198826317FCF2B0005FB1DA /* ISO8601MemoryWarningTests.h */, 3198826417FCF2B0005FB1DA /* ISO8601MemoryWarningTests.m */, 31A271CD17CE9B5B00E3FA7D /* Supporting Files */, ); path = ISO8601ForCocoaTouchTests; sourceTree = ""; }; 31A271CD17CE9B5B00E3FA7D /* Supporting Files */ = { isa = PBXGroup; children = ( 31A271CE17CE9B5B00E3FA7D /* ISO8601ForCocoaTouchTests-Info.plist */, 31A271CF17CE9B5B00E3FA7D /* InfoPlist.strings */, ); name = "Supporting Files"; sourceTree = ""; }; 31AEAFC017546BC800BD292F = { isa = PBXGroup; children = ( 31AEAFF517546BFA00BD292F /* ISO8601DateFormatter.h */, 31AEAFF617546BFA00BD292F /* ISO8601DateFormatter.m */, 31AEAFD217546BC800BD292F /* ISO8601ForCocoa */, 31AEAFE417546BC800BD292F /* ISO8601ForCocoaTests */, 31A271B817CE9B5B00E3FA7D /* ISO8601ForCocoaTouch */, 31A271CC17CE9B5B00E3FA7D /* ISO8601ForCocoaTouchTests */, 027E31B91A52DFCE00802098 /* ISO8601 */, 31AEAFCB17546BC800BD292F /* Frameworks */, 31AEAFCA17546BC800BD292F /* Products */, ); sourceTree = ""; }; 31AEAFCA17546BC800BD292F /* Products */ = { isa = PBXGroup; children = ( 31AEAFC917546BC800BD292F /* libISO8601ForCocoa.a */, 31AEAFDD17546BC800BD292F /* ISO8601ForCocoaTests.xctest */, 31A271B517CE9B5A00E3FA7D /* libISO8601ForCocoaTouch.a */, 31A271C417CE9B5B00E3FA7D /* ISO8601ForCocoaTouchTests.xctest */, 31D981F31B9E5A35007CF1DA /* ISO8601.framework */, ); name = Products; sourceTree = ""; }; 31AEAFCB17546BC800BD292F /* Frameworks */ = { isa = PBXGroup; children = ( 3119ABEE17FCF8F0003412AE /* UIKit.framework */, 31A271B617CE9B5A00E3FA7D /* Foundation.framework */, 31AEAFCE17546BC800BD292F /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; }; 31AEAFCE17546BC800BD292F /* Other Frameworks */ = { isa = PBXGroup; children = ( 31AEAFCF17546BC800BD292F /* AppKit.framework */, 31AEAFD017546BC800BD292F /* CoreData.framework */, 31AEAFD117546BC800BD292F /* Foundation.framework */, ); name = "Other Frameworks"; sourceTree = ""; }; 31AEAFD217546BC800BD292F /* ISO8601ForCocoa */ = { isa = PBXGroup; children = ( 31AEAFD317546BC800BD292F /* Supporting Files */, ); path = ISO8601ForCocoa; sourceTree = ""; }; 31AEAFD317546BC800BD292F /* Supporting Files */ = { isa = PBXGroup; children = ( 31AEAFD417546BC800BD292F /* ISO8601ForCocoa-Prefix.pch */, ); name = "Supporting Files"; sourceTree = ""; }; 31AEAFE417546BC800BD292F /* ISO8601ForCocoaTests */ = { isa = PBXGroup; children = ( 3904FF2317CF34AE003603D1 /* MBMockLocale.h */, 3904FF2417CF34AE003603D1 /* MBMockLocale.m */, 3904FF2517CF34AE003603D1 /* NSLocale+UnitTestSwizzling.h */, 3904FF2617CF34AE003603D1 /* NSLocale+UnitTestSwizzling.m */, 312D4C421B9CA7D300FF3602 /* ISO8601Testing.h */, 312D4C431B9CA7D300FF3602 /* ISO8601Testing.m */, 3179B3EB17E94D5000CE9D95 /* ISO8601ForCocoaTimeOnlyTests.h */, 3179B3EC17E94D5000CE9D95 /* ISO8601ForCocoaTimeOnlyTests.m */, 31AEAFEA17546BC800BD292F /* ISO8601ForCocoaCalendarDateTests.h */, 31AEAFEB17546BC900BD292F /* ISO8601ForCocoaCalendarDateTests.m */, 31419D9517E08256007B02E2 /* ISO8601ForCocoaWeekDateTests.h */, 31419D9617E08256007B02E2 /* ISO8601ForCocoaWeekDateTests.m */, 31AEAFE517546BC800BD292F /* Supporting Files */, 1B2A62BE59D932056840CE25 /* PRHNamedCharacter.h */, ); path = ISO8601ForCocoaTests; sourceTree = ""; }; 31AEAFE517546BC800BD292F /* Supporting Files */ = { isa = PBXGroup; children = ( 31AEAFE617546BC800BD292F /* ISO8601ForCocoaTests-Info.plist */, 31AEAFE717546BC800BD292F /* InfoPlist.strings */, ); name = "Supporting Files"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 027E31B51A52DFCE00802098 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 027E31BD1A52DFCE00802098 /* ISO8601.h in Headers */, 027E31D11A52DFE200802098 /* ISO8601DateFormatter.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; 31AEAFC717546BC800BD292F /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 31AEAFF717546BFB00BD292F /* ISO8601DateFormatter.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 027E31B71A52DFCE00802098 /* ISO8601 */ = { isa = PBXNativeTarget; buildConfigurationList = 027E31CF1A52DFCE00802098 /* Build configuration list for PBXNativeTarget "ISO8601" */; buildPhases = ( 027E31B31A52DFCE00802098 /* Sources */, 027E31B41A52DFCE00802098 /* Frameworks */, 027E31B51A52DFCE00802098 /* Headers */, 027E31B61A52DFCE00802098 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = ISO8601; productName = ISO8601DateFormatter; productReference = 31D981F31B9E5A35007CF1DA /* ISO8601.framework */; productType = "com.apple.product-type.framework"; }; 31A271B417CE9B5A00E3FA7D /* ISO8601ForCocoaTouch */ = { isa = PBXNativeTarget; buildConfigurationList = 31A271D917CE9B5B00E3FA7D /* Build configuration list for PBXNativeTarget "ISO8601ForCocoaTouch" */; buildPhases = ( 31A271B117CE9B5A00E3FA7D /* Sources */, 31A271B217CE9B5A00E3FA7D /* Frameworks */, 31A271B317CE9B5A00E3FA7D /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); name = ISO8601ForCocoaTouch; productName = ISO8601ForCocoaTouch; productReference = 31A271B517CE9B5A00E3FA7D /* libISO8601ForCocoaTouch.a */; productType = "com.apple.product-type.library.static"; }; 31A271C317CE9B5B00E3FA7D /* ISO8601ForCocoaTouchTests */ = { isa = PBXNativeTarget; buildConfigurationList = 31A271DA17CE9B5B00E3FA7D /* Build configuration list for PBXNativeTarget "ISO8601ForCocoaTouchTests" */; buildPhases = ( 31A271BF17CE9B5B00E3FA7D /* Sources */, 31A271C017CE9B5B00E3FA7D /* Frameworks */, 31A271C117CE9B5B00E3FA7D /* Resources */, ); buildRules = ( ); dependencies = ( 31A271CA17CE9B5B00E3FA7D /* PBXTargetDependency */, ); name = ISO8601ForCocoaTouchTests; productName = ISO8601ForCocoaTouchTests; productReference = 31A271C417CE9B5B00E3FA7D /* ISO8601ForCocoaTouchTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 31AEAFC817546BC800BD292F /* ISO8601ForCocoa */ = { isa = PBXNativeTarget; buildConfigurationList = 31AEAFEF17546BC900BD292F /* Build configuration list for PBXNativeTarget "ISO8601ForCocoa" */; buildPhases = ( 31AEAFC517546BC800BD292F /* Sources */, 31AEAFC617546BC800BD292F /* Frameworks */, 31AEAFC717546BC800BD292F /* Headers */, ); buildRules = ( ); dependencies = ( ); name = ISO8601ForCocoa; productName = ISO8601ForCocoa; productReference = 31AEAFC917546BC800BD292F /* libISO8601ForCocoa.a */; productType = "com.apple.product-type.library.static"; }; 31AEAFDC17546BC800BD292F /* ISO8601ForCocoaTests */ = { isa = PBXNativeTarget; buildConfigurationList = 31AEAFF217546BC900BD292F /* Build configuration list for PBXNativeTarget "ISO8601ForCocoaTests" */; buildPhases = ( 31AEAFD817546BC800BD292F /* Sources */, 31AEAFD917546BC800BD292F /* Frameworks */, 31AEAFDA17546BC800BD292F /* Resources */, ); buildRules = ( ); dependencies = ( 31AEAFE217546BC800BD292F /* PBXTargetDependency */, ); name = ISO8601ForCocoaTests; productName = ISO8601ForCocoaTests; productReference = 31AEAFDD17546BC800BD292F /* ISO8601ForCocoaTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 31AEAFC117546BC800BD292F /* Project object */ = { isa = PBXProject; attributes = { LastTestingUpgradeCheck = 0700; LastUpgradeCheck = 0460; ORGANIZATIONNAME = "Peter Hosey"; TargetAttributes = { 027E31B71A52DFCE00802098 = { CreatedOnToolsVersion = 6.1.1; }; 31AEAFDC17546BC800BD292F = { TestTargetID = 31AEAFC817546BC800BD292F; }; }; }; buildConfigurationList = 31AEAFC417546BC800BD292F /* Build configuration list for PBXProject "ISO8601ForCocoa" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = 31AEAFC017546BC800BD292F; productRefGroup = 31AEAFCA17546BC800BD292F /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 31AEAFC817546BC800BD292F /* ISO8601ForCocoa */, 31AEAFDC17546BC800BD292F /* ISO8601ForCocoaTests */, 31A271B417CE9B5A00E3FA7D /* ISO8601ForCocoaTouch */, 31A271C317CE9B5B00E3FA7D /* ISO8601ForCocoaTouchTests */, 027E31B71A52DFCE00802098 /* ISO8601 */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 027E31B61A52DFCE00802098 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 31A271C117CE9B5B00E3FA7D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 31A271D117CE9B5B00E3FA7D /* InfoPlist.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 31AEAFDA17546BC800BD292F /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 31AEAFE917546BC800BD292F /* InfoPlist.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 027E31B31A52DFCE00802098 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 027E31D21A52DFEC00802098 /* ISO8601DateFormatter.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 31A271B117CE9B5A00E3FA7D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 31A271DC17CE9C5E00E3FA7D /* ISO8601DateFormatter.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 31A271BF17CE9B5B00E3FA7D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 31A271DB17CE9C3A00E3FA7D /* ISO8601ForCocoaCalendarDateTests.m in Sources */, 3904FF2817CF34AE003603D1 /* MBMockLocale.m in Sources */, 3904FF2A17CF34AE003603D1 /* NSLocale+UnitTestSwizzling.m in Sources */, 31419D9817E08256007B02E2 /* ISO8601ForCocoaWeekDateTests.m in Sources */, 3198826517FCF2B0005FB1DA /* ISO8601MemoryWarningTests.m in Sources */, 312D4C451B9CA7D600FF3602 /* ISO8601Testing.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 31AEAFC517546BC800BD292F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 31AEAFF817546BFB00BD292F /* ISO8601DateFormatter.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 31AEAFD817546BC800BD292F /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 312D4C441B9CA7D300FF3602 /* ISO8601Testing.m in Sources */, 31AEAFEC17546BC900BD292F /* ISO8601ForCocoaCalendarDateTests.m in Sources */, 3904FF2717CF34AE003603D1 /* MBMockLocale.m in Sources */, 3904FF2917CF34AE003603D1 /* NSLocale+UnitTestSwizzling.m in Sources */, 31419D9717E08256007B02E2 /* ISO8601ForCocoaWeekDateTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 31A271CA17CE9B5B00E3FA7D /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 31A271B417CE9B5A00E3FA7D /* ISO8601ForCocoaTouch */; targetProxy = 31A271C917CE9B5B00E3FA7D /* PBXContainerItemProxy */; }; 31AEAFE217546BC800BD292F /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 31AEAFC817546BC800BD292F /* ISO8601ForCocoa */; targetProxy = 31AEAFE117546BC800BD292F /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 31A271CF17CE9B5B00E3FA7D /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 31A271D017CE9B5B00E3FA7D /* en */, ); name = InfoPlist.strings; sourceTree = ""; }; 31AEAFE717546BC800BD292F /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 31AEAFE817546BC800BD292F /* en */, ); name = InfoPlist.strings; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 027E31CB1A52DFCE00802098 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; INFOPLIST_FILE = ISO8601DateFormatter/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = org.boredzo.ISO8601; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; 027E31CC1A52DFCE00802098 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; INFOPLIST_FILE = ISO8601DateFormatter/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = org.boredzo.ISO8601; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Release; }; 31A271D517CE9B5B00E3FA7D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = NO; DSTROOT = /tmp/ISO8601ForCocoaTouch.dst; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "ISO8601ForCocoaTouch/ISO8601ForCocoaTouch-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", "ISO8601_TESTING_PURPOSES_ONLY=1", ); IPHONEOS_DEPLOYMENT_TARGET = 5.0; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; }; name = Debug; }; 31A271D617CE9B5B00E3FA7D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = NO; DSTROOT = /tmp/ISO8601ForCocoaTouch.dst; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "ISO8601ForCocoaTouch/ISO8601ForCocoaTouch-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", "ISO8601_TESTING_PURPOSES_ONLY=1", ); IPHONEOS_DEPLOYMENT_TARGET = 5.0; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; VALIDATE_PRODUCT = YES; }; name = Release; }; 31A271D717CE9B5B00E3FA7D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; FRAMEWORK_SEARCH_PATHS = ( "\"$(SDKROOT)/Developer/Library/Frameworks\"", "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", "$(inherited)", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "ISO8601ForCocoaTouch/ISO8601ForCocoaTouch-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", "ISO8601_TESTING_PURPOSES_ONLY=1", ); INFOPLIST_FILE = "ISO8601ForCocoaTouchTests/ISO8601ForCocoaTouchTests-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 5.0; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; }; name = Debug; }; 31A271D817CE9B5B00E3FA7D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; FRAMEWORK_SEARCH_PATHS = ( "\"$(SDKROOT)/Developer/Library/Frameworks\"", "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", "$(inherited)", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "ISO8601ForCocoaTouch/ISO8601ForCocoaTouch-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = ( "$(inherited)", "ISO8601_TESTING_PURPOSES_ONLY=1", ); INFOPLIST_FILE = "ISO8601ForCocoaTouchTests/ISO8601ForCocoaTouchTests-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 5.0; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; }; name = Release; }; 31AEAFED17546BC900BD292F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD)"; "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; }; name = Debug; }; 31AEAFEE17546BC900BD292F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD)"; "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_64_BIT)"; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_VARIABLE = YES; }; name = Release; }; 31AEAFF017546BC900BD292F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; GCC_GENERATE_TEST_COVERAGE_FILES = YES; GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "ISO8601ForCocoa/ISO8601ForCocoa-Prefix.pch"; MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; }; name = Debug; }; 31AEAFF117546BC900BD292F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; GCC_GENERATE_TEST_COVERAGE_FILES = YES; GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "ISO8601ForCocoa/ISO8601ForCocoa-Prefix.pch"; MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; }; name = Release; }; 31AEAFF317546BC900BD292F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", "$(inherited)", ); GCC_GENERATE_TEST_COVERAGE_FILES = YES; GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "ISO8601ForCocoa/ISO8601ForCocoa-Prefix.pch"; INFOPLIST_FILE = "ISO8601ForCocoaTests/ISO8601ForCocoaTests-Info.plist"; MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; }; name = Debug; }; 31AEAFF417546BC900BD292F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", "$(inherited)", ); GCC_GENERATE_TEST_COVERAGE_FILES = YES; GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "ISO8601ForCocoa/ISO8601ForCocoa-Prefix.pch"; INFOPLIST_FILE = "ISO8601ForCocoaTests/ISO8601ForCocoaTests-Info.plist"; MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = macosx; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 027E31CF1A52DFCE00802098 /* Build configuration list for PBXNativeTarget "ISO8601" */ = { isa = XCConfigurationList; buildConfigurations = ( 027E31CB1A52DFCE00802098 /* Debug */, 027E31CC1A52DFCE00802098 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 31A271D917CE9B5B00E3FA7D /* Build configuration list for PBXNativeTarget "ISO8601ForCocoaTouch" */ = { isa = XCConfigurationList; buildConfigurations = ( 31A271D517CE9B5B00E3FA7D /* Debug */, 31A271D617CE9B5B00E3FA7D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 31A271DA17CE9B5B00E3FA7D /* Build configuration list for PBXNativeTarget "ISO8601ForCocoaTouchTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 31A271D717CE9B5B00E3FA7D /* Debug */, 31A271D817CE9B5B00E3FA7D /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 31AEAFC417546BC800BD292F /* Build configuration list for PBXProject "ISO8601ForCocoa" */ = { isa = XCConfigurationList; buildConfigurations = ( 31AEAFED17546BC900BD292F /* Debug */, 31AEAFEE17546BC900BD292F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 31AEAFEF17546BC900BD292F /* Build configuration list for PBXNativeTarget "ISO8601ForCocoa" */ = { isa = XCConfigurationList; buildConfigurations = ( 31AEAFF017546BC900BD292F /* Debug */, 31AEAFF117546BC900BD292F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 31AEAFF217546BC900BD292F /* Build configuration list for PBXNativeTarget "ISO8601ForCocoaTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 31AEAFF317546BC900BD292F /* Debug */, 31AEAFF417546BC900BD292F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 31AEAFC117546BC800BD292F /* Project object */; } ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoa.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoa.xcodeproj/xcshareddata/xcschemes/ISO8601DateFormatter.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoa.xcodeproj/xcshareddata/xcschemes/ISO8601ForCocoa.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoa.xcodeproj/xcshareddata/xcschemes/ISO8601ForCocoaTouch.xcscheme ================================================ ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTests/ISO8601ForCocoaCalendarDateTests.h ================================================ // // ISO8601ForCocoaCalendarDateTests.h // ISO8601ForCocoaCalendarDateTests // // Created by Peter Hosey on 2013-05-27. // Copyright (c) 2013–2015 Peter Hosey. All rights reserved. // #import //This should be set to 1 (actually, removed from all uses) after the dateComponentsFromString: methods are refactored to behave reasonably on their own, rather than as the implementation of the dateFromString: methods. //For example, “T22” currently returns mostly zero components, when it should return all but one undefined. The filling in of zeroes and the current date should happen on dateFromString:'s side. That refactor is on hold pending much more test coverage (especially of dateFromString: cases). #define POST_DATE_COMPONENTS_REFACTOR 0 @interface ISO8601ForCocoaCalendarDateTests : XCTestCase - (void) testParsingDateInPacificStandardTime; - (void) testUnparsingDateInPacificStandardTime; - (void) testParsingDateInPacificDaylightTime; - (void) testUnparsingDateInPacificDaylightTime; //Test case for https://github.com/boredzo/iso-8601-date-formatter/issues/15 - (void) testUnparsingDateAtRiskOfAccidentalPM; - (void) testParsingDateInGreenwichMeanTime; - (void) testUnparsingDateInGreenwichMeanTime; - (void) testParsingDateWithFractionOfSecondWithoutLosingPrecision; - (void) testParsingDateWithUnusualTimeSeparator; - (void) testUnparsingDateWithUnusualTimeSeparator; - (void) testParsingDateWithTimeZoneSeparator; - (void) testUnparsingDateWithTimeZoneSeparator; - (void) testParsingDateWithIncompleteTime; #if POST_DATE_COMPONENTS_REFACTOR - (void) testParsingDateWithTimeOnly; #endif - (void) testUnparsingDatesWithoutTime; //Test case for https://github.com/boredzo/iso-8601-date-formatter/issues/6 - (void) testUnparsingDateInDaylightSavingTime; //Test case for https://github.com/boredzo/iso-8601-date-formatter/issues/3 and https://github.com/boredzo/iso-8601-date-formatter/issues/5 - (void) testUnparsingDateWithinBritishSummerTimeAsUTC; //Test case for https://github.com/boredzo/iso-8601-date-formatter/pull/20 - (void) testStrictModeRejectsSlashyDates; - (void) testParseNilIntoDateComponents; - (void) testParseNilIntoDate; - (void) testStringFromInapplicableObjectValues; - (void) testParsingDateWithSpaceInFrontOfItStrictly; - (void) testParsingDateWithSpaceInFrontOfItNonStrictly; - (void) testParsingSloppyDatesStrictly; - (void) testParsingDateFromSubstring; @end ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTests/ISO8601ForCocoaCalendarDateTests.m ================================================ // // ISO8601ForCocoaCalendarDateTests.m // ISO8601ForCocoaCalendarDateTests // // Created by Peter Hosey on 2013-05-27. // Copyright (c) 2013–2015 Peter Hosey. All rights reserved. // //#import #import "ISO8601ForCocoaCalendarDateTests.h" #import "ISO8601DateFormatter.h" #import "NSLocale+UnitTestSwizzling.h" #import "ISO8601Testing.h" #import "PRHNamedCharacter.h" #include static const NSTimeInterval gSecondsPerHour = 3600.0; @interface ISO8601ForCocoaCalendarDateTests () - (void) attemptToParseString:(NSString *)dateString expectTimeIntervalSinceReferenceDate:(NSTimeInterval)expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:(NSTimeInterval)expectedHoursFromGMT; @end @implementation ISO8601ForCocoaCalendarDateTests { ISO8601DateFormatter *_iso8601DateFormatter; } - (void) setUp { [super setUp]; _iso8601DateFormatter = [[ISO8601DateFormatter alloc] init]; } - (void) tearDown { _iso8601DateFormatter = nil; [super tearDown]; } - (void) attemptToParseString:(NSString *)dateString expectTimeIntervalSinceReferenceDate:(NSTimeInterval)expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:(NSTimeInterval)expectedHoursFromGMT { const NSTimeInterval expectedSecondsFromGMT = expectedHoursFromGMT * gSecondsPerHour; NSTimeZone *timeZone = nil; NSDate *date = [_iso8601DateFormatter dateFromString:dateString timeZone:&timeZone]; XCTAssertNotNil(date, @"Parsing a valid ISO 8601 calendar date should return an NSDate object"); XCTAssertNotNil(timeZone, @"Parsing a valid ISO 8601 calendar date that specifies a time zone offset should return an NSTimeZone object"); XCTAssertEqualWithAccuracy([date timeIntervalSinceReferenceDate], expectedTimeIntervalSinceReferenceDate, 0.0001, @"Date parsed from '%@' should be %f seconds since the reference date", dateString, expectedTimeIntervalSinceReferenceDate); NSInteger secondsFromGMTForDate = [timeZone secondsFromGMTForDate:date]; XCTAssertEqual(secondsFromGMTForDate, (NSInteger)expectedSecondsFromGMT, @"Time zone parsed from '%@' should be %f seconds (%f hours) from GMT, not %ld seconds (%f hours)", dateString, expectedSecondsFromGMT, expectedHoursFromGMT, secondsFromGMTForDate, secondsFromGMTForDate / gSecondsPerHour); } - (void) attemptToUnparseDateWithTimeIntervalSinceReferenceDate:(NSTimeInterval)timeIntervalSinceReferenceDate timeZoneName:(NSString *)tzName expectDateString:(NSString *)expectedDateString includeTime:(bool)includeTime { NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:timeIntervalSinceReferenceDate]; NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:tzName]; _iso8601DateFormatter.includeTime = includeTime; NSString *dateString = [_iso8601DateFormatter stringFromDate:date timeZone:timeZone]; XCTAssertNotNil(dateString, @"Unparsing a date should return a string"); XCTAssertEqualObjects(dateString, expectedDateString, @"Got unexpected output for date with time interval since reference date %f in time zone %@", timeIntervalSinceReferenceDate, timeZone); } - (void) testParsingDateInPacificStandardTime { static NSString *const dateString = @"2013-01-01T01:01:01-0800"; static NSTimeInterval const expectedTimeIntervalSinceReferenceDate = 378723661.0; static NSTimeInterval const expectedHoursFromGMT = -8.0; [self attemptToParseString:dateString expectTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:expectedHoursFromGMT]; } - (void) testUnparsingDateInPacificStandardTime { NSTimeInterval timeIntervalSinceReferenceDate = 378723661.0; NSString *expectedDateString = @"2013-01-01T01:01:01-0800"; NSString *tzName = @"America/Los_Angeles"; [self attemptToUnparseDateWithTimeIntervalSinceReferenceDate:timeIntervalSinceReferenceDate timeZoneName:tzName expectDateString:expectedDateString includeTime:true]; } - (void) testParsingDateInPacificDaylightTime { static NSString *const dateString = @"2013-08-01T01:01:01-0700"; static NSTimeInterval const expectedTimeIntervalSinceReferenceDate = 397036861.0; static NSTimeInterval const expectedHoursFromGMT = -7.0; [self attemptToParseString:dateString expectTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:expectedHoursFromGMT]; } - (void) testUnparsingDateInPacificDaylightTime { NSTimeInterval timeIntervalSinceReferenceDate = 397036861.0; NSString *expectedDateString = @"2013-08-01T01:01:01-0700"; NSString *tzName = @"America/Los_Angeles"; [self attemptToUnparseDateWithTimeIntervalSinceReferenceDate:timeIntervalSinceReferenceDate timeZoneName:tzName expectDateString:expectedDateString includeTime:true]; } - (void) testUnparsingDateAtRiskOfAccidentalPM { // swizzle [NSLocale currentLocale] with a method that returns a mock object which forces "12 hour mode" on the de_DE locale which naturally uses 24 hour formatting. SwizzleClassMethod([NSLocale class], @selector(currentLocale), @selector(mockCurrentLocale)); _iso8601DateFormatter.includeTime = YES; NSTimeInterval timeIntervalSinceReferenceDate = 397143300.0; NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:timeIntervalSinceReferenceDate]; NSTimeZone *tz; tz = [NSTimeZone timeZoneWithName:@"GMT"]; XCTAssertEqualObjects([_iso8601DateFormatter stringFromDate:date timeZone:tz], @"2013-08-02T13:35:00Z", @"Unexpected date string for 13:35 on 2 August 2013 in London"); tz = [NSTimeZone timeZoneWithName:@"Europe/London"]; XCTAssertEqualObjects([_iso8601DateFormatter stringFromDate:date timeZone:tz], @"2013-08-02T14:35:00+0100", @"Unexpected date string for 13:35 on 2 August 2013 in London"); // swizzle back so only this test is affected SwizzleClassMethod([NSLocale class], @selector(currentLocale), @selector(mockCurrentLocale)); } - (void) testParsingDateInGreenwichMeanTime { static NSTimeInterval const expectedTimeIntervalSinceReferenceDate = 381373261.0; static NSTimeInterval const expectedHoursFromGMT = -0.0; [self attemptToParseString:@"2013-02-01T01:01:01-0000" expectTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:expectedHoursFromGMT]; [self attemptToParseString:@"2013-02-01T01:01:01+0000" expectTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:expectedHoursFromGMT]; [self attemptToParseString:@"2013-02-01T01:01:01Z" expectTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:expectedHoursFromGMT]; } - (void) testUnparsingDateInGreenwichMeanTime { NSTimeInterval timeIntervalSinceReferenceDate = 381373261.0; NSString *expectedDateString = @"2013-02-01T01:01:01Z"; NSString *tzName = @"GMT"; [self attemptToUnparseDateWithTimeIntervalSinceReferenceDate:timeIntervalSinceReferenceDate timeZoneName:tzName expectDateString:expectedDateString includeTime:true]; } - (void) testParsingDateWithFractionOfSecondWithoutLosingPrecision { NSDate *referenceDate = [_iso8601DateFormatter dateFromString:@"2013-02-01T01:01:01-0000"]; NSDate *referenceDateWithAddedMilliseconds = [_iso8601DateFormatter dateFromString:@"2013-02-01T01:01:01.123-0000"]; NSTimeInterval differenceBetweenDates = [referenceDateWithAddedMilliseconds timeIntervalSinceDate:referenceDate]; XCTAssertEqualWithAccuracy(differenceBetweenDates, 0.123, 1e-3, @"Expected parsed dates to reflect difference in milliseconds"); } - (void) testParsingDateWithUnusualTimeSeparator { _iso8601DateFormatter.parsesStrictly = false; _iso8601DateFormatter.timeSeparator = SNOWMAN; static NSString *const dateString = @"2013-01-01T01☃01☃01-0800"; static NSTimeInterval const expectedTimeIntervalSinceReferenceDate = 378723661.0; static NSTimeInterval const expectedHoursFromGMT = -8.0; [self attemptToParseString:dateString expectTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:expectedHoursFromGMT]; } - (void) testUnparsingDateWithUnusualTimeSeparator { _iso8601DateFormatter.timeSeparator = SNOWMAN; NSTimeInterval timeIntervalSinceReferenceDate = 378723661.0; NSString *expectedDateString = @"2013-01-01T01☃01☃01-0800"; NSString *tzName = @"America/Los_Angeles"; [self attemptToUnparseDateWithTimeIntervalSinceReferenceDate:timeIntervalSinceReferenceDate timeZoneName:tzName expectDateString:expectedDateString includeTime:true]; } - (void) testParsingDateWithTimeZoneSeparator { _iso8601DateFormatter.timeZoneSeparator = SNOWMAN; static NSString *const dateString = @"2013-08-01T01:01:01-07☃30"; static NSTimeInterval const expectedTimeIntervalSinceReferenceDate = 397038661.0; static NSTimeInterval const expectedHoursFromGMT = -7.5; [self attemptToParseString:dateString expectTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:expectedHoursFromGMT]; } - (void) testUnparsingDateWithTimeZoneSeparator { _iso8601DateFormatter.timeZoneSeparator = ':'; NSTimeInterval timeIntervalSinceReferenceDate = 378723661.0; NSString *expectedDateString = @"2013-01-01T01:01:01-08:00"; NSString *tzName = @"America/Los_Angeles"; [self attemptToUnparseDateWithTimeIntervalSinceReferenceDate:timeIntervalSinceReferenceDate timeZoneName:tzName expectDateString:expectedDateString includeTime:true]; } - (void) testParsingDateWithIncompleteTime { NSString *string; NSTimeInterval expectedTimeIntervalSinceReferenceDate; NSDate *date; NSDate *expectedDate; string = @"2013-09-10T21:41:05Z"; expectedTimeIntervalSinceReferenceDate = 400542065.0; expectedDate = [NSDate dateWithTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate]; date = [_iso8601DateFormatter dateFromString:string]; XCTAssertEqualObjects(date, expectedDate, @"Date %@ doesn't match string %@", date, string); string = @"2013-09-10T21:41Z"; expectedTimeIntervalSinceReferenceDate = 400542060.0; expectedDate = [NSDate dateWithTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate]; date = [_iso8601DateFormatter dateFromString:string]; XCTAssertEqualObjects(date, expectedDate, @"Date %@ doesn't match string %@", date, string); string = @"2013-09-10T21Z"; expectedTimeIntervalSinceReferenceDate = 400539600.0; expectedDate = [NSDate dateWithTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate]; date = [_iso8601DateFormatter dateFromString:string]; XCTAssertEqualObjects(date, expectedDate, @"Date %@ doesn't match string %@", date, string); } #if POST_DATE_COMPONENTS_REFACTOR - (void) testParsingDateWithTimeOnly { NSString *timeOnlyString; NSTimeInterval expectedSecondsFromGMT; NSDateComponents *components; NSTimeZone *timeZone; timeOnlyString = @"T22:63:24-11:21"; expectedSecondsFromGMT = -11.0 * 3600.0 + -21.0 * 60.0; components = [_iso8601DateFormatter dateComponentsFromString:timeOnlyString timeZone:&timeZone]; XCTAssertEqual(components.hour, (NSInteger)22, @"Expected hour of '%@' to be 22", timeOnlyString); XCTAssertEqual(components.minute, (NSInteger)63, @"Expected minute of '%@' to be 63", timeOnlyString); XCTAssertEqual(components.second, (NSInteger)24, @"Expected second of '%@' to be 24", timeOnlyString); XCTAssertNotNil(timeZone, @"Expected '%@' to yield a time zone", timeOnlyString); XCTAssertEqual(timeZone.secondsFromGMT, (NSInteger)expectedSecondsFromGMT, @"Expected time zone offset of '%@' to be 11 hours and 21 minutes west of GMT", timeOnlyString); timeOnlyString = @"T22:63:24+50:70"; expectedSecondsFromGMT = +50.0 * 3600.0 + +70.0 * 60.0; components = [_iso8601DateFormatter dateComponentsFromString:timeOnlyString timeZone:&timeZone]; XCTAssertEqual(components.hour, (NSInteger)22, @"Expected hour of '%@' to be 22", timeOnlyString); XCTAssertEqual(components.minute, (NSInteger)63, @"Expected minute of '%@' to be 63", timeOnlyString); XCTAssertEqual(components.second, (NSInteger)24, @"Expected second of '%@' to be 24", timeOnlyString); XCTAssertNotNil(timeZone, @"Expected '%@' to yield a time zone", timeOnlyString); XCTAssertEqual(timeZone.secondsFromGMT, (NSInteger)expectedSecondsFromGMT, @"Expected time zone offset of '%@' to be 50 hours and 70 minutes east of GMT", timeOnlyString); timeOnlyString = @"T22:1:2"; components = [_iso8601DateFormatter dateComponentsFromString:timeOnlyString]; XCTAssertEqual(components.hour, (NSInteger)22, @"Expected hour of '%@' to be 22", timeOnlyString); XCTAssertEqual(components.minute, (NSInteger)1, @"Expected minute of '%@' to be 1", timeOnlyString); XCTAssertEqual(components.second, (NSInteger)2, @"Expected second of '%@' to be 2", timeOnlyString); timeOnlyString = @"T22:1Z"; expectedSecondsFromGMT = 0.0; components = [_iso8601DateFormatter dateComponentsFromString:timeOnlyString timeZone:&timeZone]; XCTAssertEqual(components.hour, (NSInteger)22, @"Expected hour of '%@' to be 22", timeOnlyString); XCTAssertEqual(components.minute, (NSInteger)1, @"Expected minute of '%@' to be 1", timeOnlyString); XCTAssertEqual(components.second, (NSInteger)NSUndefinedDateComponent, @"Expected second of '%@' to be undefined", timeOnlyString); XCTAssertEqual(timeZone.secondsFromGMT, (NSInteger)expectedSecondsFromGMT, @"Expected time zone offset of '%@' to be zero (GMT)", timeOnlyString); timeOnlyString = @"T22:"; components = [_iso8601DateFormatter dateComponentsFromString:timeOnlyString]; XCTAssertEqual(components.hour, (NSInteger)22, @"Expected hour of '%@' to be 22", timeOnlyString); XCTAssertEqual(components.minute, (NSInteger)NSUndefinedDateComponent, @"Expected minute of '%@' to be undefined", timeOnlyString); XCTAssertEqual(components.second, (NSInteger)NSUndefinedDateComponent, @"Expected second of '%@' to be undefined", timeOnlyString); timeOnlyString = @"T22"; components = [_iso8601DateFormatter dateComponentsFromString:timeOnlyString]; XCTAssertEqual(components.hour, (NSInteger)22, @"Expected hour of '%@' to be 22", timeOnlyString); XCTAssertEqual(components.minute, (NSInteger)NSUndefinedDateComponent, @"Expected minute of '%@' to be undefined", timeOnlyString); XCTAssertEqual(components.second, (NSInteger)NSUndefinedDateComponent, @"Expected second of '%@' to be undefined", timeOnlyString); timeOnlyString = @"T2"; components = [_iso8601DateFormatter dateComponentsFromString:timeOnlyString]; XCTAssertEqual(components.hour, (NSInteger)2, @"Expected hour of '%@' to be 2", timeOnlyString); XCTAssertEqual(components.minute, (NSInteger)NSUndefinedDateComponent, @"Expected minute of '%@' to be undefined", timeOnlyString); XCTAssertEqual(components.second, (NSInteger)NSUndefinedDateComponent, @"Expected second of '%@' to be undefined", timeOnlyString); timeOnlyString = @"T2:2:2"; components = [_iso8601DateFormatter dateComponentsFromString:timeOnlyString]; XCTAssertEqual(components.hour, (NSInteger)2, @"Expected hour of '%@' to be 2", timeOnlyString); XCTAssertEqual(components.minute, (NSInteger)2, @"Expected minute of '%@' to be 2", timeOnlyString); XCTAssertEqual(components.second, (NSInteger)2, @"Expected second of '%@' to be 2", timeOnlyString); } #endif - (void) testUnparsingDatesWithoutTime { _iso8601DateFormatter.includeTime = false; NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; XCTAssertNotNil(calendar, @"Couldn't create Gregorian calendar with which to set up date-unparsing tests"); NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; XCTAssertNotNil(calendar, @"Couldn't create C/POSIX locale with which to set up date-unparsing tests"); calendar.locale = locale; NSDateComponents *components = [NSDateComponents new]; components.month = 1; components.day = 1; for (NSUInteger year = 1990; year < 2020; ++year) { components.year = year; NSDate *date = [calendar dateFromComponents:components]; NSString *expectedString = [NSString stringWithFormat:@"%04ld-%02ld-%02ld", components.year, components.month, components.day]; NSString *string = [_iso8601DateFormatter stringFromDate:date]; XCTAssertEqualObjects(string, expectedString, @"Got surprising string for January 1, %lu", year); } } - (void) testUnparsingDateInDaylightSavingTime { _iso8601DateFormatter.defaultTimeZone = [NSTimeZone timeZoneWithName:@"Europe/Prague"]; _iso8601DateFormatter.includeTime = YES; NSDate *date; NSString *string; NSString *expectedString; date = [NSDate dateWithTimeIntervalSinceReferenceDate:365464800.0]; string = [_iso8601DateFormatter stringFromDate:date]; expectedString = @"2012-08-01T00:00:00+0200"; XCTAssertEqualObjects(string, expectedString, @"Got wrong string for first date in DST in Prague #1 (check whether DST is included in TZ offset)"); date = [NSDate dateWithTimeIntervalSinceReferenceDate:373417200.0]; string = [_iso8601DateFormatter stringFromDate:date]; expectedString = @"2012-11-01T00:00:00+0100"; XCTAssertEqualObjects(string, expectedString, @"Got wrong string for second date in DST in Prague #1 (check whether DST is included in TZ offset)"); } - (void) testUnparsingDateWithinBritishSummerTimeAsUTC { _iso8601DateFormatter.includeTime = YES; NSDate *date; NSString *expectedString; NSString *string; NSTimeZone *UTCTimeZone = [NSTimeZone timeZoneWithName:@"UTC"]; date = [NSDate dateWithTimeIntervalSinceReferenceDate:354987473.0]; expectedString = @"2012-04-01T15:37:53Z"; string = [_iso8601DateFormatter stringFromDate:date timeZone:UTCTimeZone]; XCTAssertEqualObjects(string, expectedString, @"Got wrong string for April date in UTC (check whether DST is included in TZ offset)"); _iso8601DateFormatter.defaultTimeZone = UTCTimeZone; string = [_iso8601DateFormatter stringFromDate:date]; XCTAssertEqualObjects(string, expectedString, @"Got wrong string for April date in UTC-as-default (check whether DST is included in TZ offset)"); //Date https://github.com/boredzo/iso-8601-date-formatter/issues/3 was filed. date = [NSDate dateWithTimeIntervalSinceReferenceDate:370245466.0]; expectedString = @"2012-09-25T05:57:46Z"; string = [_iso8601DateFormatter stringFromDate:date]; XCTAssertEqualObjects(string, expectedString, @"Got wrong string for September date in UTC-as-default (check whether DST is included in TZ offset)"); } //https://github.com/boredzo/iso-8601-date-formatter/issues/31 - (void) testParsingOctober9th2013 { NSDate *date = [_iso8601DateFormatter dateFromString:@"2013-10-09T13:00:00Z"]; //#31 is a crash, so we shouldn't even get here. XCTAssertNotNil(date, @"1 PM UTC on October 9th, 2013 should not be nil"); } // https://github.com/boredzo/iso-8601-date-formatter/issues/36 - (void) testParsingFractionaryTimeZone { _iso8601DateFormatter.includeTime = YES; NSTimeZone *UTCTimeZone = [NSTimeZone timeZoneForSecondsFromGMT:gSecondsPerHour*-2.5]; NSDate *date= [NSDate dateWithTimeIntervalSinceReferenceDate:354987473.0]; NSString *expectedString = @"2012-04-01T13:07:53-0230"; NSString *string = [_iso8601DateFormatter stringFromDate:date timeZone:UTCTimeZone]; XCTAssertEqualObjects(string, expectedString, @"Got wrong string for fractionary time zone"); } - (void) testStrictModeRejectsSlashyDates { _iso8601DateFormatter.parsesStrictly = true; NSString *dateString = @"11/27/1982"; NSDate *date = [_iso8601DateFormatter dateFromString:dateString]; XCTAssertNil(date, @"Slashy date string '%@' should not have been parsed as anything, let alone %@", dateString, date); } - (void) testParseNilIntoDateComponents { NSDateComponents *components = [_iso8601DateFormatter dateComponentsFromString:nil]; XCTAssertNil(components, @"dateComponentsFromString:nil should have returned nil, but returned %@", components); } - (void) testParseNilIntoDate { NSDate *date = [_iso8601DateFormatter dateFromString:nil]; XCTAssertNil(date, @"dateFromString:nil returned should have returned nil, but returned %@", date); } - (void) testStringFromInapplicableObjectValues { NSString *string = nil; XCTAssertNoThrow((string = [_iso8601DateFormatter stringForObjectValue:@42]), @"stringForObjectValue:@42 threw an exception"); XCTAssertNil(string, @"stringForObjectValue:@42 should have returned nil, but returned %@", string); XCTAssertNoThrow((string = [_iso8601DateFormatter stringForObjectValue:[NSFileManager defaultManager]]), @"stringForObjectValue:[NSFileManager] failed to throw an exception"); XCTAssertNil(string, @"stringForObjectValue:[NSFileManager] should have returned nil, but returned %@", string); XCTAssertNoThrow((string = [_iso8601DateFormatter stringForObjectValue:self]), @"stringForObjectValue:%@ failed to throw an exception", self); XCTAssertNil(string, @"stringForObjectValue:self should have returned nil, but returned %@", string); } - (void) testParsingDateWithSpaceInFrontOfItStrictly { NSString *dateString = @"2013-09-12T23:40Z"; [self attemptToParseDateString:dateString prefixedWithString:@" " strictMode:true expectedDate:nil]; [self attemptToParseDateString:dateString prefixedWithString:@"\t" strictMode:true expectedDate:nil]; [self attemptToParseDateString:dateString prefixedWithString:@"\n" strictMode:true expectedDate:nil]; [self attemptToParseDateString:dateString prefixedWithString:@"\v" strictMode:true expectedDate:nil]; [self attemptToParseDateString:dateString prefixedWithString:@"\f" strictMode:true expectedDate:nil]; [self attemptToParseDateString:dateString prefixedWithString:@"\r" strictMode:true expectedDate:nil]; } - (void) testParsingDateWithSpaceInFrontOfItNonStrictly { NSString *dateString = @"2013-09-12T23:40Z"; NSDate *expectedDate = [NSDate dateWithTimeIntervalSinceReferenceDate:400722000.0]; [self attemptToParseDateString:dateString prefixedWithString:@" " strictMode:false expectedDate:expectedDate]; [self attemptToParseDateString:dateString prefixedWithString:@"\t" strictMode:false expectedDate:expectedDate]; [self attemptToParseDateString:dateString prefixedWithString:@"\n" strictMode:false expectedDate:expectedDate]; [self attemptToParseDateString:dateString prefixedWithString:@"\v" strictMode:false expectedDate:expectedDate]; [self attemptToParseDateString:dateString prefixedWithString:@"\f" strictMode:false expectedDate:expectedDate]; [self attemptToParseDateString:dateString prefixedWithString:@"\r" strictMode:false expectedDate:expectedDate]; } - (void) attemptToParseDateString:(NSString *)dateString prefixedWithString:(NSString *)prefix strictMode:(bool)strict expectedDate:(NSDate *)expectedDate { _iso8601DateFormatter.parsesStrictly = strict; XCTAssertEqual(_iso8601DateFormatter.parsesStrictly, (typeof(_iso8601DateFormatter.parsesStrictly))strict, @"Date formatter %@ blew off an attempt to set whether it parses strictly to %@", _iso8601DateFormatter, strict ? @"true" : @"false"); NSString *string = [prefix stringByAppendingString:dateString]; NSDate *date = [_iso8601DateFormatter dateFromString:string]; if (strict) { XCTAssertNil(date, @"Strictly parsing string '%@' should have returned nil, not %@", [self stringByEscapingString:string], date); } else { XCTAssertNotNil(date, @"Parsing string '%@' with strict mode off should have returned a date, not nil", [self stringByEscapingString:string]); XCTAssertEqualObjects(date, expectedDate, @"Parsing string '%@' with strict mode off returned wrong date (expected %f, got %f)", [self stringByEscapingString:string], expectedDate.timeIntervalSinceReferenceDate, date.timeIntervalSinceReferenceDate); } } - (NSString *) stringByEscapingString:(NSString *)string { NSData *unescapedData = [string dataUsingEncoding:NSUTF8StringEncoding]; NSUInteger length = unescapedData.length; //NUL-terminate it. { NSMutableData *tempData = [unescapedData mutableCopy]; tempData.length = length + 1; unescapedData = tempData; } NSMutableData *escapedData = [NSMutableData dataWithLength:length * 4UL + 1UL]; escapedData.length = (NSUInteger)strvis(escapedData.mutableBytes, unescapedData.bytes, VIS_WHITE | VIS_CSTYLE); return [[NSString alloc] initWithData:escapedData encoding:NSASCIIStringEncoding]; } //This is really only here because test code counts toward code coverage. - (void) testStringEscaping { NSString *string; NSString *escapedString; string = @"foo"; escapedString = [self stringByEscapingString:string]; XCTAssertEqualObjects(escapedString, string, @"Escaping an all-letters string should effect no change, not produce '%@'", escapedString); string = @"foo123"; escapedString = [self stringByEscapingString:string]; XCTAssertEqualObjects(escapedString, string, @"Escaping an alphanumeric string should effect no change, not produce '%@'", escapedString); NSString *expectedString; expectedString = @"\\t\\n\\v\\f\\r"; string = @"\t\n\v\f\r"; escapedString = [self stringByEscapingString:string]; XCTAssertEqualObjects(escapedString, expectedString, @"Escaping a string of whitespace in order should produce escape sequences in order ('%@'), not '%@'", expectedString, escapedString); } - (void) testParsingSloppyDatesStrictly { _iso8601DateFormatter.parsesStrictly = true; NSString *string; NSDate *date; string = @"130918"; date = [_iso8601DateFormatter dateFromString:string]; XCTAssertNil(date, @"Parsing '%@' strictly should return nil, not %@ (%f)", string, date, date.timeIntervalSinceReferenceDate); string = @"2013-0918"; date = [_iso8601DateFormatter dateFromString:string]; XCTAssertNil(date, @"Parsing '%@' strictly should return nil, not %@ (%f)", string, date, date.timeIntervalSinceReferenceDate); } - (void) testParsingDateFromSubstring { NSString *string; NSTimeInterval expectedTimeIntervalSinceReferenceDate; NSDate *expectedDate; NSTimeZone *expectedTimeZone; NSRange expectedRange; NSDate *date; NSTimeZone *timeZone; NSRange range; #define PREFIX @" \t\t " #define DATE @"2013-09-18T04:18Z" #define NOT_A_DATE @"\u2603" #define SUFFIX @" \t\t " string = PREFIX DATE; expectedTimeIntervalSinceReferenceDate = 401170680.0; expectedDate = [NSDate dateWithTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate]; expectedTimeZone = [NSTimeZone timeZoneWithName:@"UTC"]; expectedRange = (NSRange){ PREFIX.length, DATE.length }; date = [_iso8601DateFormatter dateFromString:string timeZone:&timeZone range:&range]; XCTAssertEqualObjects(date, expectedDate, @"Date from substring of '%@' should be %@ (%f), not %@ (%f) (%+f seconds difference)", string, expectedDate, expectedTimeIntervalSinceReferenceDate, date, date.timeIntervalSinceReferenceDate, [date timeIntervalSinceDate:expectedDate]); XCTAssertEqualObjects(timeZone, expectedTimeZone, @"Time zone from substring of '%@' should be %@, not %@", string, expectedTimeZone, timeZone); ISO8601AssertEqualRanges(range, expectedRange, @"Range of date from substring of '%@' should be %@ ('%@'), not %@ ('%@')", string, NSStringFromRange(expectedRange), [string substringWithRange:expectedRange], NSStringFromRange(range), [string substringWithRange:range]); string = PREFIX DATE SUFFIX; expectedTimeIntervalSinceReferenceDate = 401170680.0; expectedDate = [NSDate dateWithTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate]; expectedTimeZone = [NSTimeZone timeZoneWithName:@"UTC"]; expectedRange = (NSRange){ PREFIX.length, DATE.length }; date = [_iso8601DateFormatter dateFromString:string timeZone:&timeZone range:&range]; XCTAssertEqualObjects(date, expectedDate, @"Date from substring of '%@' should be %@ (%f), not %@ (%f) (%+f seconds difference)", string, expectedDate, expectedTimeIntervalSinceReferenceDate, date, date.timeIntervalSinceReferenceDate, [date timeIntervalSinceDate:expectedDate]); XCTAssertEqualObjects(timeZone, expectedTimeZone, @"Time zone from substring of '%@' should be %@, not %@", string, expectedTimeZone, timeZone); ISO8601AssertEqualRanges(range, expectedRange, @"Range of date from substring of '%@' should be %@ ('%@'), not %@ ('%@')", string, NSStringFromRange(expectedRange), [string substringWithRange:expectedRange], NSStringFromRange(range), [string substringWithRange:range]); string = DATE SUFFIX; expectedTimeIntervalSinceReferenceDate = 401170680.0; expectedDate = [NSDate dateWithTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate]; expectedTimeZone = [NSTimeZone timeZoneWithName:@"UTC"]; expectedRange = (NSRange){ 0, DATE.length }; date = [_iso8601DateFormatter dateFromString:string timeZone:&timeZone range:&range]; XCTAssertEqualObjects(date, expectedDate, @"Date from substring of '%@' should be %@ (%f), not %@ (%f) (%+f seconds difference)", string, expectedDate, expectedTimeIntervalSinceReferenceDate, date, date.timeIntervalSinceReferenceDate, [date timeIntervalSinceDate:expectedDate]); XCTAssertEqualObjects(timeZone, expectedTimeZone, @"Time zone from substring of '%@' should be %@, not %@", string, expectedTimeZone, timeZone); ISO8601AssertEqualRanges(range, expectedRange, @"Range of date from substring of '%@' should be %@ ('%@'), not %@ ('%@')", string, NSStringFromRange(expectedRange), [string substringWithRange:expectedRange], NSStringFromRange(range), [string substringWithRange:range]); string = PREFIX NOT_A_DATE SUFFIX; //Note that timeZone and range are both set to previous results at this point. If dateFromString::: doesn't set them, that will cause a test failure. expectedTimeIntervalSinceReferenceDate = 0.0; expectedDate = nil; expectedTimeZone = nil; expectedRange = (NSRange){ NSNotFound, 0 }; date = [_iso8601DateFormatter dateFromString:string timeZone:&timeZone range:&range]; XCTAssertNil(date, @"Date from substring of '%@' should be nil, not %@ (%f)", string, date, date.timeIntervalSinceReferenceDate); XCTAssertNil(timeZone, @"Time zone from substring of '%@' should be nil, not %@", string, timeZone); ISO8601AssertEqualRanges(range, expectedRange, @"Range of date from substring of '%@' should be %@ ('%@'), not %@ ('%@')", string, NSStringFromRange(expectedRange), [string substringWithRange:expectedRange], NSStringFromRange(range), [string substringWithRange:range]); } @end ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTests/ISO8601ForCocoaTests-Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.boredzo.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTests/ISO8601ForCocoaTimeOnlyTests.h ================================================ // // ISO8601ForCocoaTimeOnlyTests.h // ISO8601ForCocoa // // Created by Peter Hosey on 2013-09-17. // Copyright (c) 2013 Peter Hosey. All rights reserved. // #import @interface ISO8601ForCocoaTimeOnlyTests : XCTestCase - (void) testParsingStringWithOnlyHourMinuteSecondZulu; - (void) testParsingStringWithOnlyHourMinuteZulu; - (void) testParsingStringWithOnlyHourMinuteSecondAndTimeZone; - (void) testParsingStringWithOnlyHourMinuteAndTimeZone; @end ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTests/ISO8601ForCocoaTimeOnlyTests.m ================================================ // // ISO8601ForCocoaTimeOnlyTests.m // ISO8601ForCocoa // // Created by Peter Hosey on 2013-09-17. // Copyright (c) 2013 Peter Hosey. All rights reserved. // #import "ISO8601ForCocoaTimeOnlyTests.h" #import "ISO8601DateFormatter.h" static const NSTimeInterval gSecondsPerHour = 3600.0; static const NSTimeInterval gSecondsPerMinute = 60.0; @implementation ISO8601ForCocoaTimeOnlyTests { ISO8601DateFormatter *_iso8601DateFormatter; } - (void) setUp { [super setUp]; _iso8601DateFormatter = [[ISO8601DateFormatter alloc] init]; } - (void) tearDown { _iso8601DateFormatter = nil; [super tearDown]; } - (NSString *) dateStringWithHour:(NSTimeInterval)hour minute:(NSTimeInterval)minute second:(NSTimeInterval)second timeZone:(NSTimeZone *)timeZone { NSString *format = second > 0.0 ? @"T%02g:%02g:%02g" : minute > 0.0 ? @"T%02g:%02g" : hour > 0.0 ? @"T%02g" : @"no non-zero components provided!" ; NSString *string = [NSString stringWithFormat:format, hour, minute, second]; NSInteger secondsFromGMT = [timeZone secondsFromGMT]; string = secondsFromGMT == 0.0 ? [string stringByAppendingString:@"Z"] : [string stringByAppendingFormat:@"%+03g%02g", secondsFromGMT / gSecondsPerHour, fabs(fmod(secondsFromGMT / gSecondsPerMinute, gSecondsPerMinute))]; return string; } - (NSDate *) dateForTodayWithHour:(NSTimeInterval)hour minute:(NSTimeInterval)minute second:(NSTimeInterval)second timeZone:(NSTimeZone *)timeZone { NSDate *now = [NSDate date]; NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; calendar.timeZone = timeZone; NSDate *today = nil; [calendar rangeOfUnit:NSDayCalendarUnit startDate:&today interval:NULL forDate:now]; NSDateComponents *components = [NSDateComponents new]; components.hour = (NSInteger)hour; components.minute = (NSInteger)minute; components.second = (NSInteger)second; NSDate *date = [calendar dateByAddingComponents:components toDate:today options:0]; return date; } - (void) attemptToParseString:(NSString *)dateString expectTimeIntervalSinceReferenceDate:(NSTimeInterval)expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:(NSTimeInterval)expectedHoursFromGMT { const NSTimeInterval expectedSecondsFromGMT = expectedHoursFromGMT * gSecondsPerHour; NSTimeZone *timeZone = nil; NSDate *date = [_iso8601DateFormatter dateFromString:dateString timeZone:&timeZone]; XCTAssertNotNil(date, @"Parsing a valid ISO 8601 date string (%@) should return an NSDate object", dateString); XCTAssertNotNil(timeZone, @"Parsing a valid ISO 8601 date string (%@) that specifies a time zone offset should return an NSTimeZone object", dateString); XCTAssertEqualWithAccuracy([date timeIntervalSinceReferenceDate], expectedTimeIntervalSinceReferenceDate, 0.0001, @"Date parsed from '%@' should be %f seconds since the reference date (%f seconds difference)", dateString, expectedTimeIntervalSinceReferenceDate, [date timeIntervalSinceDate:[NSDate dateWithTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate]]); NSInteger secondsFromGMTForDate = [timeZone secondsFromGMTForDate:date]; XCTAssertEqual(secondsFromGMTForDate, (NSInteger)expectedSecondsFromGMT, @"Time zone parsed from '%@' should be %f seconds (%f hours) from GMT, not %ld seconds (%f hours)", dateString, expectedSecondsFromGMT, expectedHoursFromGMT, secondsFromGMTForDate, secondsFromGMTForDate / gSecondsPerHour); } /*TODO: These tests are inherently flaky. *You can't build a stable test on [NSDate date]—the results will vary according to the current date and are likely to vary by time zone. *These tests should probably use some sort of “default date” property of the date formatter, and the date formatter should fill in from the current date if and only if its default date is not set. *Additionally, the behavior we're testing is probably best modeled by dateComponentsFromString::, not dateFromString::, once dCFS:: is changed to return only the components that were specified by the string. */ - (void) testParsingStringWithOnlyHourMinuteSecondZulu { NSTimeInterval hour = 14.0, minute = 23.0, second = 56.0; NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"]; NSString *string = [self dateStringWithHour:hour minute:minute second:second timeZone:timeZone]; NSTimeInterval timeInterval = [self dateForTodayWithHour:hour minute:minute second:second timeZone:timeZone].timeIntervalSinceReferenceDate; [self attemptToParseString:string expectTimeIntervalSinceReferenceDate:timeInterval expectTimeZoneWithHoursFromGMT:0.0]; } - (void) testParsingStringWithOnlyHourMinuteZulu { NSTimeInterval hour = 14.0, minute = 23.0; NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"]; NSString *string = [self dateStringWithHour:hour minute:minute second:0.0 timeZone:timeZone]; NSTimeInterval timeInterval = [self dateForTodayWithHour:hour minute:minute second:0.0 timeZone:timeZone].timeIntervalSinceReferenceDate; [self attemptToParseString:string expectTimeIntervalSinceReferenceDate:timeInterval expectTimeZoneWithHoursFromGMT:0.0]; } - (void) testParsingStringWithOnlyHourMinuteSecondAndTimeZone { NSTimeInterval hour = 14.0, minute = 23.0, second = 56.0; NSTimeZone *timeZone = [NSTimeZone timeZoneForSecondsFromGMT:(NSInteger)(-8.0 * gSecondsPerHour)]; NSString *string = [self dateStringWithHour:hour minute:minute second:second timeZone:timeZone]; NSTimeInterval timeInterval = [self dateForTodayWithHour:hour minute:minute second:second timeZone:timeZone].timeIntervalSinceReferenceDate; [self attemptToParseString:string expectTimeIntervalSinceReferenceDate:timeInterval expectTimeZoneWithHoursFromGMT:-8.0]; } - (void) testParsingStringWithOnlyHourMinuteAndTimeZone { NSTimeInterval hour = 14.0, minute = 23.0; NSTimeZone *timeZone = [NSTimeZone timeZoneForSecondsFromGMT:(NSInteger)(-8.0 * gSecondsPerHour)]; NSString *string = [self dateStringWithHour:hour minute:minute second:0.0 timeZone:timeZone]; NSTimeInterval timeInterval = [self dateForTodayWithHour:hour minute:minute second:0.0 timeZone:timeZone].timeIntervalSinceReferenceDate; [self attemptToParseString:string expectTimeIntervalSinceReferenceDate:timeInterval expectTimeZoneWithHoursFromGMT:-8.0]; } @end ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTests/ISO8601ForCocoaWeekDateTests.h ================================================ // // ISO8601ForCocoaWeekDateTests.h // ISO8601ForCocoa // // Created by Peter Hosey on 2013-09-11. // Copyright (c) 2013 Peter Hosey. All rights reserved. // #import @interface ISO8601ForCocoaWeekDateTests : XCTestCase - (void) testParsingDateInPacificStandardTime; - (void) testUnparsingDateInPacificStandardTime; - (void) testParsingDateInPacificDaylightTime; - (void) testUnparsingDateInPacificDaylightTime; //Test case for https://github.com/boredzo/iso-8601-date-formatter/issues/15 - (void) testUnparsingDateAtRiskOfAccidentalPM; - (void) testParsingDateInGreenwichMeanTime; - (void) testUnparsingDateInGreenwichMeanTime; - (void) testParsingDateWithFractionOfSecondWithoutLosingPrecision; - (void) testParsingDateWithUnusualTimeSeparator; - (void) testUnparsingDateWithUnusualTimeSeparator; - (void) testParsingDateWithTimeZoneSeparator; - (void) testUnparsingDateWithTimeZoneSeparator; - (void) testParsingDateWithIncompleteTime; - (void) testUnparsingDateWithoutTime; //Test case for https://github.com/boredzo/iso-8601-date-formatter/issues/6 - (void) testUnparsingDateInDaylightSavingTime; //Test case for https://github.com/boredzo/iso-8601-date-formatter/issues/3 and https://github.com/boredzo/iso-8601-date-formatter/issues/5 - (void) testUnparsingDateWithinBritishSummerTimeAsUTC; @end ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTests/ISO8601ForCocoaWeekDateTests.m ================================================ // // ISO8601ForCocoaWeekDateTests.m // ISO8601ForCocoa // // Created by Peter Hosey on 2013-09-11. // Copyright (c) 2013 Peter Hosey. All rights reserved. // #import "ISO8601ForCocoaWeekDateTests.h" #import "ISO8601DateFormatter.h" #import "NSLocale+UnitTestSwizzling.h" #import "PRHNamedCharacter.h" static const NSTimeInterval gSecondsPerHour = 3600.0; @interface ISO8601ForCocoaWeekDateTests () - (void) attemptToParseString:(NSString *)dateString expectTimeIntervalSinceReferenceDate:(NSTimeInterval)expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:(NSTimeInterval)expectedHoursFromGMT; @end @implementation ISO8601ForCocoaWeekDateTests { ISO8601DateFormatter *_iso8601DateFormatter; } - (void) setUp { [super setUp]; _iso8601DateFormatter = [[ISO8601DateFormatter alloc] init]; } - (void) tearDown { _iso8601DateFormatter = nil; [super tearDown]; } - (void) attemptToParseString:(NSString *)dateString expectTimeIntervalSinceReferenceDate:(NSTimeInterval)expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:(NSTimeInterval)expectedHoursFromGMT { const NSTimeInterval expectedSecondsFromGMT = expectedHoursFromGMT * gSecondsPerHour; NSTimeZone *timeZone = nil; NSDate *date = [_iso8601DateFormatter dateFromString:dateString timeZone:&timeZone]; XCTAssertNotNil(date, @"Parsing a valid ISO 8601 calendar date should return an NSDate object"); XCTAssertNotNil(timeZone, @"Parsing a valid ISO 8601 calendar date that specifies a time zone offset should return an NSTimeZone object"); XCTAssertEqualWithAccuracy([date timeIntervalSinceReferenceDate], expectedTimeIntervalSinceReferenceDate, 0.0001, @"Date parsed from '%@' (%@) should be %f seconds since the reference date (%@)", dateString, date, expectedTimeIntervalSinceReferenceDate, [NSDate dateWithTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate]); NSInteger secondsFromGMTForDate = [timeZone secondsFromGMTForDate:date]; XCTAssertEqual(secondsFromGMTForDate, (NSInteger)expectedSecondsFromGMT, @"Time zone parsed from '%@' should be %f seconds (%f hours) from GMT, not %ld seconds (%f hours)", dateString, expectedSecondsFromGMT, expectedHoursFromGMT, secondsFromGMTForDate, secondsFromGMTForDate / gSecondsPerHour); } - (void) attemptToUnparseDateWithTimeIntervalSinceReferenceDate:(NSTimeInterval)timeIntervalSinceReferenceDate timeZoneName:(NSString *)tzName expectDateString:(NSString *)expectedDateString includeTime:(bool)includeTime { NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:timeIntervalSinceReferenceDate]; NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:tzName]; _iso8601DateFormatter.includeTime = includeTime; _iso8601DateFormatter.format = ISO8601DateFormatWeek; NSString *dateString = [_iso8601DateFormatter stringFromDate:date timeZone:timeZone]; XCTAssertNotNil(dateString, @"Unparsing a date should return a string"); XCTAssertEqualObjects(dateString, expectedDateString, @"Got unexpected output for date with time interval since reference date %f in time zone %@", timeIntervalSinceReferenceDate, timeZone); } - (void) testParsingDateInPacificStandardTime { static NSString *const dateString = @"2007-W01-01T13:24:56-0800"; static NSTimeInterval const expectedTimeIntervalSinceReferenceDate = 189379496.0; static NSTimeInterval const expectedHoursFromGMT = -8.0; [self attemptToParseString:dateString expectTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:expectedHoursFromGMT]; } - (void) testUnparsingDateInPacificStandardTime { NSTimeInterval timeIntervalSinceReferenceDate = 189379496.0; NSString *expectedDateString = @"2007-W01-01T13:24:56-0800"; NSString *tzName = @"America/Los_Angeles"; [self attemptToUnparseDateWithTimeIntervalSinceReferenceDate:timeIntervalSinceReferenceDate timeZoneName:tzName expectDateString:expectedDateString includeTime:true]; } - (void) testParsingDateInPacificDaylightTime { static NSString *const dateString = @"2007-W31-03T13:24:56-0700"; static NSTimeInterval const expectedTimeIntervalSinceReferenceDate = 207692696.0; static NSTimeInterval const expectedHoursFromGMT = -7.0; [self attemptToParseString:dateString expectTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:expectedHoursFromGMT]; } - (void) testUnparsingDateInPacificDaylightTime { NSTimeInterval timeIntervalSinceReferenceDate = 207692696.0; NSString *expectedDateString = @"2007-W31-03T13:24:56-0700"; NSString *tzName = @"America/Los_Angeles"; [self attemptToUnparseDateWithTimeIntervalSinceReferenceDate:timeIntervalSinceReferenceDate timeZoneName:tzName expectDateString:expectedDateString includeTime:true]; } - (void) testUnparsingDateAtRiskOfAccidentalPM { // swizzle [NSLocale currentLocale] with a method that returns a mock object which forces "12 hour mode" on the de_DE locale which naturally uses 24 hour formatting. SwizzleClassMethod([NSLocale class], @selector(currentLocale), @selector(mockCurrentLocale)); _iso8601DateFormatter.includeTime = YES; _iso8601DateFormatter.format = ISO8601DateFormatWeek; NSTimeInterval timeIntervalSinceReferenceDate = 397143300.0; NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:timeIntervalSinceReferenceDate]; NSTimeZone *tz; tz = [NSTimeZone timeZoneWithName:@"GMT"]; XCTAssertEqualObjects([_iso8601DateFormatter stringFromDate:date timeZone:tz], @"2013-W31-05T13:35:00Z", @"Unexpected date string for 13:35 on 2 August 2013 in London"); tz = [NSTimeZone timeZoneWithName:@"Europe/London"]; XCTAssertEqualObjects([_iso8601DateFormatter stringFromDate:date timeZone:tz], @"2013-W31-05T14:35:00+0100", @"Unexpected date string for 13:35 on 2 August 2013 in London"); // swizzle back so only this test is affected SwizzleClassMethod([NSLocale class], @selector(currentLocale), @selector(mockCurrentLocale)); } - (void) testParsingDateInGreenwichMeanTime { static NSTimeInterval const expectedTimeIntervalSinceReferenceDate = 189350696.0; static NSTimeInterval const expectedHoursFromGMT = -0.0; [self attemptToParseString:@"2007-W01-01T13:24:56-0000" expectTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:expectedHoursFromGMT]; [self attemptToParseString:@"2007-W01-01T13:24:56+0000" expectTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:expectedHoursFromGMT]; [self attemptToParseString:@"2007-W01-01T13:24:56Z" expectTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:expectedHoursFromGMT]; } - (void) testUnparsingDateInGreenwichMeanTime { NSTimeInterval timeIntervalSinceReferenceDate = 189350696.0; NSString *expectedDateString = @"2007-W01-01T13:24:56Z"; NSString *tzName = @"GMT"; [self attemptToUnparseDateWithTimeIntervalSinceReferenceDate:timeIntervalSinceReferenceDate timeZoneName:tzName expectDateString:expectedDateString includeTime:true]; } - (void) testParsingDateWithFractionOfSecondWithoutLosingPrecision { NSDate *referenceDate = [_iso8601DateFormatter dateFromString:@"2007-W01-01T13:24:56-0000"]; NSDate *referenceDateWithAddedMilliseconds = [_iso8601DateFormatter dateFromString:@"2007-W01-01T13:24:56.123-0000"]; NSTimeInterval differenceBetweenDates = [referenceDateWithAddedMilliseconds timeIntervalSinceDate:referenceDate]; XCTAssertEqualWithAccuracy(differenceBetweenDates, 0.123, 1e-3, @"Expected parsed dates to reflect difference in milliseconds"); } - (void) testParsingDateWithUnusualTimeSeparator { _iso8601DateFormatter.parsesStrictly = false; _iso8601DateFormatter.timeSeparator = SNOWMAN; static NSString *const dateString = @"2007-W01-01T13☃24☃56-0800"; static NSTimeInterval const expectedTimeIntervalSinceReferenceDate = 189379496.0; static NSTimeInterval const expectedHoursFromGMT = -8.0; [self attemptToParseString:dateString expectTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:expectedHoursFromGMT]; } - (void) testUnparsingDateWithUnusualTimeSeparator { _iso8601DateFormatter.timeSeparator = SNOWMAN; NSTimeInterval timeIntervalSinceReferenceDate = 189379496.0; NSString *expectedDateString = @"2007-W01-01T13☃24☃56-0800"; NSString *tzName = @"America/Los_Angeles"; [self attemptToUnparseDateWithTimeIntervalSinceReferenceDate:timeIntervalSinceReferenceDate timeZoneName:tzName expectDateString:expectedDateString includeTime:true]; } - (void) testParsingDateWithTimeZoneSeparator { _iso8601DateFormatter.timeZoneSeparator = SNOWMAN; static NSString *const dateString = @"2007-W01-01T13:24:56-07☃30"; static NSTimeInterval const expectedTimeIntervalSinceReferenceDate = 189377696.0; static NSTimeInterval const expectedHoursFromGMT = -7.5; [self attemptToParseString:dateString expectTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate expectTimeZoneWithHoursFromGMT:expectedHoursFromGMT]; } - (void) testUnparsingDateWithTimeZoneSeparator { _iso8601DateFormatter.timeZoneSeparator = ':'; NSTimeInterval timeIntervalSinceReferenceDate = 189379496.0; NSString *expectedDateString = @"2007-W01-01T13:24:56-08:00"; NSString *tzName = @"America/Los_Angeles"; [self attemptToUnparseDateWithTimeIntervalSinceReferenceDate:timeIntervalSinceReferenceDate timeZoneName:tzName expectDateString:expectedDateString includeTime:true]; } - (void) testParsingDateWithIncompleteTime { NSString *string; NSTimeInterval expectedTimeIntervalSinceReferenceDate; NSDate *date; NSDate *expectedDate; string = @"2007-W01-01T13:24:56Z"; expectedTimeIntervalSinceReferenceDate = 189350696.0; expectedDate = [NSDate dateWithTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate]; date = [_iso8601DateFormatter dateFromString:string]; XCTAssertEqualObjects(date, expectedDate, @"Parsing string %@ (expected %f); got date %@ (%f)", string, expectedTimeIntervalSinceReferenceDate, date, date.timeIntervalSinceReferenceDate); string = @"2007-W01-01T13:24Z"; expectedTimeIntervalSinceReferenceDate = 189350640.0; expectedDate = [NSDate dateWithTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate]; date = [_iso8601DateFormatter dateFromString:string]; XCTAssertEqualObjects(date, expectedDate, @"Parsing string %@ (expected %f); got date %@ (%f)", string, expectedTimeIntervalSinceReferenceDate, date, date.timeIntervalSinceReferenceDate); string = @"2007-W01-01T13Z"; expectedTimeIntervalSinceReferenceDate = 189349200.0; expectedDate = [NSDate dateWithTimeIntervalSinceReferenceDate:expectedTimeIntervalSinceReferenceDate]; date = [_iso8601DateFormatter dateFromString:string]; XCTAssertEqualObjects(date, expectedDate, @"Parsing string %@ (expected %f); got date %@ (%f)", string, expectedTimeIntervalSinceReferenceDate, date, date.timeIntervalSinceReferenceDate); } - (void) testUnparsingDateWithoutTime { _iso8601DateFormatter.format = ISO8601DateFormatWeek; _iso8601DateFormatter.includeTime = false; _iso8601DateFormatter.defaultTimeZone = [NSTimeZone timeZoneWithName:@"UTC"]; NSString *expectedString = @"2007-W01-01"; NSTimeInterval timeIntervalSinceReferenceDate = 189302400.0; NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:timeIntervalSinceReferenceDate]; NSString *string = [_iso8601DateFormatter stringFromDate:date]; XCTAssertEqualObjects(string, expectedString, @"Generated wrong week date string for %@ (%f)", date, timeIntervalSinceReferenceDate); } //: As of 10.10.4, NSDateFormatter with format @"YYYY-'W'ww-FF" generates 2016-W01-05 for this date. - (void) testUnparsingDateWithoutTimeAtEndOf2015 { _iso8601DateFormatter.format = ISO8601DateFormatWeek; _iso8601DateFormatter.includeTime = false; _iso8601DateFormatter.defaultTimeZone = [NSTimeZone timeZoneWithName:@"UTC"]; NSString *expectedString = @"2015-W53-04"; NSTimeInterval timeIntervalSinceReferenceDate = 473241600.000000; NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:timeIntervalSinceReferenceDate]; NSString *string = [_iso8601DateFormatter stringFromDate:date]; XCTAssertEqualObjects(string, expectedString, @"Generated wrong week date string for %@ (%f)", date, timeIntervalSinceReferenceDate); } - (void) testUnparsingDateInDaylightSavingTime { _iso8601DateFormatter.defaultTimeZone = [NSTimeZone timeZoneWithName:@"Europe/Prague"]; _iso8601DateFormatter.includeTime = YES; _iso8601DateFormatter.format = ISO8601DateFormatWeek; NSDate *date; NSString *string; NSString *expectedString; date = [NSDate dateWithTimeIntervalSinceReferenceDate:365464800.0]; string = [_iso8601DateFormatter stringFromDate:date]; expectedString = @"2012-W31-03T00:00:00+0200"; XCTAssertEqualObjects(string, expectedString, @"Got wrong string for first date in DST in Prague #1 (check whether DST is included in TZ offset)"); date = [NSDate dateWithTimeIntervalSinceReferenceDate:373417200.0]; string = [_iso8601DateFormatter stringFromDate:date]; expectedString = @"2012-W44-04T00:00:00+0100"; XCTAssertEqualObjects(string, expectedString, @"Got wrong string for second date in DST in Prague #1 (check whether DST is included in TZ offset)"); } - (void) testUnparsingDateWithinBritishSummerTimeAsUTC { _iso8601DateFormatter.includeTime = YES; _iso8601DateFormatter.format = ISO8601DateFormatWeek; NSDate *date; NSString *expectedString; NSString *string; NSTimeZone *UTCTimeZone = [NSTimeZone timeZoneWithName:@"UTC"]; date = [NSDate dateWithTimeIntervalSinceReferenceDate:354987473.0]; expectedString = @"2012-W13-07T15:37:53Z"; string = [_iso8601DateFormatter stringFromDate:date timeZone:UTCTimeZone]; XCTAssertEqualObjects(string, expectedString, @"Got wrong string for April date in UTC (check whether DST is included in TZ offset)"); _iso8601DateFormatter.defaultTimeZone = UTCTimeZone; string = [_iso8601DateFormatter stringFromDate:date]; XCTAssertEqualObjects(string, expectedString, @"Got wrong string for April date in UTC-as-default (check whether DST is included in TZ offset)"); //Date https://github.com/boredzo/iso-8601-date-formatter/issues/3 was filed. date = [NSDate dateWithTimeIntervalSinceReferenceDate:370245466.0]; expectedString = @"2012-W39-02T05:57:46Z"; string = [_iso8601DateFormatter stringFromDate:date]; XCTAssertEqualObjects(string, expectedString, @"Got wrong string for September date in UTC-as-default (check whether DST is included in TZ offset)"); } @end ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTests/ISO8601Testing.h ================================================ // // ISO8601Testing.h // ISO8601ForCocoa // // Created by Peter Hosey on 2015-09-06. // Copyright © 2015 Peter Hosey. All rights reserved. // #import //#import #define ISO8601AssertEqualRanges(range1, range2, ...) \ do { \ XCTAssertEqual((range1).location, (range2).location, __VA_ARGS__); \ XCTAssertEqual((range1).length, (range2).length, __VA_ARGS__); \ } while(0) ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTests/ISO8601Testing.m ================================================ // // ISO8601Testing.m // ISO8601ForCocoa // // Created by Peter Hosey on 2015-09-06. // Copyright © 2015 Peter Hosey. All rights reserved. // #import "ISO8601Testing.h" //Nothing here at this time. ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTests/MBMockLocale.h ================================================ // // MBMockLocale.h // ISO8601ForCocoa // // Created by Matthias Bauch on 8/29/13. // Copyright (c) 2013 Peter Hosey. All rights reserved. // #import @interface MBMockLocale : NSObject @end ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTests/MBMockLocale.m ================================================ // // MBMockLocale.m // ISO8601ForCocoa // // Created by Matthias Bauch on 8/29/13. // Copyright (c) 2013 Peter Hosey. All rights reserved. // #import "MBMockLocale.h" @implementation MBMockLocale { NSLocale *locale; } - (id)init { self = [super init]; locale = [[NSLocale alloc] initWithLocaleIdentifier:@"de_DE"]; return self; } - (id)copyWithZone:(NSZone *)zone { return [[[self class] allocWithZone:zone] init]; } - (NSString *)localeIdentifier { return [locale localeIdentifier]; } - (id)objectForKey:(NSString *)key { id object = [locale objectForKey:key]; return object; } - (NSDictionary *)_prefs { NSMutableDictionary *prefs = [NSMutableDictionary dictionaryWithDictionary:[locale performSelector:@selector(_prefs)]]; [prefs setObject:@YES forKey:@"AppleICUForce12HourTime"]; return prefs; } @end ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTests/NSLocale+UnitTestSwizzling.h ================================================ // // NSLocale+UnitTestSwizzling.h // ISO8601ForCocoa // // Created by Matthias Bauch on 8/29/13. // Copyright (c) 2013 Peter Hosey. All rights reserved. // #import @interface NSLocale (TestSwizzling) void SwizzleClassMethod(Class c, SEL orig, SEL new); + (NSLocale *)mockCurrentLocale; @end ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTests/NSLocale+UnitTestSwizzling.m ================================================ // // NSLocale+UnitTestSwizzling.m // ISO8601ForCocoa // // Created by Matthias Bauch on 8/29/13. // Copyright (c) 2013 Peter Hosey. All rights reserved. // #import "NSLocale+UnitTestSwizzling.h" #import "MBMockLocale.h" #import #import @implementation NSLocale (TestSwizzling) void SwizzleClassMethod(Class c, SEL orig, SEL new) { Method origMethod = class_getClassMethod(c, orig); Method newMethod = class_getClassMethod(c, new); c = object_getClass((id)c); if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); else method_exchangeImplementations(origMethod, newMethod); } + (NSLocale *)mockCurrentLocale { return (NSLocale *)[[MBMockLocale alloc] init]; } @end ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTests/PRHNamedCharacter.h ================================================ typedef NS_ENUM(unichar, PRHNamedCharacter) { SNOWMAN = 0x2603 }; ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTests/en.lproj/InfoPlist.strings ================================================ /* Localized versions of Info.plist keys */ ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTouch/ISO8601ForCocoaTouch-Prefix.pch ================================================ // // Prefix header for all source files of the 'ISO8601ForCocoaTouch' target in the 'ISO8601ForCocoaTouch' project // #ifdef __OBJC__ # define NS_ENABLE_CALENDAR_NEW_API 1 # import #endif ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTouchTests/ISO8601ForCocoaTouchTests-Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier org.boredzo.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTouchTests/ISO8601MemoryWarningTests.h ================================================ // // ISO8601MemoryWarningTests.h // ISO8601ForCocoa // // Created by Peter Hosey on 2013-10-02. // Copyright (c) 2013 Peter Hosey. All rights reserved. // #import @interface ISO8601MemoryWarningTests : XCTestCase - (void) testMemoryWarning; @end ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTouchTests/ISO8601MemoryWarningTests.m ================================================ // // ISO8601MemoryWarningTests.m // ISO8601ForCocoa // // Created by Peter Hosey on 2013-10-02. // Copyright (c) 2013 Peter Hosey. All rights reserved. // #import "ISO8601MemoryWarningTests.h" #import "ISO8601DateFormatter.h" @interface ISO8601DateFormatter (ISO8601MemoryWarningTesting) + (void) purgeGlobalCaches; @end #import @implementation ISO8601MemoryWarningTests { ISO8601DateFormatter *_iso8601DateFormatter; } - (void) setUp { [super setUp]; _iso8601DateFormatter = [[ISO8601DateFormatter alloc] init]; //Just in case this isn't the first test that this process has run… [ISO8601DateFormatter purgeGlobalCaches]; } - (void) tearDown { _iso8601DateFormatter = nil; [super tearDown]; } - (void) testMemoryWarning { //Now parse a bunch of dates to try to warm the caches. [_iso8601DateFormatter dateFromString:@"2013-09-18T07:34:21-1200"]; [_iso8601DateFormatter dateFromString:@"2013-09-18T07:34:21-0800"]; [_iso8601DateFormatter dateFromString:@"2013-09-18T07:34:21-0130"]; [_iso8601DateFormatter dateFromString:@"2013-09-18T07:34:21-0000"]; [_iso8601DateFormatter dateFromString:@"2013-09-18T07:34:21+0000"]; [_iso8601DateFormatter dateFromString:@"2013-09-18T07:34:21+0130"]; [_iso8601DateFormatter dateFromString:@"2013-09-18T07:34:21+0800"]; [_iso8601DateFormatter dateFromString:@"2013-09-18T07:34:21+1200"]; } @end ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/ISO8601ForCocoa/ISO8601ForCocoaTouchTests/en.lproj/InfoPlist.strings ================================================ /* Localized versions of Info.plist keys */ ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/LICENSE.txt ================================================ Copyright © 2006–2013 Peter Hosey All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Peter Hosey nor the names of his contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/Makefile ================================================ CLANG=/usr/bin/clang CC=$(CLANG) CFLAGS+=-std=c99 -g -Werror -Wmissing-field-initializers -Wreturn-type -Wmissing-braces -Wparentheses -Wswitch -Wunused-function -Wunused-label -Wunused-variable -Wunused-value -Wshadow -Wsign-compare -Wnewline-eof -Wshorten-64-to-32 -Wundeclared-selector -Wmissing-prototypes -Wformat -Wunknown-pragmas LDFLAGS+=-framework Foundation all: testparser unparse-weekdate unparse-ordinaldate unparse-date test: all parser-test unparser-test analysis: ISO8601DateFormatter-analysis.plist parser-test: testparser testparser.sh ./testparser.sh unparser-test: testunparser.sh unparse-weekdate unparse-ordinaldate unparse-date ./testunparser.sh > testunparser.out diff -qs test_files/testunparser-expected.out testunparser.out .PHONY: all test analysis parser-test unparser-test testparser: testparser.o ISO8601DateFormatter.o testparser.sh: testparser.sh.in python testparser.sh.py unparse-weekdate: unparse-weekdate.o ISO8601DateFormatter.o ISO8601DateFormatter.o unparse-ordinaldate: unparse-ordinaldate.o ISO8601DateFormatter.o ISO8601DateFormatter.o unparse-date: unparse-date.o ISO8601DateFormatter.o ISO8601DateFormatter.o testunparsewithtime: testunparsewithtime.o ISO8601DateFormatter.o ISO8601DateFormatter-analysis.plist: ISO8601DateFormatter.m $(CLANG) $^ --analyze -o /dev/null timetrial: timetrial.o ISO8601DateFormatter.o ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/README.md ================================================ # ISO 8601: The only date format worth using [![Image: Status of most recent build and test attempt.](https://travis-ci.org/boredzo/iso-8601-date-formatter.png?branch=master)](https://travis-ci.org/boredzo/iso-8601-date-formatter) [![Image: Test code coverage percentage.](https://coveralls.io/repos/boredzo/iso-8601-date-formatter/badge.png?branch=master)](https://coveralls.io/r/boredzo/iso-8601-date-formatter?branch=master) Obligatory relevant [xkcd](http://xkcd.com/): [![Seriously now. “ISO 8601 was published on 06/05/88 and most recently amended on 12/01/04.”](http://imgs.xkcd.com/comics/iso_8601.png)](http://xkcd.com/1179/) ## How to use this code in your program Add the source files to your project. ### Parsing Create an ISO 8601 date formatter, then call `[formatter dateFromString:myString]`. The method will return either an NSDate or `nil`. There are a total of six parser methods. The one that contains the actual parser is `-[ISO8601DateFormatter dateComponentsFromString:timeZone:range:]`. The other five are based on this one. The “`outTimeZone`” parameter, when not set to `NULL`, is a pointer to an `NSTimeZone *`variable. If the string specified a time zone, you'll receive the time zone object in that variable. If the string didn't specify a time zone, you'll receive `nil`. The “`outRange`” parameter, when not set to `NULL`, is a pointer to `NSRange` storage. You will receive the range of the parsed substring in that storage. ### Unparsing Create an ISO 8601 date formatter, then call `[formatter stringFromDate:myDate]`. The method will return a string. The formatter has several properties that control its behavior: * You can set the format of the resulting strings. By default, the formatter will generate calendar-date strings; your other options are week dates and ordinal dates. * You can set a default time zone; by default, it will use `[NSTimeZone defaultTimeZone]`. * You can enable a strict mode, wherein the formatter enforces sanity checks on the string. By default, the parser will afford you quite a bit of leeway. * You can set whether to include the time in the string, and if so, what hour-minute separator to use (default `':'`). ## How to test that this code works UPDATE from the year 2013: Conversion from the old make-based test monsters to modern OCUnit-based tests is underway. Contributions of new and old test cases will be greatly appreciated. 'make test' will perform all tests. If you want to perform only *some* tests: ### Parsing Type 'make parser-test'. make will build the test program (testparser), then invoke testparser.sh.py to generate testparser.sh. Then make will invoke testparser.sh, which will invoke the test program with various dates. If you don't want to use my tests, 'make testparser' will create the test program without running it. You can then invoke testparser yourself with any date you want to. If it doesn't give you the result you expected, contact me, making sure to provide me with both the input and the output. ### Unparsing Type 'make unparser-test'. make will build the test programs, then invoke testunparser.sh. This shell script invokes each test program for -01-01 of every year from 1991 to 2010, writing the output to a file, and then runs diff -qs between that file (testunparser.out) and a file (testunparser-expected.out) containing known correct output. diff should report that the files are identical. Three test programs are included: unparse-date, unparse-weekdate, and unparse-ordinal date. If you don't want to use my tests, you can make these test programs separately. Each takes a date specified by ISO 8601 (parsed with my own ISO 8601 parser), and outputs a string that should represent the same date. ## Notes ### Version history This version is 0.7. Changes from 0.6: - Cocoa Touch is now officially supported. 4bc0a08 5d95233 - Added an Xcode project with static library targets. c847ddb 4bc0a08 - `stringFromObjectValue:` now logs to the Console when you hand it a value that isn't an NSDate. Check your Console output after upgrading—you might have had a bug all this time without knowing! 4e05978 - Added proper documentation in the header, compatible with [appledoc](http://gentlebytes.com/appledoc/). f17713f - Fixed nonsense date components/dates being returned when the input is not a valid date string. 288f757 93bb9df 0cb6442 - Fixed a bug in unparsing where the time zone was wrong (#3). 0e355ee 8f8a2c3 (Thanks, Carl Lindberg) - Fixed a DST bug in unparsing where the time zone offset was computed in general rather than for the date being unparsed (#6). 5665132 (Thanks, Zachary West) 9e835c8 0d36057 - Fixed AM/PM (or local equivalent) appearing in some locales on iOS devices (#15). 4bc0a08 3f697b5 249b3df (Thanks, Matthias Bauch) - Fixed another NSDateFormatter-rewriting-formats-to-12-hour-in-some-locales bug. 7c9907f (Thanks, Carl Lindberg) - (iOS) The class now purges its time zone cache automatically in response to a memory warning. You don't need to do that yourself, anymore, so the method to purge the caches is no longer public. 138e186 3224b32 a9b6973 3f3c3b8 - Added support for strings that specify a fraction of a second. 1d3194b 0b0b1ea (Thanks, Luke Redpath) - Added support for non-ASCII time separator characters. 47d5035 - Added support for a time zone separator. 8198f1b 3bd0c07 17c15ed (Thanks to Daniel Tull for the suggestion.) - Fixed the parser's response to being passed `nil`. 3c12abc 4980ee6 - Fixed (I think) #5: dates being formatted with DST applied when they shouldn't. 7368fe8 - Fixed `stringFromObjectValue:` to behave as NSFormatter's documentation says it should. 3846f80 9754438 - Added real unit tests based on OCUnit. c847ddb aa1c2cb daf3cc9 9029991 d92aeb6 b412326 (Thanks, Luke Redpath) 45af6bd cfedd75 af0b93c 6a7fd88 9e835c8 9e835c8 0d36057 7368fe8 4bc0a08 3f697b5 8f8a2c3 51c1130 e888681 13a872d f49193c 10ed166 d5fdf51 4980ee6 3846f80 288f757 93bb9df daa45fb 2d61bd0 9f35c4a 8f95099 d62777a 138e186 2a63718 - Fixed range computation for strings where the date portion ends with a 'Z'. 8f95099 efa095e 808e8c4 - Fixed some formats with missing hyphens being wrongly accepted when strict mode is on. 9f35c4a c4e0f15 - Fixed week date strings not having a 'T' between date and time. 7b6fd9f 6a1b66b - Fixed week date strings having wrong time zones. 9f6af7c - Strings that specify intervals (as specified by ISO 8601) are now explicitly rejected, at least for now (#20). 6d539db 51c1130 bf6a2db 6aef760 (Thanks, Blake Watters) - `ISO8601DefaultTimeSeparatorCharacter` is now declared as `const`. I hope none of you were relying on changing that. db9877c - Upgraded this README to Markdown. 103f666 fbd34b2 ebbf65a c0b9609 - Added the above xkcd comic. fbd34b2 63ba50a da3ed65 - Some light modernization (#25, #28). cdec3e9 8df32fd bb7c5c9 Changes in 0.6 from 0.5: * When not set to strict parsing, allow a space before the time-zone specification, for greater compatibility with NSDate output (`description`) and input (`dateWithString:`). 27603efc8a77 * Bug fix: We no longer try to format the formatter. 83415de9f527 * Bug fix: Hours are now zero-padded correctly ([#4](https://bitbucket.org/boredzo/iso-8601-parser-unparser/issue/4/time-zones-are-emitted-without-leading)). a5608e189ebe af0c6b397428 * Fixed many various compiler warnings. Some fixes contributed by Sparks. 8be3d6f7c6f2 78ae31de2170 68dc351e9fdb e7ea87db8621 873f499ae6db * Now 75 times faster. 6a023812bd2b 05dc35d6b505 3b2225e0ce8c d59720ad015a 10f526956963 297b8dae4095 796be11aa596 cadf0f0c8199 61d2959c6921 * iOS users can now tell the ISO 8601 date formatter class to drop its caches (which you should do when you receive a memory warning). 2bb1725914b1 * Added a couple of command-line options to the calendar-format-unparser test tool. c644aadb2b14 * The parser test tool now displays parsed dates in GMT rather than the local time zone. 788c1455ecb1 * Added a test tool to test unparsing with the time included. a89a9a8b3d61 * You can now “make analysis” to run the Clang Static Analyzer on the date formatter. b3dd33841f42 * The test tools are now built using Clang. 0723d3aa6596 Changes in 0.5 from 0.4: * Rewrote as an NSFormatter subclass using NSCalendar. * Making it a formatter makes it much easier to use with Bindings. * Using NSCalendar means we're no longer using NSCalendarDate, which Apple has said they will deprecate at some point. * Fixed a bug in week date generation: One subtraction could give a negative result, which was a problem because my implementation of the algorithm used unsigned integers. I've changed it to use signed integers, so the result truly is negative now. I also added a test case for this. Changes in 0.4 from 0.3: * Added the ability to use a time separator other than ':'. Changes in 0.3 from 0.2: * Colin Barrett noticed that I used `%m` instead of `%M` when creating the time strings. Oops. * Colin also noticed that I had the `?:` in `ISO8601DateStringWithTime:` the wrong way around. Oops again. Changes in 0.2 from 0.1: * The unparser is new. The has been munged to allow both components together, * The parser has not changed. ## Implementation details ### Parsing Whitespace before a date, and anything after a date, is ignored. Thus, " T23 and all's well" is a valid date for the purpose of this method. (Yes, T23 is a valid ISO 8601 date. It means 23:00:00, or 11 PM.) All of the frills of ISO 8601 are supported, except for extended dates (years longer than 4 digits). Specifically, you can use week-based dates (2006-W2 for the second week of 2006), ordinal dates (2006-365 for December 31), decimal minutes (11:30.5 == 11:30:30), and decimal seconds (11:30:10.5). All methods of specifying a time zone are supported. ISO 8601 leaves quite a bit up to the parties exchanging dates. I hope I've chosen reasonable defaults. For example (note that I'm writing this on 2006-02-24): * If the month or month and date are missing, 1 is assumed. "2006" == "2006-01-01". * If the year or year and month are missing, the current ones are assumed. "--02-01" == "2006-02-01". "---28" == "2006-02-28". * In the case of week-based dates, with the day missing, this implementation returns the first day of that week: 2006-W1 is 2006-01-01, 2006-W2 is 2006-01-08, etc. * For any date without a time, midnight on that date is used. * ISO 8601 permits the choice of either T0 or T24 for midnight. This implementation uses T0. T24 will get you T0 on the following day. * If no time-zone is specified, local time (as returned by [NSTimeZone localTimeZone]) is used. When a date is parsed that has a year but no century, this implementation adds the current century. The implementation is tolerant of out-of-range numbers. For example, "2005-13-40T24:62:89" == 1:02 AM on 2006-02-10. Notice that the month (13 > 12), date (40 > 31), hour (24 > 23), minute (62 > 59), and second (89 > 59) are all out-of-range. As mentioned above, there is a "strict" mode that enforces sanity checks. In particular, the date must be the entire contents of the string, and numbers are range-checked. If you have any suggestions on how to make this mode more strict, please file an enhancement request in the Issues section. ### Unparsing I use [Rick McCarty's algorithm for converting calendar dates to week dates](http://lachy.id.au/dev/script/examples/datetime/ISOwdALG.txt), slightly tweaked. ## Bugs ### Parsing * This method won't extract a date from just anywhere in a string, only immediately after the start of the string (or any leading whitespace). There are two solutions: either require you to invoke the parser on a string that is only an ISO 8601 date, with nothing before or after (bad for parsing purposes), or make the parser able to find an ISO 8601 date as a substring. I won't do the first one, and barring a patch, I probably won't do the second one either. * Date ranges (also specified by ISO 8601) are not supported; this method will only return one date. To handle ranges would require at least one more method. * There is no method to analyze a date string and tell you what was found in it (year, month, week, day, ordinal day, etc.). Feel free to submit a patch. ## Copyright This code is copyright 2006–2013 Peter Hosey. It is under the BSD license; see LICENSE.txt for the full text of the license. ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/test_files/2005-2006.txt ================================================ December 2005 M Tu W Th F S S 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 January 2006 M Tu W Th F S S 1 <- NOT W01 2 3 4 5 6 7 8 <- W01 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/test_files/2005.txt ================================================ 2005 January CW Mo Tu We Th Fr Sa Su 53 1 2 01 3 4 5 6 7 8 9 02 10 11 12 13 14 15 16 03 17 18 19 20 21 22 23 04 24 25 26 27 28 29 30 05 31 February CW Mo Tu We Th Fr Sa Su 05 1 2 3 4 5 6 06 7 8 9 10 11 12 13 07 14 15 16 17 18 19 20 08 21 22 23 24 25 26 27 09 28 March CW Mo Tu We Th Fr Sa Su 09 1 2 3 4 5 6 10 7 8 9 10 11 12 13 11 14 15 16 17 18 19 20 12 21 22 23 24 25 26 27 13 28 29 30 31 April CW Mo Tu We Th Fr Sa Su 13 1 2 3 14 4 5 6 7 8 9 10 15 11 12 13 14 15 16 17 16 18 19 20 21 22 23 24 17 25 26 27 28 29 30 May CW Mo Tu We Th Fr Sa Su 17 1 18 2 3 4 5 6 7 8 19 9 10 11 12 13 14 15 20 16 17 18 19 20 21 22 21 23 24 25 26 27 28 29 22 30 31 June CW Mo Tu We Th Fr Sa Su 22 1 2 3 4 5 23 6 7 8 9 10 11 12 24 13 14 15 16 17 18 19 25 20 21 22 23 24 25 26 26 27 28 29 30 July CW Mo Tu We Th Fr Sa Su 26 1 2 3 27 4 5 6 7 8 9 10 28 11 12 13 14 15 16 17 29 18 19 20 21 22 23 24 30 25 26 27 28 29 30 31 August CW Mo Tu We Th Fr Sa Su 31 1 2 3 4 5 6 7 32 8 9 10 11 12 13 14 33 15 16 17 18 19 20 21 34 22 23 24 25 26 27 28 35 29 30 31 September CW Mo Tu We Th Fr Sa Su 35 1 2 3 4 36 5 6 7 8 9 10 11 37 12 13 14 15 16 17 18 38 19 20 21 22 23 24 25 39 26 27 28 29 30 October CW Mo Tu We Th Fr Sa Su 39 1 2 40 3 4 5 6 7 8 9 41 10 11 12 13 14 15 16 42 17 18 19 20 21 22 23 43 24 25 26 27 28 29 30 44 31 November CW Mo Tu We Th Fr Sa Su 44 1 2 3 4 5 6 45 7 8 9 10 11 12 13 46 14 15 16 17 18 19 20 47 21 22 23 24 25 26 27 48 28 29 30 December CW Mo Tu We Th Fr Sa Su 48 1 2 3 4 49 5 6 7 8 9 10 11 50 12 13 14 15 16 17 18 51 19 20 21 22 23 24 25 52 26 27 28 29 30 31 ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/test_files/2006.txt ================================================ ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/test_files/2009-2010.txt ================================================ December 2009 M Tu W Th F S S 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 January 2010 M Tu W Th F S S 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/test_files/januaries.txt ================================================ January 1991 January 2001 Mo Tu We Th Fr Sa Su CW Mo Tu We Th Fr Sa Su CW 1 2 3 4 5 6 53/1 #W01-02 1 2 3 4 5 6 7 01 #W01-01 7 8 9 10 11 12 13 02 8 9 10 11 12 13 14 02 14 15 16 17 18 19 20 03 15 16 17 18 19 20 21 03 21 22 23 24 25 26 27 04 22 23 24 25 26 27 28 04 28 29 30 31 05 29 30 31 05 January 1992 January 2002 Mo Tu We Th Fr Sa Su CW Mo Tu We Th Fr Sa Su CW 1 2 3 4 5 53/1 #W01-03 1 2 3 4 5 6 53/1 #W01-02 6 7 8 9 10 11 12 02 7 8 9 10 11 12 13 02 13 14 15 16 17 18 19 03 14 15 16 17 18 19 20 03 20 21 22 23 24 25 26 04 21 22 23 24 25 26 27 04 27 28 29 30 31 05 28 29 30 31 05 January 1993 January 2003 Mo Tu We Th Fr Sa Su CW Mo Tu We Th Fr Sa Su CW 1 2 3 53/0 #W53-05 1 2 3 4 5 53/1 #W01-03 4 5 6 7 8 9 10 01 6 7 8 9 10 11 12 02 11 12 13 14 15 16 17 02 13 14 15 16 17 18 19 03 18 19 20 21 22 23 24 03 20 21 22 23 24 25 26 04 25 26 27 28 29 30 31 04 27 28 29 30 31 05 January 1994 January 2004 Mo Tu We Th Fr Sa Su CW Mo Tu We Th Fr Sa Su CW 1 2 52/0 #W52-06 1 2 3 4 53/1 #W01-04 3 4 5 6 7 8 9 01 5 6 7 8 9 10 11 02 10 11 12 13 14 15 16 02 12 13 14 15 16 17 18 03 17 18 19 20 21 22 23 03 19 20 21 22 23 24 25 04 24 25 26 27 28 29 30 04 26 27 28 29 30 31 05 31 05 January 1995 January 2005 Mo Tu We Th Fr Sa Su CW Mo Tu We Th Fr Sa Su CW 1 52/0 #W52-07 1 2 53/0 #W53-06 2 3 4 5 6 7 8 01 3 4 5 6 7 8 9 01 9 10 11 12 13 14 15 02 10 11 12 13 14 15 16 02 16 17 18 19 20 21 22 03 17 18 19 20 21 22 23 03 23 24 25 26 27 28 29 04 24 25 26 27 28 29 30 04 30 31 05 31 05 January 1996 January 2006 Mo Tu We Th Fr Sa Su CW Mo Tu We Th Fr Sa Su CW 1 2 3 4 5 6 7 01 #W01-01 1 52/0 #W52-07 8 9 10 11 12 13 14 02 2 3 4 5 6 7 8 01 15 16 17 18 19 20 21 03 9 10 11 12 13 14 15 02 22 23 24 25 26 27 28 04 16 17 18 19 20 21 22 03 29 30 31 05 23 24 25 26 27 28 29 04 30 31 05 January 1997 January 2007 Mo Tu We Th Fr Sa Su CW Mo Tu We Th Fr Sa Su CW 1 2 3 4 5 53/1 #W01-03 1 2 3 4 5 6 7 01 #W01-01 6 7 8 9 10 11 12 02 8 9 10 11 12 13 14 02 13 14 15 16 17 18 19 03 15 16 17 18 19 20 21 03 20 21 22 23 24 25 26 04 22 23 24 25 26 27 28 04 27 28 29 30 31 05 29 30 31 05 January 1998 January 2008 Mo Tu We Th Fr Sa Su CW Mo Tu We Th Fr Sa Su CW 1 2 3 4 53/1 #W01-04 1 2 3 4 5 6 53/1 #W01-02 5 6 7 8 9 10 11 02 7 8 9 10 11 12 13 02 12 13 14 15 16 17 18 03 14 15 16 17 18 19 20 03 19 20 21 22 23 24 25 04 21 22 23 24 25 26 27 04 26 27 28 29 30 31 05 28 29 30 31 05 January 1999 January 2009 Mo Tu We Th Fr Sa Su CW Mo Tu We Th Fr Sa Su CW 1 2 3 53/0 #W53-05 1 2 3 4 53/1 #W01-04 4 5 6 7 8 9 10 01 5 6 7 8 9 10 11 02 11 12 13 14 15 16 17 02 12 13 14 15 16 17 18 03 18 19 20 21 22 23 24 03 19 20 21 22 23 24 25 04 25 26 27 28 29 30 31 04 26 27 28 29 30 31 05 January 2000 January 2010 Mo Tu We Th Fr Sa Su CW Mo Tu We Th Fr Sa Su CW 1 2 52/0 #W52-06 1 2 3 53/0 #W53-05 3 4 5 6 7 8 9 01 4 5 6 7 8 9 10 01 10 11 12 13 14 15 16 02 11 12 13 14 15 16 17 02 17 18 19 20 21 22 23 03 18 19 20 21 22 23 24 03 24 25 26 27 28 29 30 04 25 26 27 28 29 30 31 04 31 05 ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/test_files/januaries3.txt ================================================ January 1991 Mo Tu We Th Fr Sa Su CW 1 2 3 4 5 6 53/1 7 8 9 10 11 12 13 02 14 15 16 17 18 19 20 03 21 22 23 24 25 26 27 04 28 29 30 31 05 January 1992 Mo Tu We Th Fr Sa Su CW 1 2 3 4 5 53/1 6 7 8 9 10 11 12 02 13 14 15 16 17 18 19 03 20 21 22 23 24 25 26 04 27 28 29 30 31 05 January 1993 Mo Tu We Th Fr Sa Su CW 1 2 3 53/0 4 5 6 7 8 9 10 01 11 12 13 14 15 16 17 02 18 19 20 21 22 23 24 03 25 26 27 28 29 30 31 04 January 1994 Mo Tu We Th Fr Sa Su CW 1 2 52/0 3 4 5 6 7 8 9 01 10 11 12 13 14 15 16 02 17 18 19 20 21 22 23 03 24 25 26 27 28 29 30 04 31 05 January 1995 Mo Tu We Th Fr Sa Su CW 1 52/0 2 3 4 5 6 7 8 01 9 10 11 12 13 14 15 02 16 17 18 19 20 21 22 03 23 24 25 26 27 28 29 04 30 31 05 January 1996 Mo Tu We Th Fr Sa Su CW 1 2 3 4 5 6 7 01 8 9 10 11 12 13 14 02 15 16 17 18 19 20 21 03 22 23 24 25 26 27 28 04 29 30 31 05 January 1997 Mo Tu We Th Fr Sa Su CW 1 2 3 4 5 53/1 6 7 8 9 10 11 12 02 13 14 15 16 17 18 19 03 20 21 22 23 24 25 26 04 27 28 29 30 31 05 January 1998 Mo Tu We Th Fr Sa Su CW 1 2 3 4 53/1 5 6 7 8 9 10 11 02 12 13 14 15 16 17 18 03 19 20 21 22 23 24 25 04 26 27 28 29 30 31 05 January 1999 Mo Tu We Th Fr Sa Su CW 1 2 3 53/0 4 5 6 7 8 9 10 01 11 12 13 14 15 16 17 02 18 19 20 21 22 23 24 03 25 26 27 28 29 30 31 04 January 2000 Mo Tu We Th Fr Sa Su CW 1 2 52/0 3 4 5 6 7 8 9 01 10 11 12 13 14 15 16 02 17 18 19 20 21 22 23 03 24 25 26 27 28 29 30 04 31 05 ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/testparser.m ================================================ #import #import "ISO8601DateFormatter.h" int main(int argc, const char **argv) { NSAutoreleasePool *pool = [NSAutoreleasePool new]; BOOL parseStrictly = NO; if((argc > 1) && (strcmp(argv[1], "--strict") == 0)) { --argc;++argv; parseStrictly = YES; } [NSTimeZone setDefaultTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:+0]]; ISO8601DateFormatter *formatter = [[[ISO8601DateFormatter alloc] init] autorelease]; formatter.parsesStrictly = parseStrictly; while(--argc) { NSString *str = [NSString stringWithUTF8String:*++argv]; NSLog(@"Parsing strictly: %hhi", parseStrictly); NSDate *date = [formatter dateFromString:str]; fputs([[NSString stringWithFormat:@"%@ %C %@\n", str, (unsigned short)0x2192, date] UTF8String], stdout); } [pool release]; return 0; } ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/testparser.sh.in ================================================ #Tests with a date only ./testparser 2006-02-24 \ 2006-12 \ 2006 \ 2006- \ 2006-02- \ 2006-0224 \ 200602-24 \ 20060224 \ 2001-W1-1 \ 2002-W1-1 \ 2003-W1-1 \ 2004-W1-1 \ 2010-W1-1 \ 2000-W1-1 \ 2006-W1-1 \ 2006-W1-2 \ 2006-W02 \ 2006-W2 \ 2006-W02-01 \ 2006-W02-1 \ 2006-W2-01 \ 2006-W2-1 \ 2006-W2-2 \ 2006-W2-8 \ 2006-W3-1 \ 2006-W22 \ 2006-W22-11 \ 06-02-24 \ 06-12 \ 06-02- \ 06-0224 \ 0602-24 \ 060224 \ 06-W22 \ 06-W2 \ 06-W22-11 \ 06-W2-1 \ -6-02-24 \ -6-12 \ -6 \ -6- \ -6-02- \ -6-0224 \ -602-24 \ -6-W22 \ -6-W2 \ -6-W22-11 \ -6-W2-1 \ --0224 \ --02-24 \ --2-24 \ --02-2 \ --02 \ ---24 \ -W2 \ -W2-11 \ -W-3 \ --W-3 \ 2006-001 \ 2006-002 \ 2006-032 \ 2006-055 \ 2006-365 \ 2004-001 \ 2004-366 \ -055 \ --055 \ 2006T #Current year in x century ./testparser 20 \ 1 #x year in current century ./testparser -06 #x year and month in current century ./testparser -06-02 #x year, month, and date in current century ./testparser 06-02-24 #x month and date in current year ./testparser --02-24 #x date in current year and month ./testparser ---24 #Tests with a time only ./testparser T22:63:24-11:21 \ T22:63:24+50:70 \ T22:1:2 \ T22:1Z \ T22: \ T22 \ T2 \ T2:2:2 #Tests with both a date and a time ./testparser 2006-02-24T02:43:24 \ 2006-02-24T22:43:24 \ 2006-02-24T22:63:24 \ 2006-12T12:34 \ 2006T22 #Tests with a date, a time, and a time zone ./testparser 2006-02-24T22:63:24-01:00 \ 2006-02-24T22:63:24Z \ 2006-02-24T22:63:24-1 \ 2006-02-24T22:63:24-01 \ 2006-02-24T22:63:24-01:32 \ 2006-02-24T22:63:24-01:0 \ 2006-02-24T22:63:24-01:00 \ 2006-02-24T22:63:24-01:01 \ 2006-02-24T22:63:24-01:11 \ 2006-02-24T22:63:24-11:21 #Invalid dates ./testparser '' \ T \ 2006-W \ 2006-366 \ 2006-400 \ 2004-367 \ -2006-02-24T02:43:24 \ -2006-02-24T22:43:24 \ -2006-02-24T22:63:24 \ -2006-12T12:34 \ -2006T22 \ -60224 \ --2006-02-24T02:43:24 \ --2006-02-24T22:43:24 \ --2006-02-24T22:63:24 \ --2006-12T12:34 \ --2006T22 \ ---2006-02-24T02:43:24 \ ---2006-02-24T22:43:24 \ ---2006-02-24T22:63:24 \ ---2006-12T12:34 \ ---2006T22 ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/testparser.sh.py ================================================ #!/usr/bin/env python outfile = file('testparser.sh', 'w') outfile.write('#!/bin/sh\n') hash = '#' colon = ':' shell_prompt = '% ' echo_format = "echo '%s'\n" newline = '\n' echo_by_itself = 'echo\n' import re bs_exp = re.compile('(\\\\*)\n') escape_newline_exp = re.compile('\\\\\n') empty = '' import fileinput holding = [] for line in fileinput.input(['testparser.sh.in']): if len(line) <= 1: #Empty line. continue if(len(bs_exp.search(line).group(1)) % 2): holding.append(line[:-1]) continue elif holding: holding.append(line) line = '\n'.join(holding) del holding[:] line = escape_newline_exp.sub(empty, line) is_comment = line.startswith(hash) if is_comment: line_for_display = line[:-1].strip(hash) + colon else: line_for_display = shell_prompt + line[:-1] echo_line = echo_format % (line_for_display,) lines = [newline, echo_line] if is_comment: lines.insert(1, echo_by_itself) else: lines.append(line) outfile.writelines(lines) outfile.close() # Make it executable. import os os.chmod('testparser.sh', 0755) ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/testunparser.sh ================================================ #!/usr/bin/env zsh -f echo './unparse-date 199{1,2,3,4,5,6,7,8,9}-01-01 200{0,1,2,3,4,5,6,7,8,9}-01-01 2010-01-01' ./unparse-date 199{1,2,3,4,5,6,7,8,9}-01-01 200{0,1,2,3,4,5,6,7,8,9}-01-01 2010-01-01 echo echo './unparse-weekdate 199{1,2,3,4,5,6,7,8,9}-01-01 200{0,1,2,3,4,5,6,7,8,9}-01-01 2010-01-01' ./unparse-weekdate 199{1,2,3,4,5,6,7,8,9}-01-01 200{0,1,2,3,4,5,6,7,8,9}-01-01 2010-01-01 echo echo './unparse-ordinaldate 199{1,2,3,4,5,6,7,8,9}-01-01 200{0,1,2,3,4,5,6,7,8,9}-01-01 2010-01-01' ./unparse-ordinaldate 199{1,2,3,4,5,6,7,8,9}-01-01 200{0,1,2,3,4,5,6,7,8,9}-01-01 2010-01-01 ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/testunparsewithtime.m ================================================ #import #import "ISO8601DateFormatter.h" static void testFormatStrings(int hour, int minute); int main(void) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; ISO8601DateFormatter *formatter = [[[ISO8601DateFormatter alloc] init] autorelease]; formatter.includeTime = YES; NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:336614400.0]; NSLog(@"2011-09-01 at 5 PM ET: %@", [formatter stringFromDate:date]); testFormatStrings(11, 6); testFormatStrings(2, 6); testFormatStrings(-2, 6); [pool drain]; return EXIT_SUCCESS; } static void testFormatStrings(int hour, int minute) { NSArray *formatStrings = [NSArray arrayWithObjects: @"%@: %02d:%02d", @"%@: %+02d:%02d", @"%@: %0+2d:%02d", @"%@: %02+d:%02d", @"%@: %+.2d:%02d", nil]; NSLog(@"Testing with NSLog:"); for (NSString *format in formatStrings) { NSLog(format, format, hour, minute); } printf("Testing with printf:\n"); for (NSString *format in formatStrings) { format = [format stringByReplacingOccurrencesOfString:@"%@" withString:@"%s"]; printf([[format stringByAppendingString:@"\n"] UTF8String], [format UTF8String], hour, minute); } } ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/timetrial.m ================================================ #import #import "ISO8601DateFormatter.h" int main(void) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; sleep(1); ISO8601DateFormatter *formatter = [[[ISO8601DateFormatter alloc] init] autorelease]; NSString *inString = @"2011-04-12T13:15:17-0800"; NSUInteger numResults = 0; NSDate *start, *end; enum { numReps = 10000 }; NSLog(@"Timing ISO8601DateFormatter"); start = [NSDate date]; for (NSUInteger i = 10000; i > 0; --i) { NSDate *date = [formatter dateFromString:inString]; NSString *outString = [formatter stringFromDate:date]; if (outString) ++numResults; } end = [NSDate date]; NSLog(@"Time taken: %f seconds", [end timeIntervalSinceDate:start]); NSLog(@"Number of dates and strings computed: %lu each", (unsigned long)numResults); NSLog(@"Time taken per date: %f seconds", [end timeIntervalSinceDate:start] / numReps); [pool drain]; pool = [[NSAutoreleasePool alloc] init]; sleep(1); numResults = 0; NSLog(@"Timing C standard library parsing and unparsing"); struct tm timeInfo; time_t then; char buffer[80] = { 0 }; NSTimeInterval timeZoneOffset = [[NSTimeZone localTimeZone] secondsFromGMT]; start = [NSDate date]; for (NSUInteger i = 10000; i > 0; --i) { strptime([inString cStringUsingEncoding:NSUTF8StringEncoding], "%Y-%m-%dT%H:%M:%S%z", &timeInfo); timeInfo.tm_isdst = -1; then = mktime(&timeInfo); NSDate *date = [NSDate dateWithTimeIntervalSince1970:then + timeZoneOffset]; struct tm *outputTimeInfo; time_t outputTime = [date timeIntervalSince1970] - timeZoneOffset; outputTimeInfo = localtime(&outputTime); strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%S%z", outputTimeInfo); NSString *outString = [NSString stringWithCString:buffer encoding:NSUTF8StringEncoding]; if (outString) ++numResults; } end = [NSDate date]; NSLog(@"Time taken: %f seconds", [end timeIntervalSinceDate:start]); NSLog(@"Number of dates and strings computed: %lu each", (unsigned long)numResults); NSLog(@"Time taken per date: %f seconds", [end timeIntervalSinceDate:start] / numReps); sleep(1); [pool drain]; return EXIT_SUCCESS; } ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/unparse-date.m ================================================ #import "ISO8601DateFormatter.h" int main(int argc, const char **argv) { NSAutoreleasePool *pool = [NSAutoreleasePool new]; ISO8601DateFormatter *formatter = [[[ISO8601DateFormatter alloc] init] autorelease]; formatter.format = ISO8601DateFormatCalendar; BOOL forceUTC = NO; while (argv[1]) { if (strcmp(argv[1], "--include-time") == 0) formatter.includeTime = YES; else if (strcmp(argv[1], "--force-utc") == 0) forceUTC = YES; else break; --argc; ++argv; } while(--argc) { NSString *arg = [NSString stringWithUTF8String:*++argv]; NSTimeZone *timeZone = nil; NSDate *date = [formatter dateFromString:arg timeZone:&timeZone]; if (forceUTC) timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; printf("%s\n", [[NSString stringWithFormat:@"%@:\t%@", arg, [formatter stringFromDate:date timeZone:timeZone]] UTF8String]); } [pool release]; return 0; } ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/unparse-ordinaldate.m ================================================ #import "ISO8601DateFormatter.h" int main(int argc, const char **argv) { NSAutoreleasePool *pool = [NSAutoreleasePool new]; ISO8601DateFormatter *formatter = [[[ISO8601DateFormatter alloc] init] autorelease]; formatter.format = ISO8601DateFormatOrdinal; while(--argc) { NSString *arg = [NSString stringWithUTF8String:*++argv]; NSTimeZone *timeZone = nil; printf("%s\n", [[NSString stringWithFormat:@"%@:\t%@", arg, [formatter stringFromDate:[formatter dateFromString:arg timeZone:&timeZone] timeZone:timeZone]] UTF8String]); } [pool release]; return 0; } ================================================ FILE: Carthage/Checkouts/iso-8601-date-formatter/unparse-weekdate.m ================================================ #import "ISO8601DateFormatter.h" int main(int argc, const char **argv) { NSAutoreleasePool *pool = [NSAutoreleasePool new]; ISO8601DateFormatter *formatter = [[[ISO8601DateFormatter alloc] init] autorelease]; formatter.format = ISO8601DateFormatWeek; while(--argc) { NSString *arg = [NSString stringWithUTF8String:*++argv]; NSTimeZone *timeZone = nil; printf("%s\n", [[NSString stringWithFormat:@"%@:\t%@", arg, [formatter stringFromDate:[formatter dateFromString:arg timeZone:&timeZone] timeZone:timeZone]] UTF8String]); } [pool release]; return 0; } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/.gitignore ================================================ .DS_Store .AppleDouble .LSOverride *.xcodeproj .build/* Packages/* # Icon must end with two \r Icon # Thumbnails ._* # Files that might appear in the root of a volume .DocumentRevisions-V100 .fseventsd .Spotlight-V100 .TemporaryItems .Trashes .VolumeIcon.icns # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk # Xcode build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata *.xccheckout *.moved-aside DerivedData *.hmap *.ipa *.xcuserstate Socket.IO-Test-Server/node_modules/* ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/.travis.yml ================================================ language: objective-c xcode_project: Socket.IO-Client-Swift.xcodeproj # path to your xcodeproj folder xcode_scheme: SocketIO-iOS osx_image: xcode7 before_install: - cd Socket.IO-Test-Server/ - npm install - cd .. install: node Socket.IO-Test-Server/main.js & script: xctool -project Socket.IO-Client-Swift.xcodeproj -scheme SocketIO-Mac build test -parallelize cache: directories: - Socket.IO-Test-Server/node_modules ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014-2015 Erik Little 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. This library makes use of the following third party libraries: Starscream ---------- Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Package.swift ================================================ import PackageDescription let package = Package( name: "SocketIOClientSwift" ) ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/README.md ================================================ [![Build Status](https://travis-ci.org/socketio/socket.io-client-swift.svg?branch=master)](https://travis-ci.org/socketio/socket.io-client-swift) #Socket.IO-Client-Swift Socket.IO-client for iOS/OS X. ##Example ```swift let socket = SocketIOClient(socketURL: NSURL(string: "http://localhost:8080")!, options: [.Log(true), .ForcePolling(true)]) socket.on("connect") {data, ack in print("socket connected") } socket.on("currentAmount") {data, ack in if let cur = data[0] as? Double { socket.emitWithAck("canUpdate", cur)(timeoutAfter: 0) {data in socket.emit("update", ["amount": cur + 2.50]) } ack.with("Got your currentAmount", "dude") } } socket.connect() ``` ##Objective-C Example ```objective-c NSURL* url = [[NSURL alloc] initWithString:@"http://localhost:8080"]; SocketIOClient* socket = [[SocketIOClient alloc] initWithSocketURL:url options:@{@"log": @YES, @"forcePolling": @YES}]; [socket on:@"connect" callback:^(NSArray* data, SocketAckEmitter* ack) { NSLog(@"socket connected"); }]; [socket on:@"currentAmount" callback:^(NSArray* data, SocketAckEmitter* ack) { double cur = [[data objectAtIndex:0] floatValue]; [socket emitWithAck:@"canUpdate" withItems:@[@(cur)]](0, ^(NSArray* data) { [socket emit:@"update" withItems:@[@{@"amount": @(cur + 2.50)}]]; }); [ack with:@[@"Got your currentAmount, ", @"dude"]]; }]; [socket connect]; ``` ##Features - Supports socket.io 1.0+ - Supports binary - Supports Polling and WebSockets - Supports TLS/SSL - Can be used from Objective-C ##Installation Requires Swift 2/Xcode 7 If you need Swift 1.2/Xcode 6.3/4 use v2.4.5 (Pre-Swift 2 support is no longer maintained) If you need Swift 1.1/Xcode 6.2 use v1.5.2. (Pre-Swift 1.2 support is no longer maintained) Manually (iOS 7+) ----------------- 1. Copy the Source folder into your Xcode project. (Make sure you add the files to your target(s)) 2. If you plan on using this from Objective-C, read [this](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html) on exposing Swift code to Objective-C. Swift Package Manager --------------------- Add the project as a dependency to your Package.swift: ```swift import PackageDescription let package = Package( name: "YourSocketIOProject", dependencies: [ .Package(url: "https://github.com/socketio/socket.io-client-swift", majorVersion: 5) ] ) ``` Then import `import SocketIOClientSwift`. Carthage ----------------- Add this line to your `Cartfile`: ``` github "socketio/socket.io-client-swift" ~> 5.3.3 # Or latest version ``` Run `carthage update --platform ios,macosx`. CocoaPods 0.36.0 or later (iOS 8+) ------------------ Create `Podfile` and add `pod 'Socket.IO-Client-Swift'`: ```ruby source 'https://github.com/CocoaPods/Specs.git' platform :ios, '8.0' use_frameworks! pod 'Socket.IO-Client-Swift', '~> 5.3.3' # Or latest version ``` Install pods: ``` $ pod install ``` Import the module: Swift: ```swift import SocketIOClientSwift ``` Objective-C: ```Objective-C #import ``` CocoaSeeds ----------------- Add this line to your `Seedfile`: ``` github "socketio/socket.io-client-swift", "v5.3.3", :files => "Source/*.swift" # Or latest version ``` Run `seed install`. ##API Constructors ----------- `init(var socketURL: NSURL, options: Set = [])` - Creates a new SocketIOClient. options is a Set of SocketIOClientOption. If your socket.io server is secure, you need to specify `https` in your socketURL. `convenience init(socketURL: NSURL, options: NSDictionary?)` - Same as above, but meant for Objective-C. See Options on how convert between SocketIOClientOptions and dictionary keys. Options ------- All options are a case of SocketIOClientOption. To get the Objective-C Option, convert the name to lowerCamelCase. ```swift case ConnectParams([String: AnyObject]) // Dictionary whose contents will be passed with the connection. case Reconnects(Bool) // Whether to reconnect on server lose. Default is `true` case ReconnectAttempts(Int) // How many times to reconnect. Default is `-1` (infinite tries) case ReconnectWait(Int) // Amount of time to wait between reconnects. Default is `10` case ForcePolling(Bool) // `true` forces the client to use xhr-polling. Default is `false` case ForceNew(Bool) // Will a create a new engine for each connect. Useful if you find a bug in the engine related to reconnects case ForceWebsockets(Bool) // `true` forces the client to use WebSockets. Default is `false` case Nsp(String) // The namespace to connect to. Must begin with /. Default is `/` case Cookies([NSHTTPCookie]) // An array of NSHTTPCookies. Passed during the handshake. Default is nil. case Log(Bool) // If `true` socket will log debug messages. Default is false. case Logger(SocketLogger) // Custom logger that conforms to SocketLogger. Will use the default logging otherwise. case SessionDelegate(NSURLSessionDelegate) // Sets an NSURLSessionDelegate for the underlying engine. Useful if you need to handle self-signed certs. Default is nil. case Path(String) // If the server uses a custom path. ex: `"/swift/"`. Default is `""` case ExtraHeaders([String: String]) // Adds custom headers to the initial request. Default is nil. case HandleQueue(dispatch_queue_t) // The dispatch queue that handlers are run on. Default is the main queue. case VoipEnabled(Bool) // Only use this option if you're using the client with VoIP services. Changes the way the WebSocket is created. Default is false case Secure(Bool) // If the connection should use TLS. Default is false. case SelfSigned(Bool) // Sets WebSocket.selfSignedSSL (Don't do this, iOS will yell at you) ``` Methods ------- 1. `on(event: String, callback: NormalCallback) -> NSUUID` - Adds a handler for an event. Items are passed by an array. `ack` can be used to send an ack when one is requested. See example. Returns a unique id for the handler. 2. `once(event: String, callback: NormalCallback) -> NSUUID` - Adds a handler that will only be executed once. Returns a unique id for the handler. 3. `onAny(callback:((event: String, items: AnyObject?)) -> Void)` - Adds a handler for all events. It will be called on any received event. 4. `emit(event: String, _ items: AnyObject...)` - Sends a message. Can send multiple items. 5. `emit(event: String, withItems items: [AnyObject])` - `emit` for Objective-C 6. `emitWithAck(event: String, _ items: AnyObject...) -> (timeoutAfter: UInt64, callback: (NSArray?) -> Void) -> Void` - Sends a message that requests an acknowledgement from the server. Returns a function which you can use to add a handler. See example. Note: The message is not sent until you call the returned function. 7. `emitWithAck(event: String, withItems items: [AnyObject]) -> (UInt64, (NSArray?) -> Void) -> Void` - `emitWithAck` for Objective-C. Note: The message is not sent until you call the returned function. 8. `connect()` - Establishes a connection to the server. A "connect" event is fired upon successful connection. 9. `connect(timeoutAfter timeoutAfter: Int, withTimeoutHandler handler: (() -> Void)?)` - Connect to the server. If it isn't connected after timeoutAfter seconds, the handler is called. 10. `disconnect()` - Closes the socket. Reopening a disconnected socket is not fully tested. 11. `reconnect()` - Causes the client to reconnect to the server. 12. `joinNamespace(namespace: String)` - Causes the client to join namespace. Shouldn't need to be called unless you change namespaces manually. 13. `leaveNamespace()` - Causes the client to leave the nsp and go back to / 14. `off(event: String)` - Removes all event handlers for event. 15. `off(id id: NSUUID)` - Removes the event that corresponds to id. 16. `removeAllHandlers()` - Removes all handlers. Client Events ------ 1. `connect` - Emitted when on a successful connection. 2. `disconnect` - Emitted when the connection is closed. 3. `error` - Emitted on an error. 4. `reconnect` - Emitted when the connection is starting to reconnect. 5. `reconnectAttempt` - Emitted when attempting to reconnect. ##Detailed Example A more detailed example can be found [here](https://github.com/nuclearace/socket.io-client-swift-example) ##License MIT ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Socket.IO-Client-Swift.podspec ================================================ Pod::Spec.new do |s| s.name = "Socket.IO-Client-Swift" s.module_name = "SocketIOClientSwift" s.version = "5.3.3" s.summary = "Socket.IO-client for iOS and OS X" s.description = <<-DESC Socket.IO-client for iOS and OS X. Supports ws/wss/polling connections and binary. For socket.io 1.0+ and Swift. DESC s.homepage = "https://github.com/socketio/socket.io-client-swift" s.license = { :type => 'MIT' } s.author = { "Erik" => "nuclear.ace@gmail.com" } s.ios.deployment_target = '8.0' s.osx.deployment_target = '10.10' s.tvos.deployment_target = '9.0' s.source = { :git => "https://github.com/socketio/socket.io-client-swift.git", :tag => 'v5.3.3' } s.source_files = "Source/**/*.swift" s.requires_arc = true # s.dependency 'Starscream', '~> 0.9' # currently this repo includes Starscream swift files end ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Socket.IO-Test-Server/TestCases.js ================================================ var assert = require("assert") module.exports = { basicTest: { assert: function(inputData) { }, returnData: [] }, testNull: { assert: function(inputData) { assert(!inputData) }, returnData: [null] }, testBinary: { assert: function(inputData) { assert.equal(inputData.toString(), "gakgakgak2") }, returnData: [new Buffer("gakgakgak2", "utf-8")] }, testArray: { assert: function(inputData) { assert.equal(inputData.length, 2) assert.equal(inputData[0], "test1") assert.equal(inputData[1], "test2") }, returnData: [["test3", "test4"]] }, testString: { assert: function(inputData) { assert.equal(inputData, "marco") }, returnData: ["polo"] }, testBool: { assert: function(inputData) { assert(!inputData) }, returnData: [true] }, testInteger: { assert: function(inputData) { assert.equal(inputData, 10) }, returnData: [20] }, testDouble: { assert: function(inputData) { assert.equal(inputData, 1.1) }, returnData: [1.2] }, testJSON: { assert: function(inputData) { assert.equal(inputData.name, "test") assert.equal(inputData.nestedTest.test, "test") assert.equal(inputData.testArray.length, 1) }, returnData: [{testString: "test", testNumber: 15, nestedTest: {test: "test"}, testArray: [1, 1]}] }, testJSONWithBuffer: { assert: function(inputData) { assert.equal(inputData.name, "test") assert.equal(inputData.nestedTest.test, "test") assert.equal(inputData.testArray.length, 1) }, returnData: [{testString: "test", testNumber: 15, nestedTest: {test: "test"}, testArray: [new Buffer("gakgakgak2", "utf-8"), 1]}] },testUnicode: { assert: function(inputData) { assert.equal(inputData, "🚀") }, returnData: ["🚄"] },testMultipleItems: { assert: function(array, object, number, string, bool) { assert.equal(array.length, 2) assert.equal(array[0], "test1") assert.equal(array[1], "test2") assert.equal(number, 15) assert.equal(string, "marco") assert.equal(bool, false) }, returnData: [[1, 2], {test: "bob"}, 25, "polo", false] },testMultipleItemsWithBuffer: { assert: function(array, object, number, string, binary) { assert.equal(array.length, 2) assert.equal(array[0], "test1") assert.equal(array[1], "test2") assert.equal(number, 15) assert.equal(string, "marco") assert.equal(binary.toString(), "gakgakgak2") }, returnData: [[1, 2], {test: "bob"}, 25, "polo", new Buffer("gakgakgak2")] } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Socket.IO-Test-Server/acknowledgementEvents.js ================================================ function socketCallback(testKey, socket, testCase) { return function() { testCase.assert.apply(undefined , arguments) var emitArguments = testCase.returnData; var ack = arguments[arguments.length - 1] ack.apply(socket, emitArguments) } } module.exports.socketCallback = socketCallback ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Socket.IO-Test-Server/emitEvents.js ================================================ function socketCallback(testKey, socket, testCase) { return function() { testCase.assert.apply(undefined , arguments) var emitArguments = addArrays([testKey + "EmitReturn"], testCase.returnData) socket.emit.apply(socket, emitArguments) } } function addArrays(firstArray, secondArray) { var length = secondArray.length var i; for(i = 0; i < length; i++) { firstArray.push(secondArray[i]) } return firstArray; } module.exports.socketCallback = socketCallback ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Socket.IO-Test-Server/main.js ================================================ var app = require('http').createServer() var io = require('socket.io')(app); app.listen(6979) var acknowledgementsEvents = require("./acknowledgementEvents.js") var emitEvents = require("./emitEvents.js") var socketEventRegister = require("./socketEventRegister.js") socketEventRegister.register(io, emitEvents.socketCallback, "Emit") socketEventRegister.register(io, acknowledgementsEvents.socketCallback, "Acknowledgement") var nsp = io.of("/swift") socketEventRegister.register(nsp, emitEvents.socketCallback, "Emit") socketEventRegister.register(nsp, acknowledgementsEvents.socketCallback, "Acknowledgement") ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Socket.IO-Test-Server/package.json ================================================ { "name": "socket.io-client-swift-test-server", "version": "0.0.1", "description": "A simple server to test aginst", "main": "main.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "Lukas Schmidt", "license": "MIT", "dependencies": { "socket.io": "^1.3.6" } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Socket.IO-Test-Server/socketEventRegister.js ================================================ var testCases = require("./TestCases.js") function registerSocketForEvents(ioSocket, socketCallback, testKind) { ioSocket.on('connection', function(socket) { var testCase; for(testKey in testCases) { testCase = testCases[testKey] socket.on((testKey + testKind), socketCallback(testKey, socket, testCase)) } }) } module.exports.register = registerSocketForEvents ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/SocketIO-Mac/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/SocketIO-Mac/SocketIO-Mac.h ================================================ // // SocketIO-Mac.h // SocketIO-Mac // // Created by Nacho Soto on 7/11/15. // // #import //! Project version number for SocketIO-Mac. FOUNDATION_EXPORT double SocketIO_MacVersionNumber; //! Project version string for SocketIO-Mac. FOUNDATION_EXPORT const unsigned char SocketIO_MacVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/SocketIO-MacTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/SocketIO-MacTests/SocketAckManagerTest.swift ================================================ // // SocketAckManagerTest.swift // Socket.IO-Client-Swift // // Created by Lukas Schmidt on 04.09.15. // // import XCTest @testable import SocketIOClientSwift class SocketAckManagerTest: XCTestCase { var ackManager = SocketAckManager() func testAddAcks() { let callbackExpection = self.expectationWithDescription("callbackExpection") let itemsArray = ["Hi", "ho"] func callback(items: [AnyObject]) { callbackExpection.fulfill() } ackManager.addAck(1, callback: callback) ackManager.executeAck(1, items: itemsArray) waitForExpectationsWithTimeout(3.0, handler: nil) } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/SocketIO-MacTests/SocketBasicPacketTest.swift ================================================ // // SocketBasicPacketTest.swift // Socket.IO-Client-Swift // // Created by Erik Little on 10/7/15. // // import XCTest @testable import SocketIOClientSwift class SocketBasicPacketTest: XCTestCase { let data = "test".dataUsingEncoding(NSUTF8StringEncoding)! let data2 = "test2".dataUsingEncoding(NSUTF8StringEncoding)! func testEmpyEmit() { let expectedSendString = "2[\"test\"]" let sendData = ["test"] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) } func testNullEmit() { let expectedSendString = "2[\"test\",null]" let sendData = ["test", NSNull()] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) } func testStringEmit() { let expectedSendString = "2[\"test\",\"foo bar\"]" let sendData = ["test", "foo bar"] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) } func testJSONEmit() { let expectedSendString = "2[\"test\",{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]" let sendData = ["test", ["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) } func testArrayEmit() { let expectedSendString = "2[\"test\",[\"hello\",1,{\"test\":\"test\"}]]" let sendData = ["test", ["hello", 1, ["test": "test"]]] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) } func testBinaryEmit() { let expectedSendString = "51-[\"test\",{\"num\":0,\"_placeholder\":true}]" let sendData = ["test", data] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.binary, [data]) } func testMultipleBinaryEmit() { let expectedSendString = "52-[\"test\",{\"data1\":{\"num\":0,\"_placeholder\":true},\"data2\":{\"num\":1,\"_placeholder\":true}}]" let sendData = ["test", ["data1": data, "data2": data2]] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.binary, [data, data2]) } func testEmitWithAck() { let expectedSendString = "20[\"test\"]" let sendData = ["test"] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) } func testEmitDataWithAck() { let expectedSendString = "51-0[\"test\",{\"num\":0,\"_placeholder\":true}]" let sendData = ["test", data] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.binary, [data]) } // Acks func testEmptyAck() { let expectedSendString = "30[]" let packet = SocketPacket.packetFromEmit([], id: 0, nsp: "/", ack: true) XCTAssertEqual(packet.packetString, expectedSendString) } func testNullAck() { let expectedSendString = "30[null]" let sendData = [NSNull()] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true) XCTAssertEqual(packet.packetString, expectedSendString) } func testStringAck() { let expectedSendString = "30[\"test\"]" let sendData = ["test"] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true) XCTAssertEqual(packet.packetString, expectedSendString) } func testJSONAck() { let expectedSendString = "30[{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]" let sendData = [["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true) XCTAssertEqual(packet.packetString, expectedSendString) } func testBinaryAck() { let expectedSendString = "61-0[{\"num\":0,\"_placeholder\":true}]" let sendData = [data] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true) XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.binary, [data]) } func testMultipleBinaryAck() { let expectedSendString = "62-0[{\"data2\":{\"num\":0,\"_placeholder\":true},\"data1\":{\"num\":1,\"_placeholder\":true}}]" let sendData = [["data1": data, "data2": data2]] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/", ack: true) XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.binary, [data2, data]) } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/SocketIO-MacTests/SocketEngineTest.swift ================================================ // // SocketEngineTest.swift // Socket.IO-Client-Swift // // Created by Erik Little on 10/15/15. // // import XCTest @testable import SocketIOClientSwift class SocketEngineTest: XCTestCase { var client: SocketIOClient! var engine: SocketEngine! override func setUp() { super.setUp() client = SocketIOClient(socketURL: NSURL(string: "http://localhost")!) engine = SocketEngine(client: client, url: NSURL(string: "http://localhost")!, options: nil) client.setTestable() } func testBasicPollingMessage() { let expectation = expectationWithDescription("Basic polling test") client.on("blankTest") {data, ack in expectation.fulfill() } engine.parsePollingMessage("15:42[\"blankTest\"]") waitForExpectationsWithTimeout(3, handler: nil) } func testTwoPacketsInOnePollTest() { let finalExpectation = expectationWithDescription("Final packet in poll test") var gotBlank = false client.on("blankTest") {data, ack in gotBlank = true } client.on("stringTest") {data, ack in if let str = data[0] as? String where gotBlank { if str == "hello" { finalExpectation.fulfill() } } } engine.parsePollingMessage("15:42[\"blankTest\"]24:42[\"stringTest\",\"hello\"]") waitForExpectationsWithTimeout(3, handler: nil) } func testEngineDoesErrorOnUnknownTransport() { let finalExpectation = expectationWithDescription("Unknown Transport") client.on("error") {data, ack in if let error = data[0] as? String where error == "Unknown transport" { finalExpectation.fulfill() } } engine.parseEngineMessage("{\"code\": 0, \"message\": \"Unknown transport\"}", fromPolling: false) waitForExpectationsWithTimeout(3, handler: nil) } func testEngineDoesErrorOnUnknownMessage() { let finalExpectation = expectationWithDescription("Engine Errors") client.on("error") {data, ack in finalExpectation.fulfill() } engine.parseEngineMessage("afafafda", fromPolling: false) waitForExpectationsWithTimeout(3, handler: nil) } func testEngineDecodesUTF8Properly() { let expectation = expectationWithDescription("Engine Decodes utf8") client.on("stringTest") {data, ack in XCTAssertEqual(data[0] as? String, "lïne one\nlīne \rtwo", "Failed string test") expectation.fulfill() } engine.parsePollingMessage("41:42[\"stringTest\",\"lïne one\\nlÄ«ne \\rtwo\"]") waitForExpectationsWithTimeout(3, handler: nil) } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/SocketIO-MacTests/SocketNamespacePacketTest.swift ================================================ // // SocketNamespacePacketTest.swift // Socket.IO-Client-Swift // // Created by Erik Little on 10/11/15. // // import XCTest @testable import SocketIOClientSwift class SocketNamespacePacketTest: XCTestCase { let data = "test".dataUsingEncoding(NSUTF8StringEncoding)! let data2 = "test2".dataUsingEncoding(NSUTF8StringEncoding)! func testEmpyEmit() { let expectedSendString = "2/swift,[\"test\"]" let sendData = ["test"] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) } func testNullEmit() { let expectedSendString = "2/swift,[\"test\",null]" let sendData = ["test", NSNull()] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) } func testStringEmit() { let expectedSendString = "2/swift,[\"test\",\"foo bar\"]" let sendData = ["test", "foo bar"] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) } func testJSONEmit() { let expectedSendString = "2/swift,[\"test\",{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]" let sendData = ["test", ["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) } func testArrayEmit() { let expectedSendString = "2/swift,[\"test\",[\"hello\",1,{\"test\":\"test\"}]]" let sendData = ["test", ["hello", 1, ["test": "test"]]] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) } func testBinaryEmit() { let expectedSendString = "51-/swift,[\"test\",{\"num\":0,\"_placeholder\":true}]" let sendData = ["test", data] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.binary, [data]) } func testMultipleBinaryEmit() { let expectedSendString = "52-/swift,[\"test\",{\"data1\":{\"num\":0,\"_placeholder\":true},\"data2\":{\"num\":1,\"_placeholder\":true}}]" let sendData = ["test", ["data1": data, "data2": data2]] let packet = SocketPacket.packetFromEmit(sendData, id: -1, nsp: "/swift", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.binary, [data, data2]) } func testEmitWithAck() { let expectedSendString = "2/swift,0[\"test\"]" let sendData = ["test"] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) } func testEmitDataWithAck() { let expectedSendString = "51-/swift,0[\"test\",{\"num\":0,\"_placeholder\":true}]" let sendData = ["test", data] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: false) XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.binary, [data]) } // Acks func testEmptyAck() { let expectedSendString = "3/swift,0[]" let packet = SocketPacket.packetFromEmit([], id: 0, nsp: "/swift", ack: true) XCTAssertEqual(packet.packetString, expectedSendString) } func testNullAck() { let expectedSendString = "3/swift,0[null]" let sendData = [NSNull()] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true) XCTAssertEqual(packet.packetString, expectedSendString) } func testStringAck() { let expectedSendString = "3/swift,0[\"test\"]" let sendData = ["test"] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true) XCTAssertEqual(packet.packetString, expectedSendString) } func testJSONAck() { let expectedSendString = "3/swift,0[{\"test\":\"hello\",\"hello\":1,\"foobar\":true,\"null\":null}]" let sendData = [["foobar": true, "hello": 1, "test": "hello", "null": NSNull()]] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true) XCTAssertEqual(packet.packetString, expectedSendString) } func testBinaryAck() { let expectedSendString = "61-/swift,0[{\"num\":0,\"_placeholder\":true}]" let sendData = [data] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true) XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.binary, [data]) } func testMultipleBinaryAck() { let expectedSendString = "62-/swift,0[{\"data2\":{\"num\":0,\"_placeholder\":true},\"data1\":{\"num\":1,\"_placeholder\":true}}]" let sendData = [["data1": data, "data2": data2]] let packet = SocketPacket.packetFromEmit(sendData, id: 0, nsp: "/swift", ack: true) XCTAssertEqual(packet.packetString, expectedSendString) XCTAssertEqual(packet.binary, [data2, data]) } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/SocketIO-MacTests/SocketParserTest.swift ================================================ // // SocketParserTest.swift // Socket.IO-Client-Swift // // Created by Lukas Schmidt on 05.09.15. // // import XCTest @testable import SocketIOClientSwift class SocketParserTest: XCTestCase { let testSocket = SocketIOClient(socketURL: NSURL()) //Format key: message; namespace-data-binary-id static let packetTypes: Dictionary = [ "0": ("/", [], [], -1), "1": ("/", [], [], -1), "25[\"test\"]": ("/", ["test"], [], 5), "2[\"test\",\"~~0\"]": ("/", ["test", "~~0"], [], -1), "2/swift,[\"testArrayEmitReturn\",[\"test3\",\"test4\"]]": ("/swift", ["testArrayEmitReturn", ["test3", "test4"]], [], -1), "51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]": ("/swift", ["testMultipleItemsWithBufferEmitReturn", [1, 2], ["test": "bob"], 25, "polo", "~~0"], [], -1), "3/swift,0[[\"test3\",\"test4\"]]": ("/swift", [["test3", "test4"]], [], 0), "61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]": ("/swift", [ [1, 2], ["test": "bob"], 25, "polo", "~~0"], [], 19), "4/swift,": ("/swift", [], [], -1), "0/swift": ("/swift", [], [], -1), "1/swift": ("/swift", [], [], -1), "4\"ERROR\"": ("/", ["ERROR"], [], -1), "41": ("/", [1], [], -1)] func testDisconnect() { let message = "1" validateParseResult(message) } func testConnect() { let message = "0" validateParseResult(message) } func testDisconnectNameSpace() { let message = "1/swift" validateParseResult(message) } func testConnecttNameSpace() { let message = "0/swift" validateParseResult(message) } func testIdEvent() { let message = "25[\"test\"]" validateParseResult(message) } func testBinaryPlaceholderAsString() { let message = "2[\"test\",\"~~0\"]" validateParseResult(message) } func testNameSpaceArrayParse() { let message = "2/swift,[\"testArrayEmitReturn\",[\"test3\",\"test4\"]]" validateParseResult(message) } func testNameSpaceArrayAckParse() { let message = "3/swift,0[[\"test3\",\"test4\"]]" validateParseResult(message) } func testNameSpaceBinaryEventParse() { let message = "51-/swift,[\"testMultipleItemsWithBufferEmitReturn\",[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]" validateParseResult(message) } func testNameSpaceBinaryAckParse() { let message = "61-/swift,19[[1,2],{\"test\":\"bob\"},25,\"polo\",{\"_placeholder\":true,\"num\":0}]" validateParseResult(message) } func testNamespaceErrorParse() { let message = "4/swift," validateParseResult(message) } func testErrorTypeString() { let message = "4\"ERROR\"" validateParseResult(message) } func testErrorTypeInt() { let message = "41" validateParseResult(message) } func testInvalidInput() { let message = "8" switch testSocket.parseString(message) { case .Left(_): return case .Right(_): XCTFail("Created packet when shouldn't have") } } func testGenericParser() { var parser = SocketStringReader(message: "61-/swift,") XCTAssertEqual(parser.read(1), "6") XCTAssertEqual(parser.currentCharacter, "1") XCTAssertEqual(parser.readUntilStringOccurence("-"), "1") XCTAssertEqual(parser.currentCharacter, "/") } func validateParseResult(message: String) { let validValues = SocketParserTest.packetTypes[message]! let packet = testSocket.parseString(message) let type = message.substringWithRange(Range(start: message.startIndex, end: message.startIndex.advancedBy(1))) if case let .Right(packet) = packet { XCTAssertEqual(packet.type, SocketPacket.PacketType(rawValue: Int(type) ?? -1)!) XCTAssertEqual(packet.nsp, validValues.0) XCTAssertTrue((packet.data as NSArray).isEqualToArray(validValues.1)) XCTAssertTrue((packet.binary as NSArray).isEqualToArray(validValues.2)) XCTAssertEqual(packet.id, validValues.3) } else { XCTFail() } } func testParsePerformance() { let keys = Array(SocketParserTest.packetTypes.keys) measureBlock({ for item in keys.enumerate() { self.testSocket.parseString(item.element) } }) } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/SocketIO-MacTests/SocketSideEffectTest.swift ================================================ // // SocketSideEffectTest.swift // Socket.IO-Client-Swift // // Created by Erik Little on 10/11/15. // // import XCTest @testable import SocketIOClientSwift class SocketSideEffectTest: XCTestCase { let data = "test".dataUsingEncoding(NSUTF8StringEncoding)! let data2 = "test2".dataUsingEncoding(NSUTF8StringEncoding)! private var socket: SocketIOClient! override func setUp() { super.setUp() socket = SocketIOClient(socketURL: NSURL()) socket.setTestable() } func testInitialCurrentAck() { XCTAssertEqual(socket.currentAck, -1) } func testFirstAck() { socket.emitWithAck("test")(timeoutAfter: 0) {data in} XCTAssertEqual(socket.currentAck, 0) } func testSecondAck() { socket.emitWithAck("test")(timeoutAfter: 0) {data in} socket.emitWithAck("test")(timeoutAfter: 0) {data in} XCTAssertEqual(socket.currentAck, 1) } func testHandleAck() { let expectation = expectationWithDescription("handled ack") socket.emitWithAck("test")(timeoutAfter: 0) {data in XCTAssertEqual(data[0] as? String, "hello world") expectation.fulfill() } socket.parseSocketMessage("30[\"hello world\"]") waitForExpectationsWithTimeout(3, handler: nil) } func testHandleAck2() { let expectation = expectationWithDescription("handled ack2") socket.emitWithAck("test")(timeoutAfter: 0) {data in XCTAssertTrue(data.count == 2, "Wrong number of ack items") expectation.fulfill() } socket.parseSocketMessage("61-0[{\"_placeholder\":true,\"num\":0},{\"test\":true}]") socket.parseBinaryData(NSData()) waitForExpectationsWithTimeout(3, handler: nil) } func testHandleEvent() { let expectation = expectationWithDescription("handled event") socket.on("test") {data, ack in XCTAssertEqual(data[0] as? String, "hello world") expectation.fulfill() } socket.parseSocketMessage("2[\"test\",\"hello world\"]") waitForExpectationsWithTimeout(3, handler: nil) } func testHandleOnceEvent() { let expectation = expectationWithDescription("handled event") socket.once("test") {data, ack in XCTAssertEqual(data[0] as? String, "hello world") XCTAssertEqual(self.socket.testHandlers.count, 0) expectation.fulfill() } socket.parseSocketMessage("2[\"test\",\"hello world\"]") waitForExpectationsWithTimeout(3, handler: nil) } func testOffWithEvent() { socket.on("test") {data, ack in } XCTAssertEqual(socket.testHandlers.count, 1) socket.on("test") {data, ack in } XCTAssertEqual(socket.testHandlers.count, 2) socket.off("test") XCTAssertEqual(socket.testHandlers.count, 0) } func testOffWithId() { let handler = socket.on("test") {data, ack in } XCTAssertEqual(socket.testHandlers.count, 1) socket.on("test") {data, ack in } XCTAssertEqual(socket.testHandlers.count, 2) socket.off(id: handler) XCTAssertEqual(socket.testHandlers.count, 1) } func testHandlesErrorPacket() { let expectation = expectationWithDescription("Handled error") socket.on("error") {data, ack in if let error = data[0] as? String where error == "test error" { expectation.fulfill() } } socket.parseSocketMessage("4\"test error\"") waitForExpectationsWithTimeout(3, handler: nil) } func testHandleBinaryEvent() { let expectation = expectationWithDescription("handled binary event") socket.on("test") {data, ack in if let dict = data[0] as? NSDictionary, data = dict["test"] as? NSData { XCTAssertEqual(data, self.data) expectation.fulfill() } } socket.parseSocketMessage("51-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0}}]") socket.parseBinaryData(data) waitForExpectationsWithTimeout(3, handler: nil) } func testHandleMultipleBinaryEvent() { let expectation = expectationWithDescription("handled multiple binary event") socket.on("test") {data, ack in if let dict = data[0] as? NSDictionary, data = dict["test"] as? NSData, data2 = dict["test2"] as? NSData { XCTAssertEqual(data, self.data) XCTAssertEqual(data2, self.data2) expectation.fulfill() } } socket.parseSocketMessage("52-[\"test\",{\"test\":{\"_placeholder\":true,\"num\":0},\"test2\":{\"_placeholder\":true,\"num\":1}}]") socket.parseBinaryData(data) socket.parseBinaryData(data2) waitForExpectationsWithTimeout(3, handler: nil) } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/SocketIO-iOS/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/SocketIO-iOS/SocketIO-iOS.h ================================================ // // SocketIO-iOS.h // SocketIO-iOS // // Created by Nacho Soto on 7/11/15. // // #import //! Project version number for SocketIO-iOS. FOUNDATION_EXPORT double SocketIO_iOSVersionNumber; //! Project version string for SocketIO-iOS. FOUNDATION_EXPORT const unsigned char SocketIO_iOSVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/SocketIO-iOSTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketAckEmitter.swift ================================================ // // SocketAckEmitter.swift // Socket.IO-Client-Swift // // Created by Erik Little on 9/16/15. // // 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. import Foundation public final class SocketAckEmitter: NSObject { let socket: SocketIOClient let ackNum: Int init(socket: SocketIOClient, ackNum: Int) { self.socket = socket self.ackNum = ackNum } public func with(items: AnyObject...) { guard ackNum != -1 else { return } socket.emitAck(ackNum, withItems: items) } public func with(items: [AnyObject]) { guard ackNum != -1 else { return } socket.emitAck(ackNum, withItems: items) } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketAckManager.swift ================================================ // // SocketAckManager.swift // Socket.IO-Client-Swift // // Created by Erik Little on 4/3/15. // // 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. import Foundation private struct SocketAck: Hashable, Equatable { let ack: Int var callback: AckCallback! var hashValue: Int { return ack.hashValue } init(ack: Int) { self.ack = ack } init(ack: Int, callback: AckCallback) { self.ack = ack self.callback = callback } } private func <(lhs: SocketAck, rhs: SocketAck) -> Bool { return lhs.ack < rhs.ack } private func ==(lhs: SocketAck, rhs: SocketAck) -> Bool { return lhs.ack == rhs.ack } struct SocketAckManager { private var acks = Set(minimumCapacity: 1) mutating func addAck(ack: Int, callback: AckCallback) { acks.insert(SocketAck(ack: ack, callback: callback)) } mutating func executeAck(ack: Int, items: [AnyObject]) { let callback = acks.remove(SocketAck(ack: ack)) dispatch_async(dispatch_get_main_queue()) { callback?.callback(items) } } mutating func timeoutAck(ack: Int) { let callback = acks.remove(SocketAck(ack: ack)) dispatch_async(dispatch_get_main_queue()) { callback?.callback(["NO ACK"]) } } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketAnyEvent.swift ================================================ // // SocketAnyEvent.swift // Socket.IO-Client-Swift // // Created by Erik Little on 3/28/15. // // 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. import Foundation public final class SocketAnyEvent: NSObject { public let event: String public let items: NSArray? override public var description: String { return "SocketAnyEvent: Event: \(event) items: \(items ?? nil)" } init(event: String, items: NSArray?) { self.event = event self.items = items } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketClientSpec.swift ================================================ // // SocketClientSpec.swift // Socket.IO-Client-Swift // // Created by Erik Little on 1/3/16. // // 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. protocol SocketClientSpec: class { var nsp: String { get set } var waitingData: [SocketPacket] { get set } func didConnect() func didDisconnect(reason: String) func didError(reason: String) func handleAck(ack: Int, data: [AnyObject]) func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int) func joinNamespace(namespace: String) } extension SocketClientSpec { func didError(reason: String) { DefaultSocketLogger.Logger.error("%@", type: "SocketIOClient", args: reason) handleEvent("error", data: [reason], isInternalMessage: true, withAck: -1) } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketEngine.swift ================================================ // // SocketEngine.swift // Socket.IO-Client-Swift // // Created by Erik Little on 3/3/15. // // 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. import Foundation public final class SocketEngine: NSObject, SocketEnginePollable, SocketEngineWebsocket { public let emitQueue = dispatch_queue_create("com.socketio.engineEmitQueue", DISPATCH_QUEUE_SERIAL) public let handleQueue = dispatch_queue_create("com.socketio.engineHandleQueue", DISPATCH_QUEUE_SERIAL) public let parseQueue = dispatch_queue_create("com.socketio.engineParseQueue", DISPATCH_QUEUE_SERIAL) public var connectParams: [String: AnyObject]? { didSet { (urlPolling, urlWebSocket) = createURLs() } } public var postWait = [String]() public var waitingForPoll = false public var waitingForPost = false public private(set) var closed = false public private(set) var connected = false public private(set) var cookies: [NSHTTPCookie]? public private(set) var extraHeaders: [String: String]? public private(set) var fastUpgrade = false public private(set) var forcePolling = false public private(set) var forceWebsockets = false public private(set) var invalidated = false public private(set) var pingTimer: NSTimer? public private(set) var polling = true public private(set) var probing = false public private(set) var session: NSURLSession? public private(set) var sid = "" public private(set) var socketPath = "/engine.io/" public private(set) var urlPolling = NSURL() public private(set) var urlWebSocket = NSURL() public private(set) var websocket = false public private(set) var ws: WebSocket? public weak var client: SocketEngineClient? private weak var sessionDelegate: NSURLSessionDelegate? private typealias Probe = (msg: String, type: SocketEnginePacketType, data: [NSData]) private typealias ProbeWaitQueue = [Probe] private let logType = "SocketEngine" private let url: NSURL private var pingInterval: Double? private var pingTimeout = 0.0 { didSet { pongsMissedMax = Int(pingTimeout / (pingInterval ?? 25)) } } private var pongsMissed = 0 private var pongsMissedMax = 0 private var probeWait = ProbeWaitQueue() private var secure = false private var selfSigned = false private var voipEnabled = false public init(client: SocketEngineClient, url: NSURL, options: Set) { self.client = client self.url = url for option in options { switch option { case let .ConnectParams(params): connectParams = params case let .SessionDelegate(delegate): sessionDelegate = delegate case let .ForcePolling(force): forcePolling = force case let .ForceWebsockets(force): forceWebsockets = force case let .Cookies(cookies): self.cookies = cookies case let .Path(path): socketPath = path case let .ExtraHeaders(headers): extraHeaders = headers case let .VoipEnabled(enable): voipEnabled = enable case let .Secure(secure): self.secure = secure case let .SelfSigned(selfSigned): self.selfSigned = selfSigned default: continue } } super.init() (urlPolling, urlWebSocket) = createURLs() } public convenience init(client: SocketEngineClient, url: NSURL, options: NSDictionary?) { self.init(client: client, url: url, options: options?.toSocketOptionsSet() ?? []) } @available(*, deprecated=5.3) public convenience init(client: SocketEngineClient, urlString: String, options: Set) { guard let url = NSURL(string: urlString) else { fatalError("Incorrect url") } self.init(client: client, url: url, options: options) } @available(*, deprecated=5.3) public convenience init(client: SocketEngineClient, urlString: String, options: NSDictionary?) { guard let url = NSURL(string: urlString) else { fatalError("Incorrect url") } self.init(client: client, url: url, options: options?.toSocketOptionsSet() ?? []) } deinit { DefaultSocketLogger.Logger.log("Engine is being released", type: logType) closed = true stopPolling() } private func checkAndHandleEngineError(msg: String) { guard let stringData = msg.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) else { return } do { if let dict = try NSJSONSerialization.JSONObjectWithData(stringData, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary { guard let code = dict["code"] as? Int else { return } guard let error = dict["message"] as? String else { return } switch code { case 0: // Unknown transport didError(error) case 1: // Unknown sid. didError(error) case 2: // Bad handshake request didError(error) case 3: // Bad request didError(error) default: didError(error) } } } catch { didError("Got unknown error from server \(msg)") } } private func checkIfMessageIsBase64Binary(message: String) -> Bool { if message.hasPrefix("b4") { // binary in base64 string let noPrefix = message[message.startIndex.advancedBy(2).. (NSURL, NSURL) { if client == nil { return (NSURL(), NSURL()) } let urlPolling = NSURLComponents(string: url.absoluteString)! let urlWebSocket = NSURLComponents(string: url.absoluteString)! var queryString = "" urlWebSocket.path = socketPath urlPolling.path = socketPath urlWebSocket.query = "transport=websocket" urlPolling.query = "transport=polling&b64=1" if secure { urlPolling.scheme = "https" urlWebSocket.scheme = "wss" } else { urlPolling.scheme = "http" urlWebSocket.scheme = "ws" } if connectParams != nil { for (key, value) in connectParams! { queryString += "&\(key)=\(value)" } } urlWebSocket.query = urlWebSocket.query! + queryString urlPolling.query = urlPolling.query! + queryString return (urlPolling.URL!, urlWebSocket.URL!) } private func createWebsocketAndConnect() { ws = WebSocket(url: urlWebSocketWithSid) if cookies != nil { let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!) for (key, value) in headers { ws?.headers[key] = value } } if extraHeaders != nil { for (headerName, value) in extraHeaders! { ws?.headers[headerName] = value } } ws?.queue = handleQueue ws?.voipEnabled = voipEnabled ws?.delegate = self ws?.selfSignedSSL = selfSigned ws?.connect() } public func didError(error: String) { DefaultSocketLogger.Logger.error(error, type: logType) client?.engineDidError(error) close(error) } public func doFastUpgrade() { if waitingForPoll { DefaultSocketLogger.Logger.error("Outstanding poll when switched to WebSockets," + "we'll probably disconnect soon. You should report this.", type: logType) } sendWebSocketMessage("", withType: .Upgrade, withData: []) websocket = true polling = false fastUpgrade = false probing = false flushProbeWait() } private func flushProbeWait() { DefaultSocketLogger.Logger.log("Flushing probe wait", type: logType) dispatch_async(emitQueue) { for waiter in self.probeWait { self.write(waiter.msg, withType: waiter.type, withData: waiter.data) } self.probeWait.removeAll(keepCapacity: false) if self.postWait.count != 0 { self.flushWaitingForPostToWebSocket() } } } // We had packets waiting for send when we upgraded // Send them raw public func flushWaitingForPostToWebSocket() { guard let ws = self.ws else { return } for msg in postWait { ws.writeString(fixDoubleUTF8(msg)) } postWait.removeAll(keepCapacity: true) } private func handleClose(reason: String) { client?.engineDidClose(reason) } private func handleMessage(message: String) { client?.parseEngineMessage(message) } private func handleNOOP() { doPoll() } private func handleOpen(openData: String) { let mesData = openData.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! do { let json = try NSJSONSerialization.JSONObjectWithData(mesData, options: NSJSONReadingOptions.AllowFragments) as? NSDictionary if let sid = json?["sid"] as? String { let upgradeWs: Bool self.sid = sid connected = true if let upgrades = json?["upgrades"] as? [String] { upgradeWs = upgrades.contains("websocket") } else { upgradeWs = false } if let pingInterval = json?["pingInterval"] as? Double, pingTimeout = json?["pingTimeout"] as? Double { self.pingInterval = pingInterval / 1000.0 self.pingTimeout = pingTimeout / 1000.0 } if !forcePolling && !forceWebsockets && upgradeWs { createWebsocketAndConnect() } startPingTimer() if !forceWebsockets { doPoll() } client?.engineDidOpen?("Connect") } } catch { didError("Error parsing open packet") return } } private func handlePong(pongMessage: String) { pongsMissed = 0 // We should upgrade if pongMessage == "3probe" { upgradeTransport() } } public func open() { if connected { DefaultSocketLogger.Logger.error("Engine tried opening while connected. Assuming this was a reconnect", type: logType) close("reconnect") } DefaultSocketLogger.Logger.log("Starting engine", type: logType) DefaultSocketLogger.Logger.log("Handshaking", type: logType) resetEngine() if forceWebsockets { polling = false websocket = true createWebsocketAndConnect() return } let reqPolling = NSMutableURLRequest(URL: urlPolling) if cookies != nil { let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!) reqPolling.allHTTPHeaderFields = headers } if let extraHeaders = extraHeaders { for (headerName, value) in extraHeaders { reqPolling.setValue(value, forHTTPHeaderField: headerName) } } doLongPoll(reqPolling) } public func parseEngineData(data: NSData) { DefaultSocketLogger.Logger.log("Got binary data: %@", type: "SocketEngine", args: data) client?.parseEngineBinaryData(data.subdataWithRange(NSMakeRange(1, data.length - 1))) } public func parseEngineMessage(message: String, fromPolling: Bool) { DefaultSocketLogger.Logger.log("Got message: %@", type: logType, args: message) let reader = SocketStringReader(message: message) let fixedString: String guard let type = SocketEnginePacketType(rawValue: Int(reader.currentCharacter) ?? -1) else { if !checkIfMessageIsBase64Binary(message) { checkAndHandleEngineError(message) } return } if fromPolling && type != .Noop { fixedString = fixDoubleUTF8(message) } else { fixedString = message } switch type { case .Message: handleMessage(fixedString[fixedString.startIndex.successor().. pongsMissedMax { pingTimer?.invalidate() client?.engineDidClose("Ping timeout") return } pongsMissed += 1 write("", withType: .Ping, withData: []) } // Starts the ping timer private func startPingTimer() { if let pingInterval = pingInterval { pingTimer?.invalidate() pingTimer = nil dispatch_async(dispatch_get_main_queue()) { self.pingTimer = NSTimer.scheduledTimerWithTimeInterval(pingInterval, target: self, selector: Selector("sendPing"), userInfo: nil, repeats: true) } } } private func upgradeTransport() { if ws?.isConnected ?? false { DefaultSocketLogger.Logger.log("Upgrading transport to WebSockets", type: logType) fastUpgrade = true sendPollMessage("", withType: .Noop, withData: []) // After this point, we should not send anymore polling messages } } /** Write a message, independent of transport. */ public func write(msg: String, withType type: SocketEnginePacketType, withData data: [NSData]) { dispatch_async(emitQueue) { guard self.connected else { return } if self.websocket { DefaultSocketLogger.Logger.log("Writing ws: %@ has data: %@", type: self.logType, args: msg, data.count != 0) self.sendWebSocketMessage(msg, withType: type, withData: data) } else if !self.probing { DefaultSocketLogger.Logger.log("Writing poll: %@ has data: %@", type: self.logType, args: msg, data.count != 0) self.sendPollMessage(msg, withType: type, withData: data) } else { self.probeWait.append((msg, type, data)) } } } // Delegate methods public func websocketDidConnect(socket: WebSocket) { if !forceWebsockets { probing = true probeWebSocket() } else { connected = true probing = false polling = false } } public func websocketDidDisconnect(socket: WebSocket, error: NSError?) { probing = false if closed { client?.engineDidClose("Disconnect") return } if websocket { pingTimer?.invalidate() connected = false websocket = false let reason = error?.localizedDescription ?? "Socket Disconnected" if error != nil { didError(reason) } client?.engineDidClose(reason) } else { flushProbeWait() } } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketEngineClient.swift ================================================ // // SocketEngineClient.swift // Socket.IO-Client-Swift // // Created by Erik Little on 3/19/15. // // 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. // import Foundation @objc public protocol SocketEngineClient { func engineDidError(reason: String) func engineDidClose(reason: String) optional func engineDidOpen(reason: String) func parseEngineMessage(msg: String) func parseEngineBinaryData(data: NSData) } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketEnginePacketType.swift ================================================ // // SocketEnginePacketType.swift // Socket.IO-Client-Swift // // Created by Erik Little on 10/7/15. // // 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. // import Foundation @objc public enum SocketEnginePacketType: Int { case Open, Close, Ping, Pong, Message, Upgrade, Noop } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketEnginePollable.swift ================================================ // // SocketEnginePollable.swift // Socket.IO-Client-Swift // // Created by Erik Little on 1/15/16. // // 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. import Foundation /// Protocol that is used to implement socket.io polling support public protocol SocketEnginePollable: SocketEngineSpec { var invalidated: Bool { get } /// Holds strings waiting to be sent over polling. /// You shouldn't need to mess with this. var postWait: [String] { get set } var session: NSURLSession? { get } /// Because socket.io doesn't let you send two polling request at the same time /// we have to keep track if there's an outstanding poll var waitingForPoll: Bool { get set } /// Because socket.io doesn't let you send two post request at the same time /// we have to keep track if there's an outstanding post var waitingForPost: Bool { get set } func doPoll() func sendPollMessage(message: String, withType type: SocketEnginePacketType, withData datas: [NSData]) func stopPolling() } // Default polling methods extension SocketEnginePollable { private func addHeaders(req: NSMutableURLRequest) { if cookies != nil { let headers = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies!) req.allHTTPHeaderFields = headers } if extraHeaders != nil { for (headerName, value) in extraHeaders! { req.setValue(value, forHTTPHeaderField: headerName) } } } func createRequestForPostWithPostWait() -> NSURLRequest { var postStr = "" for packet in postWait { let len = packet.characters.count postStr += "\(len):\(packet)" } DefaultSocketLogger.Logger.log("Created POST string: %@", type: "SocketEnginePolling", args: postStr) postWait.removeAll(keepCapacity: false) let req = NSMutableURLRequest(URL: urlPollingWithSid) addHeaders(req) req.HTTPMethod = "POST" req.setValue("text/plain; charset=UTF-8", forHTTPHeaderField: "Content-Type") let postData = postStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! req.HTTPBody = postData req.setValue(String(postData.length), forHTTPHeaderField: "Content-Length") return req } public func doPoll() { if websocket || waitingForPoll || !connected || closed { return } waitingForPoll = true let req = NSMutableURLRequest(URL: urlPollingWithSid) addHeaders(req) doLongPoll(req) } func doRequest(req: NSURLRequest, withCallback callback: (NSData?, NSURLResponse?, NSError?) -> Void) { if !polling || closed || invalidated { DefaultSocketLogger.Logger.error("Tried to do polling request when not supposed to", type: "SocketEnginePolling") return } DefaultSocketLogger.Logger.log("Doing polling request", type: "SocketEnginePolling") session?.dataTaskWithRequest(req, completionHandler: callback).resume() } func doLongPoll(req: NSURLRequest) { doRequest(req) {[weak self] data, res, err in guard let this = self else { return } if err != nil || data == nil { DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEnginePolling") if this.polling { this.didError(err?.localizedDescription ?? "Error") } return } DefaultSocketLogger.Logger.log("Got polling response", type: "SocketEnginePolling") if let str = String(data: data!, encoding: NSUTF8StringEncoding) { dispatch_async(this.parseQueue) { this.parsePollingMessage(str) } } this.waitingForPoll = false if this.fastUpgrade { this.doFastUpgrade() } else if !this.closed && this.polling { this.doPoll() } } } private func flushWaitingForPost() { if postWait.count == 0 || !connected { return } else if websocket { flushWaitingForPostToWebSocket() return } let req = createRequestForPostWithPostWait() waitingForPost = true DefaultSocketLogger.Logger.log("POSTing", type: "SocketEnginePolling") doRequest(req) {[weak self] data, res, err in guard let this = self else { return } if err != nil { DefaultSocketLogger.Logger.error(err?.localizedDescription ?? "Error", type: "SocketEnginePolling") if this.polling { this.didError(err?.localizedDescription ?? "Error") } return } this.waitingForPost = false dispatch_async(this.emitQueue) { if !this.fastUpgrade { this.flushWaitingForPost() this.doPoll() } } } } func parsePollingMessage(str: String) { guard str.characters.count != 1 else { return } var reader = SocketStringReader(message: str) while reader.hasNext { if let n = Int(reader.readUntilStringOccurence(":")) { let str = reader.read(n) dispatch_async(handleQueue) { self.parseEngineMessage(str, fromPolling: true) } } else { dispatch_async(handleQueue) { self.parseEngineMessage(str, fromPolling: true) } break } } } /// Send polling message. /// Only call on emitQueue public func sendPollMessage(message: String, withType type: SocketEnginePacketType, withData datas: [NSData]) { DefaultSocketLogger.Logger.log("Sending poll: %@ as type: %@", type: "SocketEnginePolling", args: message, type.rawValue) let fixedMessage = doubleEncodeUTF8(message) let strMsg = "\(type.rawValue)\(fixedMessage)" postWait.append(strMsg) for data in datas { if case let .Right(bin) = createBinaryDataForSend(data) { postWait.append(bin) } } if !waitingForPost { flushWaitingForPost() } } public func stopPolling() { waitingForPoll = false waitingForPost = false session?.finishTasksAndInvalidate() } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketEngineSpec.swift ================================================ // // SocketEngineSpec.swift // Socket.IO-Client-Swift // // Created by Erik Little on 10/7/15. // // 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. // import Foundation @objc public protocol SocketEngineSpec { weak var client: SocketEngineClient? { get set } var closed: Bool { get } var connected: Bool { get } var connectParams: [String: AnyObject]? { get set } var cookies: [NSHTTPCookie]? { get } var extraHeaders: [String: String]? { get } var fastUpgrade: Bool { get } var forcePolling: Bool { get } var forceWebsockets: Bool { get } var parseQueue: dispatch_queue_t! { get } var pingTimer: NSTimer? { get } var polling: Bool { get } var probing: Bool { get } var emitQueue: dispatch_queue_t! { get } var handleQueue: dispatch_queue_t! { get } var sid: String { get } var socketPath: String { get } var urlPolling: NSURL { get } var urlWebSocket: NSURL { get } var websocket: Bool { get } init(client: SocketEngineClient, url: NSURL, options: NSDictionary?) func close(reason: String) func didError(error: String) func doFastUpgrade() func flushWaitingForPostToWebSocket() func open() func parseEngineData(data: NSData) func parseEngineMessage(message: String, fromPolling: Bool) func write(msg: String, withType type: SocketEnginePacketType, withData data: [NSData]) } extension SocketEngineSpec { var urlPollingWithSid: NSURL { let com = NSURLComponents(URL: urlPolling, resolvingAgainstBaseURL: false)! com.query = com.query! + "&sid=\(sid)" return com.URL! } var urlWebSocketWithSid: NSURL { let com = NSURLComponents(URL: urlWebSocket, resolvingAgainstBaseURL: false)! com.query = com.query! + (sid == "" ? "" : "&sid=\(sid)") return com.URL! } func createBinaryDataForSend(data: NSData) -> Either { if websocket { var byteArray = [UInt8](count: 1, repeatedValue: 0x4) let mutData = NSMutableData(bytes: &byteArray, length: 1) mutData.appendData(data) return .Left(mutData) } else { let str = "b4" + data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0)) return .Right(str) } } /// Send an engine message (4) func send(msg: String, withData datas: [NSData]) { write(msg, withType: .Message, withData: datas) } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketEngineWebsocket.swift ================================================ // // SocketEngineWebsocket.swift // Socket.IO-Client-Swift // // Created by Erik Little on 1/15/16. // // 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. // import Foundation /// Protocol that is used to implement socket.io WebSocket support public protocol SocketEngineWebsocket: SocketEngineSpec, WebSocketDelegate { var ws: WebSocket? { get } func sendWebSocketMessage(str: String, withType type: SocketEnginePacketType, withData datas: [NSData]) } // WebSocket methods extension SocketEngineWebsocket { func probeWebSocket() { if ws?.isConnected ?? false { sendWebSocketMessage("probe", withType: .Ping, withData: []) } } /// Send message on WebSockets /// Only call on emitQueue public func sendWebSocketMessage(str: String, withType type: SocketEnginePacketType, withData datas: [NSData]) { DefaultSocketLogger.Logger.log("Sending ws: %@ as type: %@", type: "SocketEngine", args: str, type.rawValue) ws?.writeString("\(type.rawValue)\(str)") for data in datas { if case let .Left(bin) = createBinaryDataForSend(data) { ws?.writeData(bin) } } } public func websocketDidReceiveMessage(socket: WebSocket, text: String) { parseEngineMessage(text, fromPolling: false) } public func websocketDidReceiveData(socket: WebSocket, data: NSData) { parseEngineData(data) } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketEventHandler.swift ================================================ // // EventHandler.swift // Socket.IO-Client-Swift // // Created by Erik Little on 1/18/15. // // 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. import Foundation struct SocketEventHandler { let event: String let id: NSUUID let callback: NormalCallback func executeCallback(items: [AnyObject], withAck ack: Int, withSocket socket: SocketIOClient) { callback(items, SocketAckEmitter(socket: socket, ackNum: ack)) } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketFixUTF8.swift ================================================ // // SocketFixUTF8.swift // Socket.IO-Client-Swift // // Created by Erik Little on 3/16/15. // // 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. // import Foundation func fixDoubleUTF8(string: String) -> String { if let utf8 = string.dataUsingEncoding(NSISOLatin1StringEncoding), latin1 = NSString(data: utf8, encoding: NSUTF8StringEncoding) { return latin1 as String } else { return string } } func doubleEncodeUTF8(string: String) -> String { if let latin1 = string.dataUsingEncoding(NSUTF8StringEncoding), utf8 = NSString(data: latin1, encoding: NSISOLatin1StringEncoding) { return utf8 as String } else { return string } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketIOClient.swift ================================================ // // SocketIOClient.swift // Socket.IO-Client-Swift // // Created by Erik Little on 11/23/14. // // 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. import Foundation public final class SocketIOClient: NSObject, SocketEngineClient, SocketParsable { public let socketURL: NSURL public private(set) var engine: SocketEngineSpec? public private(set) var status = SocketIOClientStatus.NotConnected public var forceNew = false public var nsp = "/" public var options: Set public var reconnects = true public var reconnectWait = 10 public var sid: String? { return engine?.sid } private let emitQueue = dispatch_queue_create("com.socketio.emitQueue", DISPATCH_QUEUE_SERIAL) private let logType = "SocketIOClient" private let parseQueue = dispatch_queue_create("com.socketio.parseQueue", DISPATCH_QUEUE_SERIAL) private var anyHandler: ((SocketAnyEvent) -> Void)? private var currentReconnectAttempt = 0 private var handlers = [SocketEventHandler]() private var reconnectTimer: NSTimer? private var ackHandlers = SocketAckManager() private(set) var currentAck = -1 private(set) var handleQueue = dispatch_get_main_queue() private(set) var reconnectAttempts = -1 var waitingData = [SocketPacket]() /** Type safe way to create a new SocketIOClient. opts can be omitted */ public init(socketURL: NSURL, options: Set = []) { self.options = options self.socketURL = socketURL if socketURL.absoluteString.hasPrefix("https://") { self.options.insertIgnore(.Secure(true)) } for option in options { switch option { case let .Reconnects(reconnects): self.reconnects = reconnects case let .ReconnectAttempts(attempts): reconnectAttempts = attempts case let .ReconnectWait(wait): reconnectWait = abs(wait) case let .Nsp(nsp): self.nsp = nsp case let .Log(log): DefaultSocketLogger.Logger.log = log case let .Logger(logger): DefaultSocketLogger.Logger = logger case let .HandleQueue(queue): handleQueue = queue case let .ForceNew(force): forceNew = force default: continue } } self.options.insertIgnore(.Path("/socket.io/")) super.init() } /** Not so type safe way to create a SocketIOClient, meant for Objective-C compatiblity. If using Swift it's recommended to use `init(socketURL: NSURL, options: Set)` */ public convenience init(socketURL: NSURL, options: NSDictionary?) { self.init(socketURL: socketURL, options: options?.toSocketOptionsSet() ?? []) } /// Please use the NSURL based init @available(*, deprecated=5.3) public convenience init(socketURLString: String, options: Set = []) { guard let url = NSURL(string: socketURLString) else { fatalError("Incorrect url") } self.init(socketURL: url, options: options) } /// Please use the NSURL based init @available(*, deprecated=5.3) public convenience init(socketURLString: String, options: NSDictionary?) { guard let url = NSURL(string: socketURLString) else { fatalError("Incorrect url") } self.init(socketURL: url, options: options?.toSocketOptionsSet() ?? []) } deinit { DefaultSocketLogger.Logger.log("Client is being released", type: logType) engine?.close("Client Deinit") } private func addEngine() -> SocketEngineSpec { DefaultSocketLogger.Logger.log("Adding engine", type: logType) engine = SocketEngine(client: self, url: socketURL, options: options) return engine! } private func clearReconnectTimer() { reconnectTimer?.invalidate() reconnectTimer = nil } @available(*, deprecated=5.3) public func close() { disconnect() } /** Connect to the server. */ public func connect() { connect(timeoutAfter: 0, withTimeoutHandler: nil) } /** Connect to the server. If we aren't connected after timeoutAfter, call handler */ public func connect(timeoutAfter timeoutAfter: Int, withTimeoutHandler handler: (() -> Void)?) { assert(timeoutAfter >= 0, "Invalid timeout: \(timeoutAfter)") guard status != .Connected else { DefaultSocketLogger.Logger.log("Tried connecting on an already connected socket", type: logType) return } status = .Connecting if engine == nil || forceNew { addEngine().open() } else { engine?.open() } guard timeoutAfter != 0 else { return } let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeoutAfter) * Int64(NSEC_PER_SEC)) dispatch_after(time, handleQueue) {[weak self] in if let this = self where this.status != .Connected { this.status = .Closed this.engine?.close("Connect timeout") handler?() } } } private func createOnAck(items: [AnyObject]) -> OnAckCallback { currentAck += 1 return {[weak self, ack = currentAck] timeout, callback in if let this = self { this.ackHandlers.addAck(ack, callback: callback) dispatch_async(this.emitQueue) { this._emit(items, ack: ack) } if timeout != 0 { let time = dispatch_time(DISPATCH_TIME_NOW, Int64(timeout * NSEC_PER_SEC)) dispatch_after(time, this.handleQueue) { this.ackHandlers.timeoutAck(ack) } } } } } func didConnect() { DefaultSocketLogger.Logger.log("Socket connected", type: logType) status = .Connected currentReconnectAttempt = 0 clearReconnectTimer() // Don't handle as internal because something crazy could happen where // we disconnect before it's handled handleEvent("connect", data: [], isInternalMessage: false) } func didDisconnect(reason: String) { guard status != .Closed else { return } DefaultSocketLogger.Logger.log("Disconnected: %@", type: logType, args: reason) status = .Closed reconnects = false // Make sure the engine is actually dead. engine?.close(reason) handleEvent("disconnect", data: [reason], isInternalMessage: true) } /** Disconnects the socket. Only reconnect the same socket if you know what you're doing. Will turn off automatic reconnects. */ public func disconnect() { DefaultSocketLogger.Logger.log("Closing socket", type: logType) reconnects = false didDisconnect("Disconnect") } /** Send a message to the server */ public func emit(event: String, _ items: AnyObject...) { emit(event, withItems: items) } /** Same as emit, but meant for Objective-C */ public func emit(event: String, withItems items: [AnyObject]) { guard status == .Connected else { handleEvent("error", data: ["Tried emitting \(event) when not connected"], isInternalMessage: true) return } dispatch_async(emitQueue) { self._emit([event] + items) } } /** Sends a message to the server, requesting an ack. Use the onAck method of SocketAckHandler to add an ack. */ public func emitWithAck(event: String, _ items: AnyObject...) -> OnAckCallback { return emitWithAck(event, withItems: items) } /** Same as emitWithAck, but for Objective-C */ public func emitWithAck(event: String, withItems items: [AnyObject]) -> OnAckCallback { return createOnAck([event] + items) } private func _emit(data: [AnyObject], ack: Int? = nil) { guard status == .Connected else { handleEvent("error", data: ["Tried emitting when not connected"], isInternalMessage: true) return } let packet = SocketPacket.packetFromEmit(data, id: ack ?? -1, nsp: nsp, ack: false) let str = packet.packetString DefaultSocketLogger.Logger.log("Emitting: %@", type: logType, args: str) engine?.send(str, withData: packet.binary) } // If the server wants to know that the client received data func emitAck(ack: Int, withItems items: [AnyObject]) { dispatch_async(emitQueue) { if self.status == .Connected { let packet = SocketPacket.packetFromEmit(items, id: ack ?? -1, nsp: self.nsp, ack: true) let str = packet.packetString DefaultSocketLogger.Logger.log("Emitting Ack: %@", type: self.logType, args: str) self.engine?.send(str, withData: packet.binary) } } } public func engineDidClose(reason: String) { waitingData.removeAll() if status == .Closed || !reconnects { didDisconnect(reason) } else if status != .Reconnecting { tryReconnectWithReason(reason) } } /// error public func engineDidError(reason: String) { DefaultSocketLogger.Logger.error("%@", type: logType, args: reason) handleEvent("error", data: [reason], isInternalMessage: true) } // Called when the socket gets an ack for something it sent func handleAck(ack: Int, data: [AnyObject]) { guard status == .Connected else {return} DefaultSocketLogger.Logger.log("Handling ack: %@ with data: %@", type: logType, args: ack, data ?? "") ackHandlers.executeAck(ack, items: data) } /** Causes an event to be handled. Only use if you know what you're doing. */ public func handleEvent(event: String, data: [AnyObject], isInternalMessage: Bool, withAck ack: Int = -1) { guard status == .Connected || isInternalMessage else { return } DefaultSocketLogger.Logger.log("Handling event: %@ with data: %@", type: logType, args: event, data ?? "") dispatch_async(handleQueue) { self.anyHandler?(SocketAnyEvent(event: event, items: data)) for handler in self.handlers where handler.event == event { handler.executeCallback(data, withAck: ack, withSocket: self) } } } /** Leaves nsp and goes back to / */ public func leaveNamespace() { if nsp != "/" { engine?.send("1\(nsp)", withData: []) nsp = "/" } } /** Joins namespace */ public func joinNamespace(namespace: String) { nsp = namespace if nsp != "/" { DefaultSocketLogger.Logger.log("Joining namespace", type: logType) engine?.send("0\(nsp)", withData: []) } } /** Removes handler(s) */ public func off(event: String) { DefaultSocketLogger.Logger.log("Removing handler for event: %@", type: logType, args: event) handlers = handlers.filter { $0.event != event } } /** Removes a handler with the specified UUID gotten from an `on` or `once` */ public func off(id id: NSUUID) { DefaultSocketLogger.Logger.log("Removing handler with id: %@", type: logType, args: id) handlers = handlers.filter { $0.id != id } } /** Adds a handler for an event. Returns: A unique id for the handler */ public func on(event: String, callback: NormalCallback) -> NSUUID { DefaultSocketLogger.Logger.log("Adding handler for event: %@", type: logType, args: event) let handler = SocketEventHandler(event: event, id: NSUUID(), callback: callback) handlers.append(handler) return handler.id } /** Adds a single-use handler for an event. Returns: A unique id for the handler */ public func once(event: String, callback: NormalCallback) -> NSUUID { DefaultSocketLogger.Logger.log("Adding once handler for event: %@", type: logType, args: event) let id = NSUUID() let handler = SocketEventHandler(event: event, id: id) {[weak self] data, ack in guard let this = self else { return } this.off(id: id) callback(data, ack) } handlers.append(handler) return handler.id } /** Adds a handler that will be called on every event. */ public func onAny(handler: (SocketAnyEvent) -> Void) { anyHandler = handler } /** Same as connect */ @available(*, deprecated=5.3) public func open() { connect() } public func parseEngineMessage(msg: String) { DefaultSocketLogger.Logger.log("Should parse message: %@", type: "SocketIOClient", args: msg) dispatch_async(parseQueue) { self.parseSocketMessage(msg) } } public func parseEngineBinaryData(data: NSData) { dispatch_async(parseQueue) { self.parseBinaryData(data) } } /** Tries to reconnect to the server. */ public func reconnect() { tryReconnectWithReason("manual reconnect") } /** Removes all handlers. Can be used after disconnecting to break any potential remaining retain cycles. */ public func removeAllHandlers() { handlers.removeAll(keepCapacity: false) } private func tryReconnectWithReason(reason: String) { if reconnectTimer == nil { DefaultSocketLogger.Logger.log("Starting reconnect", type: logType) handleEvent("reconnect", data: [reason], isInternalMessage: true) status = .Reconnecting dispatch_async(dispatch_get_main_queue()) { self.reconnectTimer = NSTimer.scheduledTimerWithTimeInterval(Double(self.reconnectWait), target: self, selector: "_tryReconnect", userInfo: nil, repeats: true) } } } @objc private func _tryReconnect() { if status == .Connected { clearReconnectTimer() return } if reconnectAttempts != -1 && currentReconnectAttempt + 1 > reconnectAttempts || !reconnects { clearReconnectTimer() didDisconnect("Reconnect Failed") return } DefaultSocketLogger.Logger.log("Trying to reconnect", type: logType) handleEvent("reconnectAttempt", data: [reconnectAttempts - currentReconnectAttempt], isInternalMessage: true) currentReconnectAttempt += 1 connect() } } // Test extensions extension SocketIOClient { var testHandlers: [SocketEventHandler] { return handlers } func setTestable() { status = .Connected } func setTestEngine(engine: SocketEngineSpec?) { self.engine = engine } func emitTest(event: String, _ data: AnyObject...) { self._emit([event] + data) } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketIOClientOption.swift ================================================ // // SocketIOClientOption .swift // Socket.IO-Client-Swift // // Created by Erik Little on 10/17/15. // // 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. import Foundation protocol ClientOption: CustomStringConvertible, Hashable { func getSocketIOOptionValue() -> AnyObject } public enum SocketIOClientOption: ClientOption { case ConnectParams([String: AnyObject]) case Cookies([NSHTTPCookie]) case ExtraHeaders([String: String]) case ForceNew(Bool) case ForcePolling(Bool) case ForceWebsockets(Bool) case HandleQueue(dispatch_queue_t) case Log(Bool) case Logger(SocketLogger) case Nsp(String) case Path(String) case Reconnects(Bool) case ReconnectAttempts(Int) case ReconnectWait(Int) case Secure(Bool) case SelfSigned(Bool) case SessionDelegate(NSURLSessionDelegate) case VoipEnabled(Bool) public var description: String { let description: String switch self { case .ConnectParams: description = "connectParams" case .Cookies: description = "cookies" case .ExtraHeaders: description = "extraHeaders" case .ForceNew: description = "forceNew" case .ForcePolling: description = "forcePolling" case .ForceWebsockets: description = "forceWebsockets" case .HandleQueue: description = "handleQueue" case .Log: description = "log" case .Logger: description = "logger" case .Nsp: description = "nsp" case .Path: description = "path" case .Reconnects: description = "reconnects" case .ReconnectAttempts: description = "reconnectAttempts" case .ReconnectWait: description = "reconnectWait" case .Secure: description = "secure" case .SelfSigned: description = "selfSigned" case .SessionDelegate: description = "sessionDelegate" case .VoipEnabled: description = "voipEnabled" } return description } public var hashValue: Int { return description.hashValue } func getSocketIOOptionValue() -> AnyObject { let value: AnyObject switch self { case let .ConnectParams(params): value = params case let .Cookies(cookies): value = cookies case let .ExtraHeaders(headers): value = headers case let .ForceNew(force): value = force case let .ForcePolling(force): value = force case let .ForceWebsockets(force): value = force case let .HandleQueue(queue): value = queue case let .Log(log): value = log case let .Logger(logger): value = logger case let .Nsp(nsp): value = nsp case let .Path(path): value = path case let .Reconnects(reconnects): value = reconnects case let .ReconnectAttempts(attempts): value = attempts case let .ReconnectWait(wait): value = wait case let .Secure(secure): value = secure case let .SelfSigned(signed): value = signed case let .SessionDelegate(delegate): value = delegate case let .VoipEnabled(enabled): value = enabled } return value } } public func ==(lhs: SocketIOClientOption, rhs: SocketIOClientOption) -> Bool { return lhs.description == rhs.description } extension Set where Element: ClientOption { mutating func insertIgnore(element: Element) { if !contains(element) { insert(element) } } } extension NSDictionary { static func keyValueToSocketIOClientOption(key: String, value: AnyObject) -> SocketIOClientOption? { switch (key, value) { case let ("connectParams", params as [String: AnyObject]): return .ConnectParams(params) case let ("reconnects", reconnects as Bool): return .Reconnects(reconnects) case let ("reconnectAttempts", attempts as Int): return .ReconnectAttempts(attempts) case let ("reconnectWait", wait as Int): return .ReconnectWait(wait) case let ("forceNew", force as Bool): return .ForceNew(force) case let ("forcePolling", force as Bool): return .ForcePolling(force) case let ("forceWebsockets", force as Bool): return .ForceWebsockets(force) case let ("nsp", nsp as String): return .Nsp(nsp) case let ("cookies", cookies as [NSHTTPCookie]): return .Cookies(cookies) case let ("log", log as Bool): return .Log(log) case let ("logger", logger as SocketLogger): return .Logger(logger) case let ("sessionDelegate", delegate as NSURLSessionDelegate): return .SessionDelegate(delegate) case let ("path", path as String): return .Path(path) case let ("extraHeaders", headers as [String: String]): return .ExtraHeaders(headers) case let ("handleQueue", queue as dispatch_queue_t): return .HandleQueue(queue) case let ("voipEnabled", enable as Bool): return .VoipEnabled(enable) case let ("secure", secure as Bool): return .Secure(secure) case let ("selfSigned", selfSigned as Bool): return .SelfSigned(selfSigned) default: return nil } } func toSocketOptionsSet() -> Set { var options = Set() for (rawKey, value) in self { if let key = rawKey as? String, opt = NSDictionary.keyValueToSocketIOClientOption(key, value: value) { options.insertIgnore(opt) } } return options } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketIOClientStatus.swift ================================================ // // SocketIOClientStatus.swift // Socket.IO-Client-Swift // // Created by Erik Little on 8/14/15. // // 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. import Foundation @objc public enum SocketIOClientStatus: Int, CustomStringConvertible { case NotConnected, Closed, Connecting, Connected, Reconnecting public var description: String { switch self { case NotConnected: return "Not Connected" case Closed: return "Closed" case Connecting: return "Connecting" case Connected: return "Connected" case Reconnecting: return "Reconnecting" } } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketLogger.swift ================================================ // // SocketLogger.swift // Socket.IO-Client-Swift // // Created by Erik Little on 4/11/15. // // 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. import Foundation public protocol SocketLogger: class { /// Whether to log or not var log: Bool {get set} /// Normal log messages func log(message: String, type: String, args: AnyObject...) /// Error Messages func error(message: String, type: String, args: AnyObject...) } public extension SocketLogger { func log(message: String, type: String, args: AnyObject...) { abstractLog("LOG", message: message, type: type, args: args) } func error(message: String, type: String, args: AnyObject...) { abstractLog("ERROR", message: message, type: type, args: args) } private func abstractLog(logType: String, message: String, type: String, args: [AnyObject]) { guard log else { return } let newArgs = args.map({arg -> CVarArgType in String(arg)}) let replaced = String(format: message, arguments: newArgs) NSLog("%@ %@: %@", logType, type, replaced) } } class DefaultSocketLogger: SocketLogger { static var Logger: SocketLogger = DefaultSocketLogger() var log = false } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketPacket.swift ================================================ // // SocketPacket.swift // Socket.IO-Client-Swift // // Created by Erik Little on 1/18/15. // // 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. // import Foundation struct SocketPacket { private let placeholders: Int private static let logType = "SocketPacket" let nsp: String let id: Int let type: PacketType enum PacketType: Int { case Connect, Disconnect, Event, Ack, Error, BinaryEvent, BinaryAck } var args: [AnyObject] { if type == .Event || type == .BinaryEvent && data.count != 0 { return Array(data.dropFirst()) } else { return data } } var binary: [NSData] var data: [AnyObject] var description: String { return "SocketPacket {type: \(String(type.rawValue)); data: " + "\(String(data)); id: \(id); placeholders: \(placeholders); nsp: \(nsp)}" } var event: String { return String(data[0]) } var packetString: String { return createPacketString() } init(type: SocketPacket.PacketType, data: [AnyObject] = [AnyObject](), id: Int = -1, nsp: String, placeholders: Int = 0, binary: [NSData] = [NSData]()) { self.data = data self.id = id self.nsp = nsp self.type = type self.placeholders = placeholders self.binary = binary } mutating func addData(data: NSData) -> Bool { if placeholders == binary.count { return true } binary.append(data) if placeholders == binary.count { fillInPlaceholders() return true } else { return false } } private func completeMessage(message: String, ack: Bool) -> String { var restOfMessage = "" if data.count == 0 { return message + "]" } for arg in data { if arg is NSDictionary || arg is [AnyObject] { do { let jsonSend = try NSJSONSerialization.dataWithJSONObject(arg, options: NSJSONWritingOptions(rawValue: 0)) let jsonString = String(data: jsonSend, encoding: NSUTF8StringEncoding) restOfMessage += jsonString! + "," } catch { DefaultSocketLogger.Logger.error("Error creating JSON object in SocketPacket.completeMessage", type: SocketPacket.logType) } } else if let str = arg as? String { restOfMessage += "\"" + ((str["\n"] <~ "\\\\n")["\r"] <~ "\\\\r") + "\"," } else if arg is NSNull { restOfMessage += "null," } else { restOfMessage += "\(arg)," } } if restOfMessage != "" { restOfMessage.removeAtIndex(restOfMessage.endIndex.predecessor()) } return message + restOfMessage + "]" } private func createAck() -> String { let message: String if type == .Ack { if nsp == "/" { message = "3\(id)[" } else { message = "3\(nsp),\(id)[" } } else { if nsp == "/" { message = "6\(binary.count)-\(id)[" } else { message = "6\(binary.count)-\(nsp),\(id)[" } } return completeMessage(message, ack: true) } private func createMessageForEvent() -> String { let message: String if type == .Event { if nsp == "/" { if id == -1 { message = "2[" } else { message = "2\(id)[" } } else { if id == -1 { message = "2\(nsp),[" } else { message = "2\(nsp),\(id)[" } } } else { if nsp == "/" { if id == -1 { message = "5\(binary.count)-[" } else { message = "5\(binary.count)-\(id)[" } } else { if id == -1 { message = "5\(binary.count)-\(nsp),[" } else { message = "5\(binary.count)-\(nsp),\(id)[" } } } return completeMessage(message, ack: false) } private func createPacketString() -> String { let str: String if type == .Event || type == .BinaryEvent { str = createMessageForEvent() } else { str = createAck() } return str } // Called when we have all the binary data for a packet // calls _fillInPlaceholders, which replaces placeholders with the // corresponding binary private mutating func fillInPlaceholders() { data = data.map(_fillInPlaceholders) } // Helper method that looks for placeholder strings // If object is a collection it will recurse // Returns the object if it is not a placeholder string or the corresponding // binary data private func _fillInPlaceholders(object: AnyObject) -> AnyObject { switch object { case let string as String where string["~~(\\d)"].groups() != nil: return binary[Int(string["~~(\\d)"].groups()![1])!] case let dict as NSDictionary: return dict.reduce(NSMutableDictionary(), combine: {cur, keyValue in cur[keyValue.0 as! NSCopying] = _fillInPlaceholders(keyValue.1) return cur }) case let arr as [AnyObject]: return arr.map(_fillInPlaceholders) default: return object } } } extension SocketPacket { private static func findType(binCount: Int, ack: Bool) -> PacketType { switch binCount { case 0 where !ack: return .Event case 0 where ack: return .Ack case _ where !ack: return .BinaryEvent case _ where ack: return .BinaryAck default: return .Error } } static func packetFromEmit(items: [AnyObject], id: Int, nsp: String, ack: Bool) -> SocketPacket { let (parsedData, binary) = deconstructData(items) let packet = SocketPacket(type: findType(binary.count, ack: ack), data: parsedData, id: id, nsp: nsp, placeholders: -1, binary: binary) return packet } } private extension SocketPacket { // Recursive function that looks for NSData in collections static func shred(data: AnyObject, inout binary: [NSData]) -> AnyObject { let placeholder = ["_placeholder": true, "num": binary.count] switch data { case let bin as NSData: binary.append(bin) return placeholder case let arr as [AnyObject]: return arr.map({shred($0, binary: &binary)}) case let dict as NSDictionary: return dict.reduce(NSMutableDictionary(), combine: {cur, keyValue in cur[keyValue.0 as! NSCopying] = shred(keyValue.1, binary: &binary) return cur }) default: return data } } // Removes binary data from emit data // Returns a type containing the de-binaryed data and the binary static func deconstructData(data: [AnyObject]) -> ([AnyObject], [NSData]) { var binary = [NSData]() return (data.map({shred($0, binary: &binary)}), binary) } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketParsable.swift ================================================ // // SocketParsable.swift // Socket.IO-Client-Swift // // 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. import Foundation protocol SocketParsable: SocketClientSpec { func parseBinaryData(data: NSData) func parseSocketMessage(message: String) } extension SocketParsable { private func isCorrectNamespace(nsp: String) -> Bool { return nsp == self.nsp } private func handleConnect(p: SocketPacket) { if p.nsp == "/" && nsp != "/" { joinNamespace(nsp) } else if p.nsp != "/" && nsp == "/" { didConnect() } else { didConnect() } } private func handlePacket(pack: SocketPacket) { switch pack.type { case .Event where isCorrectNamespace(pack.nsp): handleEvent(pack.event, data: pack.args, isInternalMessage: false, withAck: pack.id) case .Ack where isCorrectNamespace(pack.nsp): handleAck(pack.id, data: pack.data) case .BinaryEvent where isCorrectNamespace(pack.nsp): waitingData.append(pack) case .BinaryAck where isCorrectNamespace(pack.nsp): waitingData.append(pack) case .Connect: handleConnect(pack) case .Disconnect: didDisconnect("Got Disconnect") case .Error: handleEvent("error", data: pack.data, isInternalMessage: true, withAck: pack.id) default: DefaultSocketLogger.Logger.log("Got invalid packet: %@", type: "SocketParser", args: pack.description) } } /// Parses a messsage from the engine. Returning either a string error or a complete SocketPacket func parseString(message: String) -> Either { var parser = SocketStringReader(message: message) guard let type = SocketPacket.PacketType(rawValue: Int(parser.read(1)) ?? -1) else { return .Left("Invalid packet type") } if !parser.hasNext { return .Right(SocketPacket(type: type, nsp: "/")) } var namespace: String? var placeholders = -1 if type == .BinaryEvent || type == .BinaryAck { if let holders = Int(parser.readUntilStringOccurence("-")) { placeholders = holders } else { return .Left("Invalid packet") } } if parser.currentCharacter == "/" { namespace = parser.readUntilStringOccurence(",") ?? parser.readUntilEnd() } if !parser.hasNext { return .Right(SocketPacket(type: type, id: -1, nsp: namespace ?? "/", placeholders: placeholders)) } var idString = "" if type == .Error { parser.advanceIndexBy(-1) } while parser.hasNext && type != .Error { if let int = Int(parser.read(1)) { idString += String(int) } else { parser.advanceIndexBy(-2) break } } let d = message[parser.currentIndex.advancedBy(1).. Either { let stringData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) do { if let arr = try NSJSONSerialization.JSONObjectWithData(stringData!, options: NSJSONReadingOptions.MutableContainers) as? [AnyObject] { return .Right(arr) } else { return .Left("Expected data array") } } catch { return .Left("Error parsing data for packet") } } // Parses messages recieved func parseSocketMessage(message: String) { guard !message.isEmpty else { return } DefaultSocketLogger.Logger.log("Parsing %@", type: "SocketParser", args: message) switch parseString(message) { case let .Left(err): DefaultSocketLogger.Logger.error("\(err): %@", type: "SocketParser", args: message) case let .Right(pack): DefaultSocketLogger.Logger.log("Decoded packet as: %@", type: "SocketParser", args: pack.description) handlePacket(pack) } } func parseBinaryData(data: NSData) { guard !waitingData.isEmpty else { DefaultSocketLogger.Logger.error("Got data when not remaking packet", type: "SocketParser") return } // Should execute event? guard waitingData[waitingData.count - 1].addData(data) else { return } let packet = waitingData.removeLast() if packet.type != .BinaryAck { handleEvent(packet.event, data: packet.args ?? [], isInternalMessage: false, withAck: packet.id) } else { handleAck(packet.id, data: packet.args) } } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketStringReader.swift ================================================ // // SocketStringReader.swift // Socket.IO-Client-Swift // // Created by Lukas Schmidt on 07.09.15. // // 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. struct SocketStringReader { let message: String var currentIndex: String.Index var hasNext: Bool { return currentIndex != message.endIndex } var currentCharacter: String { return String(message[currentIndex]) } init(message: String) { self.message = message currentIndex = message.startIndex } mutating func advanceIndexBy(n: Int) { currentIndex = currentIndex.advancedBy(n) } mutating func read(readLength: Int) -> String { let readString = message[currentIndex.. String { let substring = message[currentIndex.. String { return read(currentIndex.distanceTo(message.endIndex)) } } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SocketTypes.swift ================================================ // // SocketTypes.swift // Socket.IO-Client-Swift // // Created by Erik Little on 4/8/15. // // 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. import Foundation public typealias AckCallback = ([AnyObject]) -> Void public typealias NormalCallback = ([AnyObject], SocketAckEmitter) -> Void public typealias OnAckCallback = (timeoutAfter: UInt64, callback: AckCallback) -> Void enum Either { case Left(E) case Right(V) } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/SwiftRegex.swift ================================================ // // SwiftRegex.swift // SwiftRegex // // Created by John Holdsworth on 26/06/2014. // Copyright (c) 2014 John Holdsworth. // // $Id: //depot/SwiftRegex/SwiftRegex.swift#37 $ // // This code is in the public domain from: // https://github.com/johnno1962/SwiftRegex // import Foundation infix operator <~ { associativity none precedence 130 } private let lock = dispatch_semaphore_create(1) private var swiftRegexCache = [String: NSRegularExpression]() internal final class SwiftRegex: NSObject, BooleanType { var target:String var regex: NSRegularExpression init(target:String, pattern:String, options:NSRegularExpressionOptions?) { self.target = target if dispatch_semaphore_wait(lock, dispatch_time(DISPATCH_TIME_NOW, Int64(10 * NSEC_PER_MSEC))) != 0 { do { let regex = try NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions.DotMatchesLineSeparators) self.regex = regex } catch let error as NSError { SwiftRegex.failure("Error in pattern: \(pattern) - \(error)") self.regex = NSRegularExpression() } super.init() return } if let regex = swiftRegexCache[pattern] { self.regex = regex } else { do { let regex = try NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions.DotMatchesLineSeparators) swiftRegexCache[pattern] = regex self.regex = regex } catch let error as NSError { SwiftRegex.failure("Error in pattern: \(pattern) - \(error)") self.regex = NSRegularExpression() } } dispatch_semaphore_signal(lock) super.init() } private static func failure(message: String) { fatalError("SwiftRegex: \(message)") } private var targetRange: NSRange { return NSRange(location: 0,length: target.utf16.count) } private func substring(range: NSRange) -> String? { if range.location != NSNotFound { return (target as NSString).substringWithRange(range) } else { return nil } } func doesMatch(options: NSMatchingOptions!) -> Bool { return range(options).location != NSNotFound } func range(options: NSMatchingOptions) -> NSRange { return regex.rangeOfFirstMatchInString(target as String, options: [], range: targetRange) } func match(options: NSMatchingOptions) -> String? { return substring(range(options)) } func groups() -> [String]? { return groupsForMatch(regex.firstMatchInString(target as String, options: NSMatchingOptions.WithoutAnchoringBounds, range: targetRange)) } private func groupsForMatch(match: NSTextCheckingResult?) -> [String]? { guard let match = match else { return nil } var groups = [String]() for groupno in 0...regex.numberOfCaptureGroups { if let group = substring(match.rangeAtIndex(groupno)) { groups += [group] } else { groups += ["_"] // avoids bridging problems } } return groups } subscript(groupno: Int) -> String? { get { return groups()?[groupno] } set(newValue) { if newValue == nil { return } for match in Array(matchResults().reverse()) { let replacement = regex.replacementStringForResult(match, inString: target as String, offset: 0, template: newValue!) let mut = NSMutableString(string: target) mut.replaceCharactersInRange(match.rangeAtIndex(groupno), withString: replacement) target = mut as String } } } func matchResults() -> [NSTextCheckingResult] { let matches = regex.matchesInString(target as String, options: NSMatchingOptions.WithoutAnchoringBounds, range: targetRange) as [NSTextCheckingResult] return matches } func ranges() -> [NSRange] { return matchResults().map { $0.range } } func matches() -> [String] { return matchResults().map( { self.substring($0.range)!}) } func allGroups() -> [[String]?] { return matchResults().map { self.groupsForMatch($0) } } func dictionary(options: NSMatchingOptions!) -> Dictionary { var out = Dictionary() for match in matchResults() { out[substring(match.rangeAtIndex(1))!] = substring(match.rangeAtIndex(2))! } return out } func substituteMatches(substitution: ((NSTextCheckingResult, UnsafeMutablePointer) -> String), options:NSMatchingOptions) -> String { let out = NSMutableString() var pos = 0 regex.enumerateMatchesInString(target as String, options: options, range: targetRange ) {match, flags, stop in let matchRange = match!.range out.appendString( self.substring(NSRange(location:pos, length:matchRange.location-pos))!) out.appendString( substitution(match!, stop) ) pos = matchRange.location + matchRange.length } out.appendString(substring(NSRange(location:pos, length:targetRange.length-pos))!) return out as String } var boolValue: Bool { return doesMatch(nil) } } extension String { subscript(pattern: String, options: NSRegularExpressionOptions) -> SwiftRegex { return SwiftRegex(target: self, pattern: pattern, options: options) } } extension String { subscript(pattern: String) -> SwiftRegex { return SwiftRegex(target: self, pattern: pattern, options: nil) } } func <~ (left: SwiftRegex, right: String) -> String { return left.substituteMatches({match, stop in return left.regex.replacementStringForResult( match, inString: left.target as String, offset: 0, template: right ) }, options: []) } ================================================ FILE: Carthage/Checkouts/socket.io-client-swift/Source/WebSocket.swift ================================================ ////////////////////////////////////////////////////////////////////////////////////////////////// // // Websocket.swift // // Created by Dalton Cherry on 7/16/14. // Copyright (c) 2014-2015 Dalton Cherry. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ////////////////////////////////////////////////////////////////////////////////////////////////// import Foundation import CoreFoundation import Security public protocol WebSocketDelegate: class { func websocketDidConnect(socket: WebSocket) func websocketDidDisconnect(socket: WebSocket, error: NSError?) func websocketDidReceiveMessage(socket: WebSocket, text: String) func websocketDidReceiveData(socket: WebSocket, data: NSData) } public protocol WebSocketPongDelegate: class { func websocketDidReceivePong(socket: WebSocket) } public class WebSocket : NSObject, NSStreamDelegate { enum OpCode : UInt8 { case ContinueFrame = 0x0 case TextFrame = 0x1 case BinaryFrame = 0x2 //3-7 are reserved. case ConnectionClose = 0x8 case Ping = 0x9 case Pong = 0xA //B-F reserved. } public enum CloseCode : UInt16 { case Normal = 1000 case GoingAway = 1001 case ProtocolError = 1002 case ProtocolUnhandledType = 1003 // 1004 reserved. case NoStatusReceived = 1005 //1006 reserved. case Encoding = 1007 case PolicyViolated = 1008 case MessageTooBig = 1009 } public static let ErrorDomain = "WebSocket" enum InternalErrorCode : UInt16 { // 0-999 WebSocket status codes not used case OutputStreamWriteError = 1 } //Where the callback is executed. It defaults to the main UI thread queue. public var queue = dispatch_get_main_queue() var optionalProtocols : [String]? //Constant Values. let headerWSUpgradeName = "Upgrade" let headerWSUpgradeValue = "websocket" let headerWSHostName = "Host" let headerWSConnectionName = "Connection" let headerWSConnectionValue = "Upgrade" let headerWSProtocolName = "Sec-WebSocket-Protocol" let headerWSVersionName = "Sec-WebSocket-Version" let headerWSVersionValue = "13" let headerWSKeyName = "Sec-WebSocket-Key" let headerOriginName = "Origin" let headerWSAcceptName = "Sec-WebSocket-Accept" let BUFFER_MAX = 4096 let FinMask: UInt8 = 0x80 let OpCodeMask: UInt8 = 0x0F let RSVMask: UInt8 = 0x70 let MaskMask: UInt8 = 0x80 let PayloadLenMask: UInt8 = 0x7F let MaxFrameSize: Int = 32 class WSResponse { var isFin = false var code: OpCode = .ContinueFrame var bytesLeft = 0 var frameCount = 0 var buffer: NSMutableData? } public weak var delegate: WebSocketDelegate? public weak var pongDelegate: WebSocketPongDelegate? public var onConnect: ((Void) -> Void)? public var onDisconnect: ((NSError?) -> Void)? public var onText: ((String) -> Void)? public var onData: ((NSData) -> Void)? public var onPong: ((Void) -> Void)? public var headers = [String: String]() public var voipEnabled = false public var selfSignedSSL = false private var security: SSLSecurity? public var enabledSSLCipherSuites: [SSLCipherSuite]? public var origin: String? public var isConnected :Bool { return connected } public var currentURL: NSURL {return url} private var url: NSURL private var inputStream: NSInputStream? private var outputStream: NSOutputStream? private var connected = false private var isCreated = false private var writeQueue = NSOperationQueue() private var readStack = [WSResponse]() private var inputQueue = [NSData]() private var fragBuffer: NSData? private var certValidated = false private var didDisconnect = false private var readyToWrite = false private let mutex = NSLock() private var canDispatch: Bool { mutex.lock() let canWork = readyToWrite mutex.unlock() return canWork } //the shared processing queue used for all websocket private static let sharedWorkQueue = dispatch_queue_create("com.vluxe.starscream.websocket", DISPATCH_QUEUE_SERIAL) //used for setting protocols. public init(url: NSURL, protocols: [String]? = nil) { self.url = url self.origin = url.absoluteString writeQueue.maxConcurrentOperationCount = 1 optionalProtocols = protocols } ///Connect to the websocket server on a background thread public func connect() { guard !isCreated else { return } didDisconnect = false isCreated = true createHTTPRequest() isCreated = false } /** Disconnect from the server. I send a Close control frame to the server, then expect the server to respond with a Close control frame and close the socket from its end. I notify my delegate once the socket has been closed. If you supply a non-nil `forceTimeout`, I wait at most that long (in seconds) for the server to close the socket. After the timeout expires, I close the socket and notify my delegate. If you supply a zero (or negative) `forceTimeout`, I immediately close the socket (without sending a Close control frame) and notify my delegate. - Parameter forceTimeout: Maximum time to wait for the server to close the socket. */ public func disconnect(forceTimeout forceTimeout: NSTimeInterval? = nil) { switch forceTimeout { case .Some(let seconds) where seconds > 0: dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(seconds * Double(NSEC_PER_SEC))), queue) { [unowned self] in self.disconnectStream(nil) } fallthrough case .None: writeError(CloseCode.Normal.rawValue) default: self.disconnectStream(nil) break } } ///write a string to the websocket. This sends it as a text frame. public func writeString(str: String) { guard isConnected else { return } dequeueWrite(str.dataUsingEncoding(NSUTF8StringEncoding)!, code: .TextFrame) } ///write binary data to the websocket. This sends it as a binary frame. public func writeData(data: NSData) { guard isConnected else { return } dequeueWrite(data, code: .BinaryFrame) } //write a ping to the websocket. This sends it as a control frame. //yodel a sound to the planet. This sends it as an astroid. http://youtu.be/Eu5ZJELRiJ8?t=42s public func writePing(data: NSData) { guard isConnected else { return } dequeueWrite(data, code: .Ping) } //private method that starts the connection private func createHTTPRequest() { let urlRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, "GET", url, kCFHTTPVersion1_1).takeRetainedValue() var port = url.port if port == nil { if ["wss", "https"].contains(url.scheme) { port = 443 } else { port = 80 } } addHeader(urlRequest, key: headerWSUpgradeName, val: headerWSUpgradeValue) addHeader(urlRequest, key: headerWSConnectionName, val: headerWSConnectionValue) if let protocols = optionalProtocols { addHeader(urlRequest, key: headerWSProtocolName, val: protocols.joinWithSeparator(",")) } addHeader(urlRequest, key: headerWSVersionName, val: headerWSVersionValue) addHeader(urlRequest, key: headerWSKeyName, val: generateWebSocketKey()) if let origin = origin { addHeader(urlRequest, key: headerOriginName, val: origin) } addHeader(urlRequest, key: headerWSHostName, val: "\(url.host!):\(port!)") for (key,value) in headers { addHeader(urlRequest, key: key, val: value) } if let cfHTTPMessage = CFHTTPMessageCopySerializedMessage(urlRequest) { let serializedRequest = cfHTTPMessage.takeRetainedValue() initStreamsWithData(serializedRequest, Int(port!)) } } //Add a header to the CFHTTPMessage by using the NSString bridges to CFString private func addHeader(urlRequest: CFHTTPMessage, key: NSString, val: NSString) { CFHTTPMessageSetHeaderFieldValue(urlRequest, key, val) } //generate a websocket key as needed in rfc private func generateWebSocketKey() -> String { var key = "" let seed = 16 for _ in 0..? var writeStream: Unmanaged? let h: NSString = url.host! CFStreamCreatePairWithSocketToHost(nil, h, UInt32(port), &readStream, &writeStream) inputStream = readStream!.takeRetainedValue() outputStream = writeStream!.takeRetainedValue() guard let inStream = inputStream, let outStream = outputStream else { return } inStream.delegate = self outStream.delegate = self if ["wss", "https"].contains(url.scheme) { inStream.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL, forKey: NSStreamSocketSecurityLevelKey) outStream.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL, forKey: NSStreamSocketSecurityLevelKey) } else { certValidated = true //not a https session, so no need to check SSL pinning } if voipEnabled { inStream.setProperty(NSStreamNetworkServiceTypeVoIP, forKey: NSStreamNetworkServiceType) outStream.setProperty(NSStreamNetworkServiceTypeVoIP, forKey: NSStreamNetworkServiceType) } if selfSignedSSL { let settings: [NSObject: NSObject] = [kCFStreamSSLValidatesCertificateChain: NSNumber(bool:false), kCFStreamSSLPeerName: kCFNull] inStream.setProperty(settings, forKey: kCFStreamPropertySSLSettings as String) outStream.setProperty(settings, forKey: kCFStreamPropertySSLSettings as String) } if let cipherSuites = self.enabledSSLCipherSuites { if let sslContextIn = CFReadStreamCopyProperty(inputStream, kCFStreamPropertySSLContext) as! SSLContextRef?, sslContextOut = CFWriteStreamCopyProperty(outputStream, kCFStreamPropertySSLContext) as! SSLContextRef? { let resIn = SSLSetEnabledCiphers(sslContextIn, cipherSuites, cipherSuites.count) let resOut = SSLSetEnabledCiphers(sslContextOut, cipherSuites, cipherSuites.count) if resIn != errSecSuccess { let error = self.errorWithDetail("Error setting ingoing cypher suites", code: UInt16(resIn)) disconnectStream(error) return } if resOut != errSecSuccess { let error = self.errorWithDetail("Error setting outgoing cypher suites", code: UInt16(resOut)) disconnectStream(error) return } } } CFReadStreamSetDispatchQueue(inStream, WebSocket.sharedWorkQueue) CFWriteStreamSetDispatchQueue(outStream, WebSocket.sharedWorkQueue) inStream.open() outStream.open() self.mutex.lock() self.readyToWrite = true self.mutex.unlock() let bytes = UnsafePointer(data.bytes) var timeout = 5000000 //wait 5 seconds before giving up writeQueue.addOperationWithBlock { [weak self] in guard let this = self else { return } while !outStream.hasSpaceAvailable { usleep(100) //wait until the socket is ready timeout -= 100 if timeout < 0 { this.cleanupStream() this.doDisconnect(this.errorWithDetail("write wait timed out", code: 2)) return } else if outStream.streamError != nil { return //disconnectStream will be called. } } outStream.write(bytes, maxLength: data.length) } } //delegate for the stream methods. Processes incoming bytes public func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) { if let sec = security where !certValidated && [.HasBytesAvailable, .HasSpaceAvailable].contains(eventCode) { let possibleTrust: AnyObject? = aStream.propertyForKey(kCFStreamPropertySSLPeerTrust as String) if let trust: AnyObject = possibleTrust { let domain: AnyObject? = aStream.propertyForKey(kCFStreamSSLPeerName as String) if sec.isValid(trust as! SecTrustRef, domain: domain as! String?) { certValidated = true } else { let error = errorWithDetail("Invalid SSL certificate", code: 1) disconnectStream(error) return } } } if eventCode == .HasBytesAvailable { if aStream == inputStream { processInputStream() } } else if eventCode == .ErrorOccurred { disconnectStream(aStream.streamError) } else if eventCode == .EndEncountered { disconnectStream(nil) } } //disconnect the stream object private func disconnectStream(error: NSError?) { writeQueue.waitUntilAllOperationsAreFinished() cleanupStream() doDisconnect(error) } private func cleanupStream() { outputStream?.delegate = nil inputStream?.delegate = nil if let stream = inputStream { CFReadStreamSetDispatchQueue(stream, nil) stream.close() } if let stream = outputStream { CFWriteStreamSetDispatchQueue(stream, nil) stream.close() } outputStream = nil inputStream = nil } ///handles the incoming bytes and sending them to the proper processing method private func processInputStream() { let buf = NSMutableData(capacity: BUFFER_MAX) let buffer = UnsafeMutablePointer(buf!.bytes) let length = inputStream!.read(buffer, maxLength: BUFFER_MAX) guard length > 0 else { return } var process = false if inputQueue.count == 0 { process = true } inputQueue.append(NSData(bytes: buffer, length: length)) if process { dequeueInput() } } ///dequeue the incoming input so it is processed in order private func dequeueInput() { guard !inputQueue.isEmpty else { return } let data = inputQueue[0] var work = data if let fragBuffer = fragBuffer { let combine = NSMutableData(data: fragBuffer) combine.appendData(data) work = combine self.fragBuffer = nil } let buffer = UnsafePointer(work.bytes) let length = work.length if !connected { processTCPHandshake(buffer, bufferLen: length) } else { processRawMessage(buffer, bufferLen: length) } inputQueue = inputQueue.filter{$0 != data} dequeueInput() } //handle checking the inital connection status private func processTCPHandshake(buffer: UnsafePointer, bufferLen: Int) { let code = processHTTP(buffer, bufferLen: bufferLen) switch code { case 0: connected = true guard canDispatch else {return} dispatch_async(queue) { [weak self] in guard let s = self else { return } s.onConnect?() s.delegate?.websocketDidConnect(s) } case -1: fragBuffer = NSData(bytes: buffer, length: bufferLen) break //do nothing, we are going to collect more data default: doDisconnect(errorWithDetail("Invalid HTTP upgrade", code: UInt16(code))) } } ///Finds the HTTP Packet in the TCP stream, by looking for the CRLF. private func processHTTP(buffer: UnsafePointer, bufferLen: Int) -> Int { let CRLFBytes = [UInt8(ascii: "\r"), UInt8(ascii: "\n"), UInt8(ascii: "\r"), UInt8(ascii: "\n")] var k = 0 var totalSize = 0 for i in 0.. 0 { let code = validateResponse(buffer, bufferLen: totalSize) if code != 0 { return code } totalSize += 1 //skip the last \n let restSize = bufferLen - totalSize if restSize > 0 { processRawMessage((buffer+totalSize),bufferLen: restSize) } return 0 //success } return -1 //was unable to find the full TCP header } ///validates the HTTP is a 101 as per the RFC spec private func validateResponse(buffer: UnsafePointer, bufferLen: Int) -> Int { let response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false).takeRetainedValue() CFHTTPMessageAppendBytes(response, buffer, bufferLen) let code = CFHTTPMessageGetResponseStatusCode(response) if code != 101 { return code } if let cfHeaders = CFHTTPMessageCopyAllHeaderFields(response) { let headers = cfHeaders.takeRetainedValue() as NSDictionary if let acceptKey = headers[headerWSAcceptName] as? NSString { if acceptKey.length > 0 { return 0 } } } return -1 } ///read a 16 bit big endian value from a buffer private static func readUint16(buffer: UnsafePointer, offset: Int) -> UInt16 { return (UInt16(buffer[offset + 0]) << 8) | UInt16(buffer[offset + 1]) } ///read a 64 bit big endian value from a buffer private static func readUint64(buffer: UnsafePointer, offset: Int) -> UInt64 { var value = UInt64(0) for i in 0...7 { value = (value << 8) | UInt64(buffer[offset + i]) } return value } ///write a 16 bit big endian value to a buffer private static func writeUint16(buffer: UnsafeMutablePointer, offset: Int, value: UInt16) { buffer[offset + 0] = UInt8(value >> 8) buffer[offset + 1] = UInt8(value & 0xff) } ///write a 64 bit big endian value to a buffer private static func writeUint64(buffer: UnsafeMutablePointer, offset: Int, value: UInt64) { for i in 0...7 { buffer[offset + i] = UInt8((value >> (8*UInt64(7 - i))) & 0xff) } } ///process the websocket data private func processRawMessage(buffer: UnsafePointer, bufferLen: Int) { let response = readStack.last if response != nil && bufferLen < 2 { fragBuffer = NSData(bytes: buffer, length: bufferLen) return } if let response = response where response.bytesLeft > 0 { var len = response.bytesLeft var extra = bufferLen - response.bytesLeft if response.bytesLeft > bufferLen { len = bufferLen extra = 0 } response.bytesLeft -= len response.buffer?.appendData(NSData(bytes: buffer, length: len)) processResponse(response) let offset = bufferLen - extra if extra > 0 { processExtra((buffer+offset), bufferLen: extra) } return } else { let isFin = (FinMask & buffer[0]) let receivedOpcode = OpCode(rawValue: (OpCodeMask & buffer[0])) let isMasked = (MaskMask & buffer[1]) let payloadLen = (PayloadLenMask & buffer[1]) var offset = 2 if (isMasked > 0 || (RSVMask & buffer[0]) > 0) && receivedOpcode != .Pong { let errCode = CloseCode.ProtocolError.rawValue doDisconnect(errorWithDetail("masked and rsv data is not currently supported", code: errCode)) writeError(errCode) return } let isControlFrame = (receivedOpcode == .ConnectionClose || receivedOpcode == .Ping) if !isControlFrame && (receivedOpcode != .BinaryFrame && receivedOpcode != .ContinueFrame && receivedOpcode != .TextFrame && receivedOpcode != .Pong) { let errCode = CloseCode.ProtocolError.rawValue doDisconnect(errorWithDetail("unknown opcode: \(receivedOpcode)", code: errCode)) writeError(errCode) return } if isControlFrame && isFin == 0 { let errCode = CloseCode.ProtocolError.rawValue doDisconnect(errorWithDetail("control frames can't be fragmented", code: errCode)) writeError(errCode) return } if receivedOpcode == .ConnectionClose { var code = CloseCode.Normal.rawValue if payloadLen == 1 { code = CloseCode.ProtocolError.rawValue } else if payloadLen > 1 { code = WebSocket.readUint16(buffer, offset: offset) if code < 1000 || (code > 1003 && code < 1007) || (code > 1011 && code < 3000) { code = CloseCode.ProtocolError.rawValue } offset += 2 } if payloadLen > 2 { let len = Int(payloadLen-2) if len > 0 { let bytes = UnsafePointer((buffer+offset)) let str: NSString? = NSString(data: NSData(bytes: bytes, length: len), encoding: NSUTF8StringEncoding) if str == nil { code = CloseCode.ProtocolError.rawValue } } } doDisconnect(errorWithDetail("connection closed by server", code: code)) writeError(code) return } if isControlFrame && payloadLen > 125 { writeError(CloseCode.ProtocolError.rawValue) return } var dataLength = UInt64(payloadLen) if dataLength == 127 { dataLength = WebSocket.readUint64(buffer, offset: offset) offset += sizeof(UInt64) } else if dataLength == 126 { dataLength = UInt64(WebSocket.readUint16(buffer, offset: offset)) offset += sizeof(UInt16) } if bufferLen < offset || UInt64(bufferLen - offset) < dataLength { fragBuffer = NSData(bytes: buffer, length: bufferLen) return } var len = dataLength if dataLength > UInt64(bufferLen) { len = UInt64(bufferLen-offset) } var data: NSData! if len < 0 { len = 0 data = NSData() } else { data = NSData(bytes: UnsafePointer((buffer+offset)), length: Int(len)) } if receivedOpcode == .Pong { if canDispatch { dispatch_async(queue) { [weak self] in guard let s = self else { return } s.onPong?() s.pongDelegate?.websocketDidReceivePong(s) } } let step = Int(offset+numericCast(len)) let extra = bufferLen-step if extra > 0 { processRawMessage((buffer+step), bufferLen: extra) } return } var response = readStack.last if isControlFrame { response = nil //don't append pings } if isFin == 0 && receivedOpcode == .ContinueFrame && response == nil { let errCode = CloseCode.ProtocolError.rawValue doDisconnect(errorWithDetail("continue frame before a binary or text frame", code: errCode)) writeError(errCode) return } var isNew = false if response == nil { if receivedOpcode == .ContinueFrame { let errCode = CloseCode.ProtocolError.rawValue doDisconnect(errorWithDetail("first frame can't be a continue frame", code: errCode)) writeError(errCode) return } isNew = true response = WSResponse() response!.code = receivedOpcode! response!.bytesLeft = Int(dataLength) response!.buffer = NSMutableData(data: data) } else { if receivedOpcode == .ContinueFrame { response!.bytesLeft = Int(dataLength) } else { let errCode = CloseCode.ProtocolError.rawValue doDisconnect(errorWithDetail("second and beyond of fragment message must be a continue frame", code: errCode)) writeError(errCode) return } response!.buffer!.appendData(data) } if let response = response { response.bytesLeft -= Int(len) response.frameCount++ response.isFin = isFin > 0 ? true : false if isNew { readStack.append(response) } processResponse(response) } let step = Int(offset+numericCast(len)) let extra = bufferLen-step if extra > 0 { processExtra((buffer+step), bufferLen: extra) } } } ///process the extra of a buffer private func processExtra(buffer: UnsafePointer, bufferLen: Int) { if bufferLen < 2 { fragBuffer = NSData(bytes: buffer, length: bufferLen) } else { processRawMessage(buffer, bufferLen: bufferLen) } } ///process the finished response of a buffer private func processResponse(response: WSResponse) -> Bool { if response.isFin && response.bytesLeft <= 0 { if response.code == .Ping { let data = response.buffer! //local copy so it is perverse for writing dequeueWrite(data, code: OpCode.Pong) } else if response.code == .TextFrame { let str: NSString? = NSString(data: response.buffer!, encoding: NSUTF8StringEncoding) if str == nil { writeError(CloseCode.Encoding.rawValue) return false } if canDispatch { dispatch_async(queue) { [weak self] in guard let s = self else { return } s.onText?(str! as String) s.delegate?.websocketDidReceiveMessage(s, text: str! as String) } } } else if response.code == .BinaryFrame { if canDispatch { let data = response.buffer! //local copy so it is perverse for writing dispatch_async(queue) { [weak self] in guard let s = self else { return } s.onData?(data) s.delegate?.websocketDidReceiveData(s, data: data) } } } readStack.removeLast() return true } return false } ///Create an error private func errorWithDetail(detail: String, code: UInt16) -> NSError { var details = [String: String]() details[NSLocalizedDescriptionKey] = detail return NSError(domain: WebSocket.ErrorDomain, code: Int(code), userInfo: details) } ///write a an error to the socket private func writeError(code: UInt16) { let buf = NSMutableData(capacity: sizeof(UInt16)) let buffer = UnsafeMutablePointer(buf!.bytes) WebSocket.writeUint16(buffer, offset: 0, value: code) dequeueWrite(NSData(bytes: buffer, length: sizeof(UInt16)), code: .ConnectionClose) } ///used to write things to the stream private func dequeueWrite(data: NSData, code: OpCode) { writeQueue.addOperationWithBlock { [weak self] in //stream isn't ready, let's wait guard let s = self else { return } var offset = 2 let bytes = UnsafeMutablePointer(data.bytes) let dataLength = data.length let frame = NSMutableData(capacity: dataLength + s.MaxFrameSize) let buffer = UnsafeMutablePointer(frame!.mutableBytes) buffer[0] = s.FinMask | code.rawValue if dataLength < 126 { buffer[1] = CUnsignedChar(dataLength) } else if dataLength <= Int(UInt16.max) { buffer[1] = 126 WebSocket.writeUint16(buffer, offset: offset, value: UInt16(dataLength)) offset += sizeof(UInt16) } else { buffer[1] = 127 WebSocket.writeUint64(buffer, offset: offset, value: UInt64(dataLength)) offset += sizeof(UInt64) } buffer[1] |= s.MaskMask let maskKey = UnsafeMutablePointer(buffer + offset) SecRandomCopyBytes(kSecRandomDefault, Int(sizeof(UInt32)), maskKey) offset += sizeof(UInt32) for i in 0..(frame!.bytes+total) let len = outStream.write(writeBuffer, maxLength: offset-total) if len < 0 { var error: NSError? if let streamError = outStream.streamError { error = streamError } else { let errCode = InternalErrorCode.OutputStreamWriteError.rawValue error = s.errorWithDetail("output stream error during write", code: errCode) } s.doDisconnect(error) break } else { total += len } if total >= offset { break } } } } ///used to preform the disconnect delegate private func doDisconnect(error: NSError?) { guard !didDisconnect else { return } didDisconnect = true connected = false guard canDispatch else {return} dispatch_async(queue) { [weak self] in guard let s = self else { return } s.onDisconnect?(error) s.delegate?.websocketDidDisconnect(s, error: error) } } deinit { mutex.lock() readyToWrite = false mutex.unlock() cleanupStream() } } private class SSLCert { var certData: NSData? var key: SecKeyRef? /** Designated init for certificates - parameter data: is the binary data of the certificate - returns: a representation security object to be used with */ init(data: NSData) { self.certData = data } /** Designated init for public keys - parameter key: is the public key to be used - returns: a representation security object to be used with */ init(key: SecKeyRef) { self.key = key } } private class SSLSecurity { var validatedDN = true //should the domain name be validated? var isReady = false //is the key processing done? var certificates: [NSData]? //the certificates var pubKeys: [SecKeyRef]? //the public keys var usePublicKeys = false //use public keys or certificate validation? /** Use certs from main app bundle - parameter usePublicKeys: is to specific if the publicKeys or certificates should be used for SSL pinning validation - returns: a representation security object to be used with */ convenience init(usePublicKeys: Bool = false) { let paths = NSBundle.mainBundle().pathsForResourcesOfType("cer", inDirectory: ".") let certs = paths.reduce([SSLCert]()) { (var certs: [SSLCert], path: String) -> [SSLCert] in if let data = NSData(contentsOfFile: path) { certs.append(SSLCert(data: data)) } return certs } self.init(certs: certs, usePublicKeys: usePublicKeys) } /** Designated init - parameter keys: is the certificates or public keys to use - parameter usePublicKeys: is to specific if the publicKeys or certificates should be used for SSL pinning validation - returns: a representation security object to be used with */ init(certs: [SSLCert], usePublicKeys: Bool) { self.usePublicKeys = usePublicKeys if self.usePublicKeys { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)) { let pubKeys = certs.reduce([SecKeyRef]()) { (var pubKeys: [SecKeyRef], cert: SSLCert) -> [SecKeyRef] in if let data = cert.certData where cert.key == nil { cert.key = self.extractPublicKey(data) } if let key = cert.key { pubKeys.append(key) } return pubKeys } self.pubKeys = pubKeys self.isReady = true } } else { let certificates = certs.reduce([NSData]()) { (var certificates: [NSData], cert: SSLCert) -> [NSData] in if let data = cert.certData { certificates.append(data) } return certificates } self.certificates = certificates self.isReady = true } } /** Valid the trust and domain name. - parameter trust: is the serverTrust to validate - parameter domain: is the CN domain to validate - returns: if the key was successfully validated */ func isValid(trust: SecTrustRef, domain: String?) -> Bool { var tries = 0 while(!self.isReady) { usleep(1000) tries += 1 if tries > 5 { return false //doesn't appear it is going to ever be ready... } } var policy: SecPolicyRef if self.validatedDN { policy = SecPolicyCreateSSL(true, domain) } else { policy = SecPolicyCreateBasicX509() } SecTrustSetPolicies(trust,policy) if self.usePublicKeys { if let keys = self.pubKeys { let serverPubKeys = publicKeyChainForTrust(trust) for serverKey in serverPubKeys as [AnyObject] { for key in keys as [AnyObject] { if serverKey.isEqual(key) { return true } } } } } else if let certs = self.certificates { let serverCerts = certificateChainForTrust(trust) var collect = [SecCertificate]() for cert in certs { collect.append(SecCertificateCreateWithData(nil,cert)!) } SecTrustSetAnchorCertificates(trust,collect) var result: SecTrustResultType = 0 SecTrustEvaluate(trust,&result) let r = Int(result) if r == kSecTrustResultUnspecified || r == kSecTrustResultProceed { var trustedCount = 0 for serverCert in serverCerts { for cert in certs { if cert == serverCert { trustedCount++ break } } } if trustedCount == serverCerts.count { return true } } } return false } /** Get the public key from a certificate data - parameter data: is the certificate to pull the public key from - returns: a public key */ func extractPublicKey(data: NSData) -> SecKeyRef? { guard let cert = SecCertificateCreateWithData(nil, data) else { return nil } return extractPublicKeyFromCert(cert, policy: SecPolicyCreateBasicX509()) } /** Get the public key from a certificate - parameter data: is the certificate to pull the public key from - returns: a public key */ func extractPublicKeyFromCert(cert: SecCertificate, policy: SecPolicy) -> SecKeyRef? { var possibleTrust: SecTrust? SecTrustCreateWithCertificates(cert, policy, &possibleTrust) guard let trust = possibleTrust else { return nil } var result: SecTrustResultType = 0 SecTrustEvaluate(trust, &result) return SecTrustCopyPublicKey(trust) } /** Get the certificate chain for the trust - parameter trust: is the trust to lookup the certificate chain for - returns: the certificate chain for the trust */ func certificateChainForTrust(trust: SecTrustRef) -> [NSData] { let certificates = (0.. [NSData] in let cert = SecTrustGetCertificateAtIndex(trust, index) certificates.append(SecCertificateCopyData(cert!)) return certificates } return certificates } /** Get the public key chain for the trust - parameter trust: is the trust to lookup the certificate chain and extract the public keys - returns: the public keys from the certifcate chain for the trust */ func publicKeyChainForTrust(trust: SecTrustRef) -> [SecKeyRef] { let policy = SecPolicyCreateBasicX509() let keys = (0.. [SecKeyRef] in let cert = SecTrustGetCertificateAtIndex(trust, index) if let key = extractPublicKeyFromCert(cert!, policy: policy) { keys.append(key) } return keys } return keys } } ================================================ FILE: README.md ================================================ # BrewMobile [![Bitrise](https://www.bitrise.io/app/276d8847158110d2.svg?token=aYjuPeusfMeRdDn_eDksIg&branch=master)](https://www.bitrise.io/) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) iOS client for the [Brewfactory](https://github.com/brewfactory/BrewCore) project. Read the [stories of upgrading BrewMobile to ReactiveCocoa & Swift on AllTheFlow](https://blog.alltheflow.com/reactive-swift-upgrading-to-reactivecocoa-3-0/). What is this? ------------- App for managing the brewing process from your iPhone. - continuous temperature updates - displays current phases with necessary info - gives visual feedback of the current state - brew designer - ability of composing new brew - stopping current process ## Used technologies - Swift 2.1.x - iOS >= 8.1 - socket.io - [ReactiveCocoa](https://github.com/ReactiveCocoa/ReactiveCocoa) Required minimum Xcode version: 7.1 ## Setting up the project with [Carthage](https://github.com/Carthage/Carthage) In case you don't have Carthage installed, run: ``` $ brew update && brew install carthage ``` then: ``` $ carthage update --platform iOS $ open BrewMobile.xcworkspace/ ``` ## The UI ![Brewing a beer](http://brewfactory.org/BrewMobile/img/9_small.png)![Designing a brew](http://brewfactory.org/BrewMobile/img/8_small.png)