├── .clang-format ├── .gitignore ├── .hgignore ├── .travis.yml ├── BUILD ├── CONTRIBUTING.md ├── FBLFunctional.h ├── FBLFunctional.xcodeproj ├── FBLFunctionalTests_Info.plist ├── FBLFunctional_Info.plist ├── project.pbxproj └── xcshareddata │ └── xcschemes │ └── FBLFunctional.xcscheme ├── FunctionalObjC.podspec ├── LICENSE ├── Package.swift ├── README.md ├── Sources └── FBLFunctional │ ├── NSDictionary+FBLFunctional.m │ ├── NSObject+FBLFunctional.m │ └── include │ ├── FBLFunctional.h │ ├── NSArray+FBLFunctional.h │ ├── NSDictionary+FBLFunctional.h │ ├── NSOrderedSet+FBLFunctional.h │ ├── NSSet+FBLFunctional.h │ ├── framework.modulemap │ └── module.modulemap ├── Tests └── FBLFunctionalTests │ ├── NSArray+FBLFunctionalTests.m │ ├── NSDictionary+FBLFunctionalTests.m │ ├── NSOrderedSet+FBLFunctionalTests.m │ └── NSSet+FBLFunctionalTests.m └── WORKSPACE /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | 3 | AlignOperands: false 4 | AllowShortIfStatementsOnASingleLine: true 5 | AllowShortLoopsOnASingleLine: false 6 | BreakBeforeTernaryOperators: false 7 | ColumnLimit: 100 8 | PointerBindsToType: false 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generic build products 2 | 3 | *.[oa] 4 | [Bb]uild/ 5 | [Pp]re-[Bb]uild/ 6 | [Dd]eliverables/ 7 | [Dd]istribution/ 8 | [Dd]ocumentation/ 9 | [Dd]ocs/ 10 | 11 | # Swift PM 12 | 13 | Packages/ 14 | .build/ 15 | *.resolved 16 | 17 | # Bazel 18 | 19 | bazel-* 20 | 21 | # Other VCS 22 | 23 | .hg 24 | .svn 25 | *.prej 26 | *.mine 27 | CVS 28 | 29 | # OSX 30 | 31 | .DS_Store 32 | .DS_Store? 33 | ._* 34 | .~* 35 | ~$* 36 | *.lock 37 | .AppleDouble 38 | .LSOverride 39 | .DocumentRevisions-V100 40 | .fseventsd 41 | .Spotlight-V100 42 | .TemporaryItems 43 | .Trashes 44 | ehthumbs.db 45 | Thumbs.db 46 | .AppleDB 47 | .AppleDesktop 48 | .apdisk 49 | 50 | # Windows 51 | 52 | Thumbs.db 53 | ehthumbs.db 54 | Desktop.ini 55 | $RECYCLE.BIN/ 56 | *.cab 57 | *.msi 58 | *.msm 59 | *.msp 60 | *.lnk 61 | 62 | # Xcode 63 | 64 | DerivedData/ 65 | xcuserdata/ 66 | project.xcworkspace/ 67 | *.mode1 68 | *.mode1v3 69 | *.mode2v3 70 | *.perspective 71 | *.perspectivev3 72 | *.pbxuser 73 | *.xccheckout 74 | *.moved-aside 75 | *.xcuserstate 76 | *.xctimeline 77 | 78 | # JetBrains 79 | 80 | .idea/ 81 | 82 | # CocoaPods 83 | 84 | !Podfile.lock 85 | !Pods/Manifest.lock 86 | Pods/Documentation 87 | 88 | #Carthage 89 | 90 | Carthage/ 91 | 92 | # SublimeText 93 | 94 | *.tmlanguage.cache 95 | *.tmPreferences.cache 96 | *.stTheme.cache 97 | *.sublime-workspace 98 | -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | 3 | # Generic build products 4 | 5 | *.[oa] 6 | [Bb]uild/ 7 | [Pp]re-[Bb]uild/ 8 | [Dd]eliverables/ 9 | [Dd]istribution/ 10 | [Dd]ocumentation/ 11 | [Dd]ocs/ 12 | 13 | # Swift PM 14 | 15 | Packages/ 16 | .build/ 17 | *.resolved 18 | 19 | # Bazel 20 | 21 | bazel-* 22 | 23 | # Other VCS 24 | 25 | .hg 26 | .svn 27 | *.prej 28 | *.mine 29 | CVS 30 | 31 | # OSX 32 | 33 | .DS_Store 34 | .DS_Store? 35 | ._* 36 | .~* 37 | ~$* 38 | *.lock 39 | .AppleDouble 40 | .LSOverride 41 | .DocumentRevisions-V100 42 | .fseventsd 43 | .Spotlight-V100 44 | .TemporaryItems 45 | .Trashes 46 | ehthumbs.db 47 | Thumbs.db 48 | .AppleDB 49 | .AppleDesktop 50 | .apdisk 51 | 52 | # Windows 53 | 54 | Thumbs.db 55 | ehthumbs.db 56 | Desktop.ini 57 | $RECYCLE.BIN/ 58 | *.cab 59 | *.msi 60 | *.msm 61 | *.msp 62 | *.lnk 63 | 64 | # Xcode 65 | 66 | DerivedData/ 67 | xcuserdata/ 68 | project.xcworkspace/ 69 | *.mode1 70 | *.mode1v3 71 | *.mode2v3 72 | *.perspective 73 | *.perspectivev3 74 | *.pbxuser 75 | *.xccheckout 76 | *.moved-aside 77 | *.xcuserstate 78 | *.xctimeline 79 | 80 | # JetBrains 81 | 82 | .idea/ 83 | 84 | # CocoaPods 85 | 86 | !Podfile.lock 87 | !Pods/Manifest.lock 88 | Pods/Documentation 89 | 90 | #Carthage 91 | 92 | Carthage/ 93 | 94 | # SublimeText 95 | 96 | *.tmlanguage.cache 97 | *.tmPreferences.cache 98 | *.stTheme.cache 99 | *.sublime-workspace 100 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: osx 2 | language: objective-c 3 | install: true 4 | before_install: 5 | - brew update 6 | - brew install bazel 7 | script: 8 | - bazel --batch test Tests --spawn_strategy=standalone --genrule_strategy=standalone --test_strategy=standalone --noshow_progress --noshow_loading_progress --verbose_failures --test_verbose_timeout_warnings --test_output=errors 9 | -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | licenses(["notice"]) # Apache 2.0 4 | 5 | exports_files(["LICENSE"]) 6 | 7 | load("@build_bazel_rules_apple//apple:ios.bzl", "ios_unit_test") 8 | 9 | OBJC_COPTS = [ 10 | "-Wall", 11 | "-Wextra", 12 | "-Werror", 13 | ] 14 | 15 | objc_library( 16 | name = "FBLFunctional", 17 | srcs = glob([ 18 | "Sources/FBLFunctional/*.m", 19 | ]), 20 | hdrs = glob([ 21 | "Sources/FBLFunctional/include/*.h", 22 | ]) + [ 23 | "FBLFunctional.h", 24 | ], 25 | copts = OBJC_COPTS, 26 | includes = [ 27 | "Sources/FBLFunctional/include", 28 | ], 29 | ) 30 | 31 | ios_unit_test( 32 | name = "Tests", 33 | minimum_os_version = "8.0", 34 | deps = [ 35 | ":FBLFunctionalTests", 36 | ], 37 | ) 38 | 39 | objc_library( 40 | name = "FBLFunctionalTests", 41 | testonly = 1, 42 | srcs = glob([ 43 | "Tests/FBLFunctionalTests/*.m", 44 | ]), 45 | copts = OBJC_COPTS, 46 | deps = [ 47 | ":FBLFunctional", 48 | ], 49 | ) 50 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute # 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few guidelines you need to follow. 5 | 6 | 7 | ## Contributor License Agreement ## 8 | 9 | Contributions to any Google project must be accompanied by a Contributor 10 | License Agreement. This is not a copyright **assignment**, it simply gives 11 | Google permission to use and redistribute your contributions as part of the 12 | project. 13 | 14 | * If you are an individual writing original source code and you're sure you 15 | own the intellectual property, then you'll need to sign an [individual 16 | CLA][]. 17 | 18 | * If you work for a company that wants to allow you to contribute your work, 19 | then you'll need to sign a [corporate CLA][]. 20 | 21 | You generally only need to submit a CLA once, so if you've already submitted 22 | one (even if it was for a different project), you probably don't need to do it 23 | again. 24 | 25 | [individual CLA]: https://developers.google.com/open-source/cla/individual 26 | [corporate CLA]: https://developers.google.com/open-source/cla/corporate 27 | 28 | 29 | ## Submitting a patch ## 30 | 31 | 1. It's generally best to start by opening a new issue describing the bug or 32 | feature you're intending to fix. Even if you think it's relatively minor, 33 | it's helpful to know what people are working on. Mention in the initial 34 | issue that you are planning to work on that bug or feature so that it can 35 | be assigned to you. 36 | 37 | 1. Follow the normal process of [forking][] the project, and setup a new 38 | branch to work in. It's important that each group of changes be done in 39 | separate branches in order to ensure that a pull request only includes the 40 | commits related to that bug or feature. 41 | 42 | 1. Any significant changes should almost always be accompanied by tests. The 43 | project already has good test coverage, so look at some of the existing 44 | tests if you're unsure how to go about it. 45 | 46 | 1. Do your best to have [well-formed commit messages][] for each change. 47 | This provides consistency throughout the project, and ensures that commit 48 | messages are able to be formatted properly by various git tools. 49 | 50 | 1. Finally, push the commits to your fork and submit a [pull request][]. 51 | 52 | [forking]: https://help.github.com/articles/fork-a-repo 53 | [well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html 54 | [pull request]: https://help.github.com/articles/creating-a-pull-request 55 | -------------------------------------------------------------------------------- /FBLFunctional.h: -------------------------------------------------------------------------------- 1 | Sources/FBLFunctional/include/FBLFunctional.h -------------------------------------------------------------------------------- /FBLFunctional.xcodeproj/FBLFunctionalTests_Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | com.google.$(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | BNDL 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /FBLFunctional.xcodeproj/FBLFunctional_Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | com.google.$(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | FMWK 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /FBLFunctional.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 032B8165204629650097BF12 /* NSDictionary+FBLFunctional.h in Headers */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* NSDictionary+FBLFunctional.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 032B8166204629650097BF12 /* NSOrderedSet+FBLFunctional.h in Headers */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* NSOrderedSet+FBLFunctional.h */; settings = {ATTRIBUTES = (Public, ); }; }; 12 | 032B8167204629650097BF12 /* NSArray+FBLFunctional.h in Headers */ = {isa = PBXBuildFile; fileRef = OBJ_14 /* NSArray+FBLFunctional.h */; settings = {ATTRIBUTES = (Public, ); }; }; 13 | 032B8168204629650097BF12 /* FBLFunctional.h in Headers */ = {isa = PBXBuildFile; fileRef = OBJ_15 /* FBLFunctional.h */; settings = {ATTRIBUTES = (Public, ); }; }; 14 | 032B8169204629650097BF12 /* NSSet+FBLFunctional.h in Headers */ = {isa = PBXBuildFile; fileRef = OBJ_16 /* NSSet+FBLFunctional.h */; settings = {ATTRIBUTES = (Public, ); }; }; 15 | OBJ_38 /* NSArray+FBLFunctionalTests.m in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_20 /* NSArray+FBLFunctionalTests.m */; }; 16 | OBJ_39 /* NSDictionary+FBLFunctionalTests.m in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_21 /* NSDictionary+FBLFunctionalTests.m */; }; 17 | OBJ_40 /* NSOrderedSet+FBLFunctionalTests.m in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_22 /* NSOrderedSet+FBLFunctionalTests.m */; }; 18 | OBJ_41 /* NSSet+FBLFunctionalTests.m in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_23 /* NSSet+FBLFunctionalTests.m */; }; 19 | OBJ_43 /* FBLFunctional.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "FBLFunctional::FBLFunctional::Product" /* FBLFunctional.framework */; }; 20 | OBJ_50 /* NSDictionary+FBLFunctional.m in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* NSDictionary+FBLFunctional.m */; }; 21 | OBJ_51 /* NSObject+FBLFunctional.m in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_10 /* NSObject+FBLFunctional.m */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXContainerItemProxy section */ 25 | 032B8162204628AD0097BF12 /* PBXContainerItemProxy */ = { 26 | isa = PBXContainerItemProxy; 27 | containerPortal = OBJ_1 /* Project object */; 28 | proxyType = 1; 29 | remoteGlobalIDString = "FBLFunctional::FBLFunctional"; 30 | remoteInfo = FBLFunctional; 31 | }; 32 | /* End PBXContainerItemProxy section */ 33 | 34 | /* Begin PBXFileReference section */ 35 | 032B816A2046298C0097BF12 /* framework.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = framework.modulemap; sourceTree = ""; }; 36 | "FBLFunctional::FBLFunctional::Product" /* FBLFunctional.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FBLFunctional.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | "FBLFunctional::FBLFunctionalTests::Product" /* FBLFunctionalTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; path = FBLFunctionalTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | OBJ_10 /* NSObject+FBLFunctional.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+FBLFunctional.m"; sourceTree = ""; }; 39 | OBJ_12 /* NSDictionary+FBLFunctional.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+FBLFunctional.h"; sourceTree = ""; }; 40 | OBJ_13 /* NSOrderedSet+FBLFunctional.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSOrderedSet+FBLFunctional.h"; sourceTree = ""; }; 41 | OBJ_14 /* NSArray+FBLFunctional.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSArray+FBLFunctional.h"; sourceTree = ""; }; 42 | OBJ_15 /* FBLFunctional.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FBLFunctional.h; sourceTree = ""; }; 43 | OBJ_16 /* NSSet+FBLFunctional.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSSet+FBLFunctional.h"; sourceTree = ""; }; 44 | OBJ_20 /* NSArray+FBLFunctionalTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSArray+FBLFunctionalTests.m"; sourceTree = ""; }; 45 | OBJ_21 /* NSDictionary+FBLFunctionalTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+FBLFunctionalTests.m"; sourceTree = ""; }; 46 | OBJ_22 /* NSOrderedSet+FBLFunctionalTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSOrderedSet+FBLFunctionalTests.m"; sourceTree = ""; }; 47 | OBJ_23 /* NSSet+FBLFunctionalTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSSet+FBLFunctionalTests.m"; sourceTree = ""; }; 48 | OBJ_9 /* NSDictionary+FBLFunctional.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+FBLFunctional.m"; sourceTree = ""; }; 49 | /* End PBXFileReference section */ 50 | 51 | /* Begin PBXFrameworksBuildPhase section */ 52 | OBJ_42 /* Frameworks */ = { 53 | isa = PBXFrameworksBuildPhase; 54 | buildActionMask = 0; 55 | files = ( 56 | OBJ_43 /* FBLFunctional.framework in Frameworks */, 57 | ); 58 | runOnlyForDeploymentPostprocessing = 0; 59 | }; 60 | OBJ_52 /* Frameworks */ = { 61 | isa = PBXFrameworksBuildPhase; 62 | buildActionMask = 0; 63 | files = ( 64 | ); 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | /* End PBXFrameworksBuildPhase section */ 68 | 69 | /* Begin PBXGroup section */ 70 | OBJ_11 /* include */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | OBJ_15 /* FBLFunctional.h */, 74 | OBJ_14 /* NSArray+FBLFunctional.h */, 75 | OBJ_12 /* NSDictionary+FBLFunctional.h */, 76 | OBJ_13 /* NSOrderedSet+FBLFunctional.h */, 77 | OBJ_16 /* NSSet+FBLFunctional.h */, 78 | 032B816A2046298C0097BF12 /* framework.modulemap */, 79 | ); 80 | path = include; 81 | sourceTree = ""; 82 | }; 83 | OBJ_18 /* Tests */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | OBJ_19 /* FBLFunctionalTests */, 87 | ); 88 | name = Tests; 89 | sourceTree = SOURCE_ROOT; 90 | }; 91 | OBJ_19 /* FBLFunctionalTests */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | OBJ_20 /* NSArray+FBLFunctionalTests.m */, 95 | OBJ_21 /* NSDictionary+FBLFunctionalTests.m */, 96 | OBJ_22 /* NSOrderedSet+FBLFunctionalTests.m */, 97 | OBJ_23 /* NSSet+FBLFunctionalTests.m */, 98 | ); 99 | name = FBLFunctionalTests; 100 | path = Tests/FBLFunctionalTests; 101 | sourceTree = SOURCE_ROOT; 102 | }; 103 | OBJ_24 /* Products */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | "FBLFunctional::FBLFunctionalTests::Product" /* FBLFunctionalTests.xctest */, 107 | "FBLFunctional::FBLFunctional::Product" /* FBLFunctional.framework */, 108 | ); 109 | name = Products; 110 | sourceTree = BUILT_PRODUCTS_DIR; 111 | }; 112 | OBJ_5 = { 113 | isa = PBXGroup; 114 | children = ( 115 | OBJ_7 /* Sources */, 116 | OBJ_18 /* Tests */, 117 | OBJ_24 /* Products */, 118 | ); 119 | sourceTree = ""; 120 | }; 121 | OBJ_7 /* Sources */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | OBJ_8 /* FBLFunctional */, 125 | ); 126 | name = Sources; 127 | sourceTree = SOURCE_ROOT; 128 | }; 129 | OBJ_8 /* FBLFunctional */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | OBJ_9 /* NSDictionary+FBLFunctional.m */, 133 | OBJ_10 /* NSObject+FBLFunctional.m */, 134 | OBJ_11 /* include */, 135 | ); 136 | name = FBLFunctional; 137 | path = Sources/FBLFunctional; 138 | sourceTree = SOURCE_ROOT; 139 | }; 140 | /* End PBXGroup section */ 141 | 142 | /* Begin PBXHeadersBuildPhase section */ 143 | 032B81642046295E0097BF12 /* Headers */ = { 144 | isa = PBXHeadersBuildPhase; 145 | buildActionMask = 2147483647; 146 | files = ( 147 | 032B8168204629650097BF12 /* FBLFunctional.h in Headers */, 148 | 032B8166204629650097BF12 /* NSOrderedSet+FBLFunctional.h in Headers */, 149 | 032B8165204629650097BF12 /* NSDictionary+FBLFunctional.h in Headers */, 150 | 032B8167204629650097BF12 /* NSArray+FBLFunctional.h in Headers */, 151 | 032B8169204629650097BF12 /* NSSet+FBLFunctional.h in Headers */, 152 | ); 153 | runOnlyForDeploymentPostprocessing = 0; 154 | }; 155 | /* End PBXHeadersBuildPhase section */ 156 | 157 | /* Begin PBXNativeTarget section */ 158 | "FBLFunctional::FBLFunctional" /* FBLFunctional */ = { 159 | isa = PBXNativeTarget; 160 | buildConfigurationList = OBJ_46 /* Build configuration list for PBXNativeTarget "FBLFunctional" */; 161 | buildPhases = ( 162 | OBJ_49 /* Sources */, 163 | OBJ_52 /* Frameworks */, 164 | 032B81642046295E0097BF12 /* Headers */, 165 | ); 166 | buildRules = ( 167 | ); 168 | dependencies = ( 169 | ); 170 | name = FBLFunctional; 171 | productName = FBLFunctional; 172 | productReference = "FBLFunctional::FBLFunctional::Product" /* FBLFunctional.framework */; 173 | productType = "com.apple.product-type.framework"; 174 | }; 175 | "FBLFunctional::FBLFunctionalTests" /* FBLFunctionalTests */ = { 176 | isa = PBXNativeTarget; 177 | buildConfigurationList = OBJ_34 /* Build configuration list for PBXNativeTarget "FBLFunctionalTests" */; 178 | buildPhases = ( 179 | OBJ_37 /* Sources */, 180 | OBJ_42 /* Frameworks */, 181 | ); 182 | buildRules = ( 183 | ); 184 | dependencies = ( 185 | OBJ_44 /* PBXTargetDependency */, 186 | ); 187 | name = FBLFunctionalTests; 188 | productName = FBLFunctionalTests; 189 | productReference = "FBLFunctional::FBLFunctionalTests::Product" /* FBLFunctionalTests.xctest */; 190 | productType = "com.apple.product-type.bundle.unit-test"; 191 | }; 192 | /* End PBXNativeTarget section */ 193 | 194 | /* Begin PBXProject section */ 195 | OBJ_1 /* Project object */ = { 196 | isa = PBXProject; 197 | attributes = { 198 | LastUpgradeCheck = 9999; 199 | }; 200 | buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "FBLFunctional" */; 201 | compatibilityVersion = "Xcode 3.2"; 202 | developmentRegion = English; 203 | hasScannedForEncodings = 0; 204 | knownRegions = ( 205 | en, 206 | ); 207 | mainGroup = OBJ_5; 208 | productRefGroup = OBJ_24 /* Products */; 209 | projectDirPath = ""; 210 | projectRoot = ""; 211 | targets = ( 212 | "FBLFunctional::FBLFunctionalTests" /* FBLFunctionalTests */, 213 | "FBLFunctional::FBLFunctional" /* FBLFunctional */, 214 | ); 215 | }; 216 | /* End PBXProject section */ 217 | 218 | /* Begin PBXSourcesBuildPhase section */ 219 | OBJ_37 /* Sources */ = { 220 | isa = PBXSourcesBuildPhase; 221 | buildActionMask = 0; 222 | files = ( 223 | OBJ_38 /* NSArray+FBLFunctionalTests.m in Sources */, 224 | OBJ_39 /* NSDictionary+FBLFunctionalTests.m in Sources */, 225 | OBJ_40 /* NSOrderedSet+FBLFunctionalTests.m in Sources */, 226 | OBJ_41 /* NSSet+FBLFunctionalTests.m in Sources */, 227 | ); 228 | runOnlyForDeploymentPostprocessing = 0; 229 | }; 230 | OBJ_49 /* Sources */ = { 231 | isa = PBXSourcesBuildPhase; 232 | buildActionMask = 0; 233 | files = ( 234 | OBJ_50 /* NSDictionary+FBLFunctional.m in Sources */, 235 | OBJ_51 /* NSObject+FBLFunctional.m in Sources */, 236 | ); 237 | runOnlyForDeploymentPostprocessing = 0; 238 | }; 239 | /* End PBXSourcesBuildPhase section */ 240 | 241 | /* Begin PBXTargetDependency section */ 242 | OBJ_44 /* PBXTargetDependency */ = { 243 | isa = PBXTargetDependency; 244 | target = "FBLFunctional::FBLFunctional" /* FBLFunctional */; 245 | targetProxy = 032B8162204628AD0097BF12 /* PBXContainerItemProxy */; 246 | }; 247 | /* End PBXTargetDependency section */ 248 | 249 | /* Begin XCBuildConfiguration section */ 250 | OBJ_3 /* Debug */ = { 251 | isa = XCBuildConfiguration; 252 | buildSettings = { 253 | CLANG_ENABLE_OBJC_ARC = YES; 254 | COMBINE_HIDPI_IMAGES = YES; 255 | COPY_PHASE_STRIP = NO; 256 | DEBUG_INFORMATION_FORMAT = dwarf; 257 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 258 | ENABLE_NS_ASSERTIONS = YES; 259 | GCC_OPTIMIZATION_LEVEL = 0; 260 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 261 | MACOSX_DEPLOYMENT_TARGET = 10.10; 262 | ONLY_ACTIVE_ARCH = YES; 263 | PRODUCT_NAME = "$(TARGET_NAME)"; 264 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; 265 | TVOS_DEPLOYMENT_TARGET = 9.0; 266 | USE_HEADERMAP = NO; 267 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 268 | }; 269 | name = Debug; 270 | }; 271 | OBJ_35 /* Debug */ = { 272 | isa = XCBuildConfiguration; 273 | buildSettings = { 274 | FRAMEWORK_SEARCH_PATHS = ( 275 | "$(inherited)", 276 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 277 | ); 278 | HEADER_SEARCH_PATHS = ( 279 | "$(inherited)", 280 | "$(SRCROOT)/Tests/FBLFunctionalTests/include", 281 | "$(SRCROOT)/Sources/FBLFunctional/include", 282 | ); 283 | INFOPLIST_FILE = FBLFunctional.xcodeproj/FBLFunctionalTests_Info.plist; 284 | LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks @loader_path/Frameworks"; 285 | OTHER_LDFLAGS = "$(inherited)"; 286 | TARGET_NAME = FBLFunctionalTests; 287 | }; 288 | name = Debug; 289 | }; 290 | OBJ_36 /* Release */ = { 291 | isa = XCBuildConfiguration; 292 | buildSettings = { 293 | FRAMEWORK_SEARCH_PATHS = ( 294 | "$(inherited)", 295 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 296 | ); 297 | HEADER_SEARCH_PATHS = ( 298 | "$(inherited)", 299 | "$(SRCROOT)/Tests/FBLFunctionalTests/include", 300 | "$(SRCROOT)/Sources/FBLFunctional/include", 301 | ); 302 | INFOPLIST_FILE = FBLFunctional.xcodeproj/FBLFunctionalTests_Info.plist; 303 | LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks @loader_path/Frameworks"; 304 | OTHER_LDFLAGS = "$(inherited)"; 305 | TARGET_NAME = FBLFunctionalTests; 306 | }; 307 | name = Release; 308 | }; 309 | OBJ_4 /* Release */ = { 310 | isa = XCBuildConfiguration; 311 | buildSettings = { 312 | CLANG_ENABLE_OBJC_ARC = YES; 313 | COMBINE_HIDPI_IMAGES = YES; 314 | COPY_PHASE_STRIP = YES; 315 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 316 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 317 | GCC_OPTIMIZATION_LEVEL = s; 318 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 319 | MACOSX_DEPLOYMENT_TARGET = 10.10; 320 | PRODUCT_NAME = "$(TARGET_NAME)"; 321 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; 322 | TVOS_DEPLOYMENT_TARGET = 9.0; 323 | USE_HEADERMAP = NO; 324 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 325 | }; 326 | name = Release; 327 | }; 328 | OBJ_47 /* Debug */ = { 329 | isa = XCBuildConfiguration; 330 | buildSettings = { 331 | DEFINES_MODULE = YES; 332 | ENABLE_TESTABILITY = YES; 333 | FRAMEWORK_SEARCH_PATHS = ( 334 | "$(inherited)", 335 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 336 | ); 337 | HEADER_SEARCH_PATHS = ( 338 | "$(inherited)", 339 | "$(SRCROOT)/Sources/FBLFunctional/include", 340 | ); 341 | INFOPLIST_FILE = FBLFunctional.xcodeproj/FBLFunctional_Info.plist; 342 | MODULEMAP_FILE = "$(SRCROOT)/Sources/FBLFunctional/include/framework.modulemap"; 343 | OTHER_LDFLAGS = "$(inherited)"; 344 | PRODUCT_BUNDLE_IDENTIFIER = FBLFunctional; 345 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; 346 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 347 | SKIP_INSTALL = YES; 348 | TARGET_NAME = FBLFunctional; 349 | }; 350 | name = Debug; 351 | }; 352 | OBJ_48 /* Release */ = { 353 | isa = XCBuildConfiguration; 354 | buildSettings = { 355 | DEFINES_MODULE = YES; 356 | ENABLE_TESTABILITY = YES; 357 | FRAMEWORK_SEARCH_PATHS = ( 358 | "$(inherited)", 359 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 360 | ); 361 | HEADER_SEARCH_PATHS = ( 362 | "$(inherited)", 363 | "$(SRCROOT)/Sources/FBLFunctional/include", 364 | ); 365 | INFOPLIST_FILE = FBLFunctional.xcodeproj/FBLFunctional_Info.plist; 366 | MODULEMAP_FILE = "$(SRCROOT)/Sources/FBLFunctional/include/framework.modulemap"; 367 | OTHER_LDFLAGS = "$(inherited)"; 368 | PRODUCT_BUNDLE_IDENTIFIER = FBLFunctional; 369 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; 370 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 371 | SKIP_INSTALL = YES; 372 | TARGET_NAME = FBLFunctional; 373 | }; 374 | name = Release; 375 | }; 376 | /* End XCBuildConfiguration section */ 377 | 378 | /* Begin XCConfigurationList section */ 379 | OBJ_2 /* Build configuration list for PBXProject "FBLFunctional" */ = { 380 | isa = XCConfigurationList; 381 | buildConfigurations = ( 382 | OBJ_3 /* Debug */, 383 | OBJ_4 /* Release */, 384 | ); 385 | defaultConfigurationIsVisible = 0; 386 | defaultConfigurationName = Debug; 387 | }; 388 | OBJ_34 /* Build configuration list for PBXNativeTarget "FBLFunctionalTests" */ = { 389 | isa = XCConfigurationList; 390 | buildConfigurations = ( 391 | OBJ_35 /* Debug */, 392 | OBJ_36 /* Release */, 393 | ); 394 | defaultConfigurationIsVisible = 0; 395 | defaultConfigurationName = Debug; 396 | }; 397 | OBJ_46 /* Build configuration list for PBXNativeTarget "FBLFunctional" */ = { 398 | isa = XCConfigurationList; 399 | buildConfigurations = ( 400 | OBJ_47 /* Debug */, 401 | OBJ_48 /* Release */, 402 | ); 403 | defaultConfigurationIsVisible = 0; 404 | defaultConfigurationName = Debug; 405 | }; 406 | /* End XCConfigurationList section */ 407 | }; 408 | rootObject = OBJ_1 /* Project object */; 409 | } 410 | -------------------------------------------------------------------------------- /FBLFunctional.xcodeproj/xcshareddata/xcschemes/FBLFunctional.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /FunctionalObjC.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'FunctionalObjC' 3 | s.version = '1.0.2' 4 | s.authors = 'Google Inc.' 5 | s.license = { :type => 'Apache', :file => 'LICENSE' } 6 | s.homepage = 'https://github.com/google/functional-objc' 7 | s.source = { :git => 'https://github.com/google/functional-objc.git', :tag => s.version } 8 | s.summary = 'Functional operators for Objective-C' 9 | s.description = <<-DESC 10 | 11 | An Objective-C library of functional operators, derived from Swift.Sequence, 12 | that help you write more concise and readable code for collection 13 | transformations. Foundation collections supported include: NSArray, 14 | NSDictionary, NSOrderedSet, and NSSet. 15 | DESC 16 | 17 | s.ios.deployment_target = '8.0' 18 | s.osx.deployment_target = '10.10' 19 | s.tvos.deployment_target = '9.0' 20 | s.watchos.deployment_target = '2.0' 21 | 22 | s.module_name = 'FBLFunctional' 23 | s.prefix_header_file = false 24 | s.source_files = "Sources/#{s.module_name}/**/*.{h,m}" 25 | 26 | s.test_spec "Tests" do |ts| 27 | ts.source_files = "Tests/#{s.module_name}Tests/*.{h,m}" 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:4.0 2 | // swiftlint:disable trailing_comma 3 | 4 | // To generate and open project in Xcode run: 5 | // swift package generate-xcodeproj && open FBLFunctional.xcodeproj 6 | 7 | // Copyright 2018 Google Inc. All rights reserved. 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); 10 | // you may not use this file except in compliance with the License. 11 | // You may obtain a copy of the License at: 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | 21 | import PackageDescription 22 | 23 | let package = Package( 24 | name: "FBLFunctional", 25 | products: [ 26 | .library( 27 | name: "FBLFunctional", 28 | targets: ["FBLFunctional"] 29 | ) 30 | ], 31 | targets: [ 32 | .target( 33 | name: "FBLFunctional" 34 | ), 35 | .testTarget( 36 | name: "FBLFunctionalTests", 37 | dependencies: [ 38 | "FBLFunctional", 39 | ] 40 | ), 41 | ] 42 | ) 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Apache 2 | License](https://img.shields.io/github/license/google/functional-objc.svg)](LICENSE) 3 | [![Travis](https://img.shields.io/travis/google/promises.svg)](https://travis-ci.org/google/functional-objc) 4 | 5 | # Functional operators for Objective-C 6 | 7 | An Objective-C library of functional operators, derived from `Swift.Sequence`, 8 | that help you write more concise and readable code for collection 9 | transformations. Foundation collections supported include: `NSArray`, 10 | `NSDictionary`, `NSOrderedSet`, and `NSSet`. 11 | 12 | ## Functional Operators 13 | 14 | ### Filter 15 | 16 | Loops over a collection and returns an array that contains elements that meet a 17 | condition. 18 | 19 | ```objectivec 20 | NSArray *filteredArray = [@[ @13, @42, @0 ] fbl_filter:^BOOL(NSNumber *value) { 21 | return value.integerValue > 0; 22 | }]; 23 | XCTAssertEqualObjects(filteredArray, @[ @13, @42 ]); 24 | ``` 25 | 26 | ### First 27 | 28 | Returns the first element in the collection that satisfies a condition. 29 | 30 | ```objectivec 31 | NSNumber *firstValue = [@[ @13, @42, @100 ] fbl_first:^BOOL(NSNumber *value) { 32 | return value.integerValue > 20; 33 | }]; 34 | XCTAssertEqualObjects(firstValue, @42); 35 | ``` 36 | 37 | ### FlatMap 38 | 39 | Similar to [`map`](#map), but can also flatten a collection of collections. 40 | 41 | ```objectivec 42 | NSArray *> *originalArray = @[ @[ @13, @42 ], @[ @14, @43 ], @[] ]; 43 | NSArray *flatMappedArray = [originalArray fbl_flatMap:^id(NSArray *value) { 44 | return value.count > 0 ? value : nil; 45 | }]; 46 | XCTAssertEqualObjects(flatMappedArray, @[ @13, @42, @14, @43 ]); 47 | ``` 48 | 49 | ### ForEach 50 | 51 | Invokes a block on each element of the collection in the same order as a for-in 52 | loop. 53 | 54 | ```objectivec 55 | [@[ @13, @42, @100 ] fbl_forEach:^(NSNumber *value) { 56 | // Invokes this block for values @13, @42, @100 57 | }]; 58 | ``` 59 | 60 | ### Map 61 | 62 | Loops over a collection and applies the same operation to each element in the 63 | collection. 64 | 65 | ```objectivec 66 | NSArray *mappedArray = [@[ @13, @42, @0 ] fbl_map:^id(NSNumber *value) { 67 | if (value.integerValue == 0) { 68 | return nil; 69 | } 70 | return value.stringValue; 71 | }]; 72 | XCTAssertEqualObjects(mappedArray, @[ @"13", @"42", [NSNull null] ]); 73 | ``` 74 | 75 | ### Reduce 76 | 77 | Combines all items in a collection to create a single value. 78 | 79 | ```objectivec 80 | NSNumber *reducedValue = 81 | [@[ @13, @42, @100 ] fbl_reduce:@0 82 | combine:^NSNumber *(NSNumber *accumulator, NSNumber *value) { 83 | return @(accumulator.integerValue + value.integerValue); 84 | }]; 85 | XCTAssertEqualObjects(reducedValue, @(13 + 42 + 100)); 86 | ``` 87 | 88 | ### Zip 89 | 90 | Creates an array of pairs built from the two input collections. 91 | 92 | ```objectivec 93 | NSArray *zippedArray = [@[ @13, @42, @101 ] fbl_zip:@[ @"100", @"14" ]]; 94 | XCTAssertEqualObjects(zippedArray, @[ @[ @13, @"100" ], @[ @42, @"14" ] ]); 95 | ``` 96 | 97 | ## Setup 98 | 99 | ### CocoaPods 100 | 101 | Add the following to your `Podfile`: 102 | 103 | ```ruby 104 | pod 'FunctionalObjC', '~> 1.0' 105 | ``` 106 | 107 | Or, if you would also like to include the tests: 108 | 109 | ```ruby 110 | pod 'FunctionalObjC', '~> 1.0', :testspecs => ['Tests'] 111 | ``` 112 | 113 | Then, run `pod install`. 114 | 115 | ### Carthage 116 | 117 | Add the following to your `Cartfile`: 118 | 119 | ``` 120 | github "google/functional-objc" 121 | ``` 122 | 123 | Then, run `carthage update` and follow the [rest of instructions](https://github.com/Carthage/Carthage#getting-started). 124 | 125 | ### Import 126 | 127 | Import the umbrella header as: 128 | 129 | ```objectivec 130 | #import 131 | ``` 132 | 133 | Or: 134 | 135 | ```objectivec 136 | #import "FBLFunctional.h" 137 | ``` 138 | 139 | Or, the module: 140 | 141 | ```objectivec 142 | @import FBLFunctional; 143 | ``` 144 | -------------------------------------------------------------------------------- /Sources/FBLFunctional/NSDictionary+FBLFunctional.m: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2018 Google Inc. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at: 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import "NSDictionary+FBLFunctional.h" 18 | 19 | FOUNDATION_EXTERN NSArray *FBLZip(id container1, id container2); 20 | 21 | static NSDictionary *FBLDictionaryFilter(NSDictionary *dictionary, BOOL (^predicate)(id, id)) { 22 | NSMutableDictionary *result = [[NSMutableDictionary alloc] init]; 23 | for (id key in dictionary) { 24 | id value = dictionary[key]; 25 | if (predicate(key, value)) { 26 | result[key] = value; 27 | } 28 | } 29 | return result; 30 | } 31 | 32 | static id __nullable FBLDictionaryFirst(NSDictionary *dictionary, BOOL (^predicate)(id, id)) { 33 | for (id key in dictionary) { 34 | if (predicate(key, dictionary[key])) { 35 | return key; 36 | } 37 | } 38 | return nil; 39 | } 40 | 41 | static NSArray *FBLDictionaryFlatMap(NSDictionary *dictionary, id __nullable (^mapper)(id, id)) { 42 | NSMutableArray *result = [[NSMutableArray alloc] init]; 43 | for (id key in dictionary) { 44 | id mapped = mapper(key, dictionary[key]); 45 | if ([mapped isKindOfClass:[NSDictionary class]]) { 46 | [result addObjectsFromArray:[mapped allValues]]; 47 | } else if (mapped) { 48 | [result addObject:mapped]; 49 | } 50 | } 51 | return result; 52 | } 53 | 54 | static void FBLDictionaryForEach(NSDictionary *dictionary, void (^block)(id, id)) { 55 | for (id key in dictionary) { 56 | block(key, dictionary[key]); 57 | } 58 | } 59 | 60 | static NSArray *FBLDictionaryMap(NSDictionary *dictionary, id __nullable (^mapper)(id, id)) { 61 | NSMutableArray *result = [[NSMutableArray alloc] init]; 62 | for (id key in dictionary) { 63 | id mapped = mapper(key, dictionary[key]); 64 | [result addObject:mapped ?: [NSNull null]]; 65 | } 66 | return result; 67 | } 68 | 69 | static NSDictionary *FBLDictionaryMapValues(NSDictionary *dictionary, id __nullable (^mapper)(id)) { 70 | NSMutableDictionary *result = [[NSMutableDictionary alloc] init]; 71 | for (id key in dictionary) { 72 | id mapped = mapper(dictionary[key]); 73 | result[key] = mapped ?: [NSNull null]; 74 | } 75 | return result; 76 | } 77 | 78 | static id __nullable FBLDictionaryReduce(NSDictionary *dictionary, id __nullable initialValue, 79 | id __nullable (^reducer)(id __nullable, id, id)) { 80 | id result = initialValue; 81 | for (id key in dictionary) { 82 | result = reducer(result, key, dictionary[key]); 83 | } 84 | return result; 85 | } 86 | 87 | @implementation NSDictionary (FBLFunctionalAdditions) 88 | 89 | - (instancetype)fbl_filter:(NS_NOESCAPE BOOL (^)(id, id))predicate { 90 | NSParameterAssert(predicate); 91 | 92 | return FBLDictionaryFilter(self, predicate); 93 | } 94 | 95 | - (nullable id)fbl_first:(NS_NOESCAPE BOOL (^)(id, id))predicate { 96 | NSParameterAssert(predicate); 97 | 98 | return FBLDictionaryFirst(self, predicate); 99 | } 100 | 101 | - (NSArray *)fbl_flatMap:(NS_NOESCAPE id (^)(id, id))mapper { 102 | NSParameterAssert(mapper); 103 | 104 | return FBLDictionaryFlatMap(self, mapper); 105 | } 106 | 107 | - (void)fbl_forEach:(NS_NOESCAPE void (^)(id, id))block { 108 | NSParameterAssert(block); 109 | 110 | FBLDictionaryForEach(self, block); 111 | } 112 | 113 | - (NSArray *)fbl_map:(NS_NOESCAPE id (^)(id, id))mapper { 114 | NSParameterAssert(mapper); 115 | 116 | return FBLDictionaryMap(self, mapper); 117 | } 118 | 119 | - (NSDictionary *)fbl_mapValues:(NS_NOESCAPE id (^)(id))mapper { 120 | NSParameterAssert(mapper); 121 | 122 | return FBLDictionaryMapValues(self, mapper); 123 | } 124 | 125 | - (nullable id)fbl_reduce:(nullable NS_NOESCAPE id)initialValue 126 | combine:(NS_NOESCAPE id (^)(id, id, id))reducer { 127 | NSParameterAssert(reducer); 128 | 129 | return FBLDictionaryReduce(self, initialValue, reducer); 130 | } 131 | 132 | - (NSArray *)fbl_zip:(id)container { 133 | NSParameterAssert([self isKindOfClass:[NSDictionary class]]); 134 | NSParameterAssert( 135 | [container isKindOfClass:[NSDictionary class]] || [container isKindOfClass:[NSArray class]] || 136 | [container isKindOfClass:[NSSet class]] || [container isKindOfClass:[NSOrderedSet class]]); 137 | 138 | return FBLZip(self, container); 139 | } 140 | 141 | @end 142 | -------------------------------------------------------------------------------- /Sources/FBLFunctional/NSObject+FBLFunctional.m: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2018 Google Inc. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at: 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import "NSArray+FBLFunctional.h" 18 | #import "NSOrderedSet+FBLFunctional.h" 19 | #import "NSSet+FBLFunctional.h" 20 | 21 | NSArray *FBLZip(id container1, id container2) { 22 | NSMutableArray *result = [[NSMutableArray alloc] init]; 23 | NSEnumerator *enumerator1 = [container1 objectEnumerator]; 24 | NSEnumerator *enumerator2 = [container2 objectEnumerator]; 25 | for (;;) { 26 | id object1 = [enumerator1 nextObject]; 27 | id object2 = [enumerator2 nextObject]; 28 | if (!object1 || !object2) break; 29 | [result addObject:@[ object1, object2 ]]; 30 | } 31 | return result; 32 | } 33 | 34 | static NSArray *FBLArrayFromContainer(id container) { 35 | NSArray *result = @[]; 36 | if ([container isKindOfClass:[NSArray class]]) { 37 | result = container; 38 | } else if ([container isKindOfClass:[NSSet class]]) { 39 | result = [container allObjects]; 40 | } else if ([container isKindOfClass:[NSOrderedSet class]]) { 41 | result = [container array]; 42 | } 43 | return result; 44 | } 45 | 46 | /** 47 | Compares object classes similarly to isKindOfClass, which doesn't work for class clusters: 48 | NSArray isn't kind of class NSArray when two instances are compared. 49 | This method compares each instance to generic container class instead. 50 | */ 51 | static BOOL FBLSameKindContainers(id container1, id container2) { 52 | // Both containers are NSArrays. 53 | if ([container1 isKindOfClass:[NSArray class]] && [container2 isKindOfClass:[NSArray class]]) { 54 | return YES; 55 | } 56 | // Both containers are NSOrderedSets. 57 | if ([container1 isKindOfClass:[NSOrderedSet class]] && 58 | [container2 isKindOfClass:[NSOrderedSet class]]) { 59 | return YES; 60 | } 61 | // Both containers are NSSets. 62 | if ([container1 isKindOfClass:[NSSet class]] && [container2 isKindOfClass:[NSSet class]]) { 63 | return YES; 64 | } 65 | return NO; 66 | } 67 | 68 | static id FBLFilter(id container, BOOL (^predicate)(id)) { 69 | id result = [[[container class] new] mutableCopy]; 70 | for (id object in container) { 71 | if (predicate(object)) { 72 | [result addObject:object]; 73 | } 74 | } 75 | return result; 76 | } 77 | 78 | static id __nullable FBLFirst(id container, BOOL (^predicate)(id)) { 79 | for (id object in container) { 80 | if (predicate(object)) { 81 | return object; 82 | } 83 | } 84 | return nil; 85 | } 86 | 87 | static NSArray *FBLFlatMap(id container, id __nullable (^mapper)(id)) { 88 | NSMutableArray *result = [[NSMutableArray alloc] init]; 89 | for (id object in container) { 90 | id mapped = mapper(object); 91 | if (FBLSameKindContainers(container, mapped)) { 92 | [result addObjectsFromArray:FBLArrayFromContainer(mapped)]; 93 | } else if (mapped) { 94 | [result addObject:mapped]; 95 | } 96 | } 97 | return result; 98 | } 99 | 100 | static void FBLForEach(id container, void (^block)(id)) { 101 | for (id object in container) { 102 | block(object); 103 | } 104 | } 105 | 106 | static NSArray *FBLMap(id container, id __nullable (^mapper)(id)) { 107 | NSMutableArray *result = [[NSMutableArray alloc] init]; 108 | for (id object in container) { 109 | id mapped = mapper(object); 110 | [result addObject:mapped ?: [NSNull null]]; 111 | } 112 | return result; 113 | } 114 | 115 | static id __nullable FBLReduce(id container, id __nullable initialValue, 116 | id __nullable (^reducer)(id __nullable, id)) { 117 | id result = initialValue; 118 | for (id object in container) { 119 | result = reducer(result, object); 120 | } 121 | return result; 122 | } 123 | 124 | /// Common implementation for NSArray, NSSet and NSOrderedSet to avoid boilerplate code. 125 | @implementation NSObject (FBLFunctionalAdditions) 126 | 127 | - (instancetype)fbl_filter:(BOOL (^)(id))predicate { 128 | NSParameterAssert([self isKindOfClass:[NSArray class]] || [self isKindOfClass:[NSSet class]] || 129 | [self isKindOfClass:[NSOrderedSet class]]); 130 | NSParameterAssert(predicate); 131 | 132 | return FBLFilter((id)self, predicate); 133 | } 134 | 135 | - (nullable id)fbl_first:(BOOL (^)(id))predicate { 136 | NSParameterAssert([self isKindOfClass:[NSArray class]] || [self isKindOfClass:[NSSet class]] || 137 | [self isKindOfClass:[NSOrderedSet class]]); 138 | NSParameterAssert(predicate); 139 | 140 | return FBLFirst((id)self, predicate); 141 | } 142 | 143 | - (NSArray *)fbl_flatMap:(id (^)(id))mapper { 144 | NSParameterAssert([self isKindOfClass:[NSArray class]] || [self isKindOfClass:[NSSet class]] || 145 | [self isKindOfClass:[NSOrderedSet class]]); 146 | NSParameterAssert(mapper); 147 | 148 | return FBLFlatMap((id)self, mapper); 149 | } 150 | 151 | - (void)fbl_forEach:(void (^)(id))block { 152 | NSParameterAssert([self isKindOfClass:[NSArray class]] || [self isKindOfClass:[NSSet class]] || 153 | [self isKindOfClass:[NSOrderedSet class]]); 154 | NSParameterAssert(block); 155 | 156 | FBLForEach((id)self, block); 157 | } 158 | 159 | - (NSArray *)fbl_map:(id (^)(id))mapper { 160 | NSParameterAssert([self isKindOfClass:[NSArray class]] || [self isKindOfClass:[NSSet class]] || 161 | [self isKindOfClass:[NSOrderedSet class]]); 162 | NSParameterAssert(mapper); 163 | 164 | return FBLMap((id)self, mapper); 165 | } 166 | 167 | - (nullable id)fbl_reduce:(nullable id)initialValue combine:(id (^)(id, id))reducer { 168 | NSParameterAssert([self isKindOfClass:[NSArray class]] || [self isKindOfClass:[NSSet class]] || 169 | [self isKindOfClass:[NSOrderedSet class]]); 170 | NSParameterAssert(reducer); 171 | 172 | return FBLReduce((id)self, initialValue, reducer); 173 | } 174 | 175 | - (NSArray *)fbl_zip:(id)container { 176 | NSParameterAssert([self isKindOfClass:[NSArray class]] || [self isKindOfClass:[NSSet class]] || 177 | [self isKindOfClass:[NSOrderedSet class]]); 178 | NSParameterAssert([container isKindOfClass:[NSArray class]] || 179 | [container isKindOfClass:[NSSet class]] || 180 | [container isKindOfClass:[NSOrderedSet class]]); 181 | 182 | return FBLZip(self, container); 183 | } 184 | 185 | @end 186 | -------------------------------------------------------------------------------- /Sources/FBLFunctional/include/FBLFunctional.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2018 Google Inc. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at: 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import "NSArray+FBLFunctional.h" 18 | #import "NSDictionary+FBLFunctional.h" 19 | #import "NSOrderedSet+FBLFunctional.h" 20 | #import "NSSet+FBLFunctional.h" 21 | -------------------------------------------------------------------------------- /Sources/FBLFunctional/include/NSArray+FBLFunctional.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2018 Google Inc. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at: 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | @interface NSArray(FBLFunctionalAdditions) 22 | 23 | typedef void (^FBLFunctionalArrayEnumeratorBlock)(ObjectType value); 24 | typedef id __nullable (^FBLFunctionalArrayMapperBlock)(ObjectType value); 25 | typedef BOOL (^FBLFunctionalArrayPredicateBlock)(ObjectType value); 26 | typedef id __nullable (^FBLFunctionalArrayReducerBlock)(id __nullable accumulator, 27 | ObjectType value); 28 | 29 | /** 30 | Returns an array containing receiver's elements that satisfy the given predicate. 31 | */ 32 | - (instancetype)fbl_filter:(NS_NOESCAPE FBLFunctionalArrayPredicateBlock)predicate 33 | NS_SWIFT_UNAVAILABLE(""); 34 | 35 | /** 36 | Returns the first element of the receiver that satisfies the given predicate. 37 | */ 38 | - (nullable ObjectType)fbl_first:(NS_NOESCAPE FBLFunctionalArrayPredicateBlock)predicate 39 | NS_SWIFT_UNAVAILABLE(""); 40 | 41 | /** 42 | Returns an array containing the results of mapping the given mapper over receiver’s elements. 43 | Mapped nil is ignored. Mapped NSArray is flattened: its elements are appended to the results. 44 | */ 45 | - (NSArray *)fbl_flatMap:(NS_NOESCAPE FBLFunctionalArrayMapperBlock)mapper NS_SWIFT_UNAVAILABLE(""); 46 | 47 | /** 48 | Calls the given block on each element of the receiver in the same order as a for-in loop. 49 | */ 50 | - (void)fbl_forEach:(NS_NOESCAPE FBLFunctionalArrayEnumeratorBlock)block NS_SWIFT_UNAVAILABLE(""); 51 | 52 | /** 53 | Returns an array containing the results of mapping the given mapper over receiver’s elements. 54 | Mapped nil appears as NSNull in resulting array. 55 | */ 56 | - (NSArray *)fbl_map:(NS_NOESCAPE FBLFunctionalArrayMapperBlock)mapper NS_SWIFT_UNAVAILABLE(""); 57 | 58 | /** 59 | Returns the result of combining receiver's elements using the given reducer. 60 | */ 61 | - (nullable id)fbl_reduce:(nullable id)initialValue 62 | combine:(NS_NOESCAPE FBLFunctionalArrayReducerBlock)reducer 63 | NS_SWIFT_UNAVAILABLE(""); 64 | 65 | /** 66 | Returns an array of pairs built out of the receiver's and provided elements. If the two containers 67 | have different counts, the resulting array is the same count as the shorter container. 68 | */ 69 | - (NSArray *)fbl_zip:(id)container NS_SWIFT_UNAVAILABLE(""); 70 | 71 | @end 72 | 73 | NS_ASSUME_NONNULL_END 74 | -------------------------------------------------------------------------------- /Sources/FBLFunctional/include/NSDictionary+FBLFunctional.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2018 Google Inc. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at: 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | @interface NSDictionary(FBLFunctionalAdditions) 22 | 23 | typedef void (^FBLFunctionalDictionaryEnumeratorBlock)(KeyType key, ObjectType value); 24 | typedef id __nullable (^FBLFunctionalDictionaryMapperBlock)(KeyType key, ObjectType value); 25 | typedef BOOL (^FBLFunctionalDictionaryPredicateBlock)(KeyType key, ObjectType value); 26 | typedef id __nullable (^FBLFunctionalDictionaryReducerBlock)(id __nullable accumulator, KeyType key, 27 | ObjectType value); 28 | typedef id __nullable (^FBLFunctionalDictionaryValueMapperBlock)(ObjectType value); 29 | 30 | /** 31 | Returns a dictionary containing receiver's elements that satisfy the given predicate. 32 | */ 33 | - (instancetype)fbl_filter:(NS_NOESCAPE FBLFunctionalDictionaryPredicateBlock)predicate 34 | NS_SWIFT_UNAVAILABLE(""); 35 | 36 | /** 37 | Returns the key of the first element of the receiver that satisfies the given predicate. 38 | */ 39 | - (nullable KeyType)fbl_first:(NS_NOESCAPE FBLFunctionalDictionaryPredicateBlock)predicate 40 | NS_SWIFT_UNAVAILABLE(""); 41 | 42 | /** 43 | Returns an array containing the results of mapping the given mapper over receiver’s elements. 44 | Mapped nil is ignored. Mapped NSDictionary is flattened: its values are appended to the results. 45 | */ 46 | - (NSArray *)fbl_flatMap:(NS_NOESCAPE FBLFunctionalDictionaryMapperBlock)mapper 47 | NS_SWIFT_UNAVAILABLE(""); 48 | 49 | /** 50 | Calls the given block on each element of the receiver in the same order as a for-in loop. 51 | */ 52 | - (void)fbl_forEach:(NS_NOESCAPE FBLFunctionalDictionaryEnumeratorBlock)block 53 | NS_SWIFT_UNAVAILABLE(""); 54 | 55 | /** 56 | Returns an array containing the results of mapping the given mapper over receiver’s elements. 57 | Mapped nil appears as NSNull in resulting array. 58 | */ 59 | - (NSArray *)fbl_map:(NS_NOESCAPE FBLFunctionalDictionaryMapperBlock)mapper 60 | NS_SWIFT_UNAVAILABLE(""); 61 | 62 | /** 63 | Returns a dictionary containing receiver’s keys with the values transformed by the given mapper. 64 | Mapped nil appears as NSNull in resulting array. 65 | */ 66 | - (NSDictionary *)fbl_mapValues: 67 | (NS_NOESCAPE FBLFunctionalDictionaryValueMapperBlock)mapper NS_SWIFT_UNAVAILABLE(""); 68 | 69 | /** 70 | Returns the result of combining receiver's elements using the given reducer. 71 | */ 72 | - (nullable id)fbl_reduce:(nullable id)initialValue 73 | combine:(NS_NOESCAPE FBLFunctionalDictionaryReducerBlock)reducer 74 | NS_SWIFT_UNAVAILABLE(""); 75 | 76 | /** 77 | Returns an array of pairs built out of the receiver's and provided elements. If the two containers 78 | have different counts, the resulting array is the same count as the shorter container. 79 | */ 80 | - (NSArray *)fbl_zip:(id)container NS_SWIFT_UNAVAILABLE(""); 81 | 82 | @end 83 | 84 | NS_ASSUME_NONNULL_END 85 | -------------------------------------------------------------------------------- /Sources/FBLFunctional/include/NSOrderedSet+FBLFunctional.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2018 Google Inc. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at: 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | @interface NSOrderedSet(FBLFunctionalAdditions) 22 | 23 | typedef void (^FBLFunctionalOrderedSetEnumeratorBlock)(ObjectType value); 24 | typedef id __nullable (^FBLFunctionalOrderedSetMapperBlock)(ObjectType value); 25 | typedef BOOL (^FBLFunctionalOrderedSetPredicateBlock)(ObjectType value); 26 | typedef id __nullable (^FBLFunctionalOrderedSetReducerBlock)(id __nullable accumulator, 27 | ObjectType value); 28 | 29 | /** 30 | Returns an ordered set containing receiver's elements that satisfy the given predicate. 31 | */ 32 | - (instancetype)fbl_filter:(NS_NOESCAPE FBLFunctionalOrderedSetPredicateBlock)predicate 33 | NS_SWIFT_UNAVAILABLE(""); 34 | 35 | /** 36 | Returns the first element of the receiver that satisfies the given predicate. 37 | */ 38 | - (nullable ObjectType)fbl_first:(NS_NOESCAPE FBLFunctionalOrderedSetPredicateBlock)predicate 39 | NS_SWIFT_UNAVAILABLE(""); 40 | 41 | /** 42 | Returns an array containing the results of mapping the given mapper over receiver’s elements. 43 | Mapped nil is ignored. Mapped NSOrderedSet is flattened: its elements are appended to the results. 44 | */ 45 | - (NSArray *)fbl_flatMap:(NS_NOESCAPE FBLFunctionalOrderedSetMapperBlock)mapper 46 | NS_SWIFT_UNAVAILABLE(""); 47 | 48 | /** 49 | Calls the given block on each element of the receiver in the same order as a for-in loop. 50 | */ 51 | - (void)fbl_forEach:(NS_NOESCAPE FBLFunctionalOrderedSetEnumeratorBlock)block 52 | NS_SWIFT_UNAVAILABLE(""); 53 | 54 | /** 55 | Returns an array containing the results of mapping the given mapper over receiver’s elements. 56 | Mapped nil appears as NSNull in resulting array. 57 | */ 58 | - (NSArray *)fbl_map:(NS_NOESCAPE FBLFunctionalOrderedSetMapperBlock)mapper 59 | NS_SWIFT_UNAVAILABLE(""); 60 | 61 | /** 62 | Returns the result of combining receiver's elements using the given reducer. 63 | */ 64 | - (nullable id)fbl_reduce:(nullable id)initial 65 | combine:(NS_NOESCAPE FBLFunctionalOrderedSetReducerBlock)reducer 66 | NS_SWIFT_UNAVAILABLE(""); 67 | 68 | /** 69 | Returns an array of pairs built out of the receiver's and provided elements. If the two containers 70 | have different counts, the resulting array is the same count as the shorter container. 71 | */ 72 | - (NSArray *)fbl_zip:(id)container NS_SWIFT_UNAVAILABLE(""); 73 | 74 | @end 75 | 76 | NS_ASSUME_NONNULL_END 77 | -------------------------------------------------------------------------------- /Sources/FBLFunctional/include/NSSet+FBLFunctional.h: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2018 Google Inc. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at: 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import 18 | 19 | NS_ASSUME_NONNULL_BEGIN 20 | 21 | @interface NSSet(FBLFunctionalAdditions) 22 | 23 | typedef void (^FBLFunctionalSetEnumeratorBlock)(ObjectType value); 24 | typedef id __nullable (^FBLFunctionalSetMapperBlock)(ObjectType value); 25 | typedef BOOL (^FBLFunctionalSetPredicateBlock)(ObjectType value); 26 | typedef id __nullable (^FBLFunctionalSetReducerBlock)(id __nullable accumulator, ObjectType value); 27 | 28 | /** 29 | Returns a set containing receiver's elements that satisfy the given predicate. 30 | */ 31 | - (instancetype)fbl_filter:(NS_NOESCAPE FBLFunctionalSetPredicateBlock)predicate 32 | NS_SWIFT_UNAVAILABLE(""); 33 | 34 | /** 35 | Returns the first element of the receiver that satisfies the given predicate. 36 | */ 37 | - (nullable ObjectType)fbl_first:(NS_NOESCAPE FBLFunctionalSetPredicateBlock)predicate 38 | NS_SWIFT_UNAVAILABLE(""); 39 | 40 | /** 41 | Returns an array containing the results of mapping the given mapper over receiver’s elements. 42 | Mapped nil is ignored. Mapped NSSet is flattened: its elements are appended to the results. 43 | */ 44 | - (NSArray *)fbl_flatMap:(NS_NOESCAPE FBLFunctionalSetMapperBlock)mapper NS_SWIFT_UNAVAILABLE(""); 45 | 46 | /** 47 | Calls the given block on each element of the receiver in the same order as a for-in loop. 48 | */ 49 | - (void)fbl_forEach:(NS_NOESCAPE FBLFunctionalSetEnumeratorBlock)block NS_SWIFT_UNAVAILABLE(""); 50 | 51 | /** 52 | Returns an array containing the results of mapping the given mapper over receiver’s elements. 53 | Mapped nil appears as NSNull in resulting array. 54 | */ 55 | - (NSArray *)fbl_map:(NS_NOESCAPE FBLFunctionalSetMapperBlock)mapper NS_SWIFT_UNAVAILABLE(""); 56 | 57 | /** 58 | Returns the result of combining receiver's elements using the given reducer. 59 | */ 60 | - (nullable id)fbl_reduce:(nullable id)initial 61 | combine:(NS_NOESCAPE FBLFunctionalSetReducerBlock)reducer 62 | NS_SWIFT_UNAVAILABLE(""); 63 | 64 | /** 65 | Returns an array of pairs built out of the receiver's and provided elements. If the two containers 66 | have different counts, the resulting array is the same count as the shorter container. 67 | */ 68 | - (NSArray *)fbl_zip:(id)container NS_SWIFT_UNAVAILABLE(""); 69 | 70 | @end 71 | 72 | NS_ASSUME_NONNULL_END 73 | -------------------------------------------------------------------------------- /Sources/FBLFunctional/include/framework.modulemap: -------------------------------------------------------------------------------- 1 | framework module FBLFunctional { 2 | umbrella header "FBLFunctional.h" 3 | 4 | header "NSArray+FBLFunctional.h" 5 | header "NSDictionary+FBLFunctional.h" 6 | header "NSOrderedSet+FBLFunctional.h" 7 | header "NSSet+FBLFunctional.h" 8 | 9 | export * 10 | } 11 | -------------------------------------------------------------------------------- /Sources/FBLFunctional/include/module.modulemap: -------------------------------------------------------------------------------- 1 | module FBLFunctional { 2 | umbrella header "FBLFunctional.h" 3 | 4 | header "NSArray+FBLFunctional.h" 5 | header "NSDictionary+FBLFunctional.h" 6 | header "NSOrderedSet+FBLFunctional.h" 7 | header "NSSet+FBLFunctional.h" 8 | 9 | export * 10 | } 11 | -------------------------------------------------------------------------------- /Tests/FBLFunctionalTests/NSArray+FBLFunctionalTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2018 Google Inc. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at: 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import "NSArray+FBLFunctional.h" 18 | 19 | #import 20 | 21 | @interface NSArrayFBLFunctionalTests : XCTestCase 22 | @end 23 | 24 | @implementation NSArrayFBLFunctionalTests 25 | 26 | - (void)testFilterArray { 27 | // Arrange. 28 | NSArray *originalArray = @[ @13, @42, @0 ]; 29 | NSArray *expectedArray = @[ @13, @42 ]; 30 | 31 | // Act. 32 | NSArray *resultingArray = [originalArray fbl_filter:^BOOL(NSNumber *value) { 33 | return value.integerValue > 0; 34 | }]; 35 | 36 | // Assert. 37 | XCTAssertEqualObjects(resultingArray, expectedArray); 38 | } 39 | 40 | - (void)testFirstArray { 41 | // Arrange. 42 | NSArray *originalArray = @[ @13, @42, @100 ]; 43 | NSNumber *expectedValue = @42; 44 | 45 | // Act. 46 | NSNumber *resultingValue = [originalArray fbl_first:^BOOL(NSNumber *value) { 47 | return value.integerValue > 20; 48 | }]; 49 | 50 | // Assert. 51 | XCTAssertEqualObjects(resultingValue, expectedValue); 52 | } 53 | 54 | - (void)testFlatMapArray { 55 | // Arrange. 56 | NSArray *> *originalArray = @[ @[ @13, @42 ], @[ @14, @43 ], @[] ]; 57 | NSArray *expectedArray = @[ @13, @42, @14, @43 ]; 58 | 59 | // Act. 60 | NSArray *resultingArray = [originalArray fbl_flatMap:^id(NSArray *value) { 61 | return value.count > 0 ? value : nil; 62 | }]; 63 | 64 | // Assert. 65 | XCTAssertEqualObjects(resultingArray, expectedArray); 66 | } 67 | 68 | - (void)testForEachArray { 69 | // Arrange. 70 | NSArray *originalArray = @[ @13, @42, @100 ]; 71 | NSMutableArray *resultingArray = [[NSMutableArray alloc] init]; 72 | 73 | // Act. 74 | [originalArray fbl_forEach:^(NSNumber *value) { 75 | [resultingArray addObject:value]; 76 | }]; 77 | 78 | // Assert. 79 | XCTAssertEqualObjects(originalArray, resultingArray); 80 | } 81 | 82 | - (void)testMapArray { 83 | // Arrange. 84 | NSArray *originalArray = @[ @13, @42, @0 ]; 85 | NSArray *expectedArray = @[ @"13", @"42", (NSString *)[NSNull null] ]; 86 | 87 | // Act. 88 | NSArray *resultingArray = [originalArray fbl_map:^id(NSNumber *value) { 89 | if (value.integerValue == 0) { 90 | return nil; 91 | } 92 | return value.stringValue; 93 | }]; 94 | 95 | // Assert. 96 | XCTAssertEqualObjects(resultingArray, expectedArray); 97 | } 98 | 99 | - (void)testReduceArray { 100 | // Arrange. 101 | NSArray *originalArray = @[ @13, @42, @100 ]; 102 | NSNumber *expectedValue = @(13 + 42 + 100); 103 | 104 | // Act. 105 | NSNumber *resultingValue = 106 | [originalArray fbl_reduce:@0 107 | combine:^NSNumber *(NSNumber *accumulator, NSNumber *value) { 108 | return @(accumulator.integerValue + value.integerValue); 109 | }]; 110 | 111 | // Assert. 112 | XCTAssertEqualObjects(resultingValue, expectedValue); 113 | } 114 | 115 | - (void)testZipArray { 116 | // Arrange. 117 | NSArray *array1 = @[ @13, @42, @101 ]; 118 | NSArray *array2 = @[ @"100", @"14" ]; 119 | NSArray *expectedArray = @[ @[ @13, @"100" ], @[ @42, @"14" ] ]; 120 | 121 | // Act. 122 | NSArray *resultingArray = [array1 fbl_zip:array2]; 123 | 124 | // Assert. 125 | XCTAssertEqualObjects(resultingArray, expectedArray); 126 | } 127 | 128 | - (void)testZipArrayWithDifferentContainerTypes { 129 | // Arrange. 130 | NSArray *array = @[ @13, @42, @101 ]; 131 | NSSet *set = [NSSet setWithArray:@[ @13, @42 ]]; 132 | NSUInteger expectedCount = MIN(array.count, set.count); 133 | 134 | // Act. 135 | NSArray *resultingArray = [array fbl_zip:set]; 136 | 137 | // Assert. 138 | XCTAssertEqual(resultingArray.count, expectedCount); 139 | for (NSArray *array in resultingArray) { 140 | XCTAssertTrue([array containsObject:array.firstObject]); 141 | XCTAssertTrue([set containsObject:array.lastObject]); 142 | } 143 | } 144 | 145 | @end 146 | -------------------------------------------------------------------------------- /Tests/FBLFunctionalTests/NSDictionary+FBLFunctionalTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2018 Google Inc. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at: 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import "NSDictionary+FBLFunctional.h" 18 | 19 | #import 20 | 21 | @interface NSDictionaryFBLFunctionalTests : XCTestCase 22 | @end 23 | 24 | @implementation NSDictionaryFBLFunctionalTests 25 | 26 | - (void)testFilterDictionary { 27 | // Arrange. 28 | NSDictionary *originalDictionary = @{ @"1" : @12, @"2" : @40, @"0" : @0 }; 29 | NSDictionary *expectedDictionary = @{ @"1" : @12, @"2" : @40 }; 30 | 31 | // Act. 32 | NSDictionary *resultingDictionary = 33 | [originalDictionary fbl_filter:^BOOL(NSString __unused *_, NSNumber *value) { 34 | return value.integerValue > 0; 35 | }]; 36 | 37 | // Assert. 38 | XCTAssertEqualObjects(resultingDictionary, expectedDictionary); 39 | } 40 | 41 | - (void)testFirstDictionary { 42 | // Arrange. 43 | NSDictionary *originalDictionary = @{ @"1" : @13, @"2" : @42, @"3" : @0 }; 44 | NSString *expectedKey = @"2"; 45 | 46 | // Act. 47 | NSString *resultingKey = 48 | [originalDictionary fbl_first:^BOOL(NSString __unused *_, NSNumber *value) { 49 | return value.integerValue > 20; 50 | }]; 51 | 52 | // Assert. 53 | XCTAssertEqualObjects(resultingKey, expectedKey); 54 | } 55 | 56 | - (void)testForEachDictionary { 57 | // Arrange. 58 | NSDictionary *originalDictionary = @{ @"1" : @13, @"2" : @42, @"3" : @0 }; 59 | NSMutableDictionary *expectedDictionary = 60 | [[NSMutableDictionary alloc] init]; 61 | 62 | // Act. 63 | [originalDictionary fbl_forEach:^(NSString *key, NSNumber *value) { 64 | expectedDictionary[key] = value; 65 | }]; 66 | 67 | // Assert. 68 | XCTAssertEqualObjects(originalDictionary, expectedDictionary); 69 | } 70 | 71 | - (void)testFlatMapDictionary { 72 | // Arrange. 73 | NSDictionary *> *originalDictionary = 74 | @{ @1 : @{@"1" : @13}, 75 | @2 : @{@"2" : @42}, 76 | @3 : @{} }; 77 | NSArray *> *expectedArray = @[ 78 | @{ @"1" : @13 }, 79 | @{ @"2" : @42 } 80 | ]; 81 | 82 | // Act. 83 | NSArray *> *resultingArray = [originalDictionary 84 | fbl_flatMap:^id(NSNumber *key, NSDictionary *value) { 85 | return value.count > 0 ? @{key : value} : nil; 86 | }]; 87 | 88 | // Assert. 89 | XCTAssertEqualObjects(resultingArray, expectedArray); 90 | } 91 | 92 | - (void)testMapDictionary { 93 | // Arrange. 94 | NSDictionary *originalDictionary = @{ @"1" : @12, @"2" : @40, @"0" : @0 }; 95 | NSArray *expectedArray = @[ @"13", @"42", (NSString *)[NSNull null] ]; 96 | 97 | // Act. 98 | NSArray *resultingArray = 99 | [originalDictionary fbl_map:^id(NSString *key, NSNumber *value) { 100 | NSInteger sum = key.integerValue + value.integerValue; 101 | if (sum == 0) { 102 | return nil; 103 | } 104 | return @(sum).stringValue; 105 | }]; 106 | 107 | // Assert. 108 | XCTAssertEqualObjects(resultingArray, expectedArray); 109 | } 110 | 111 | - (void)testMapValuesDictionary { 112 | // Arrange. 113 | NSDictionary *> *originalDictionary = 114 | @{ @1 : @[ @1, @12 ], 115 | @2 : @[ @2, @40 ], 116 | @3 : @[ @3 ] }; 117 | NSDictionary *expectedDictionary = 118 | @{ @1 : @"13", 119 | @2 : @"42", 120 | @3 : (NSString *)[NSNull null] }; 121 | 122 | // Act. 123 | NSDictionary *resultingDictionary = 124 | [originalDictionary fbl_mapValues:^id(NSArray *value) { 125 | return value.count == 2 ? 126 | @(value.firstObject.integerValue + value.lastObject.integerValue).stringValue : 127 | nil; 128 | }]; 129 | 130 | // Assert. 131 | XCTAssertEqualObjects(resultingDictionary, expectedDictionary); 132 | } 133 | 134 | - (void)testZipDictionary { 135 | // Arrange. 136 | NSDictionary *dictionary1 = @{ @"1" : @12, @"2" : @40, @"0" : @0 }; 137 | NSDictionary *dictionary2 = @{@"3" : @"13", @"4" : @"42"}; 138 | NSUInteger expectedCount = MIN(dictionary1.count, dictionary2.count); 139 | 140 | // Act. 141 | NSArray *resultingArray = [dictionary1 fbl_zip:dictionary2]; 142 | 143 | // Assert. 144 | XCTAssertEqual(resultingArray.count, expectedCount); 145 | NSArray *dict1Values = dictionary1.allValues; 146 | NSArray *dict2Values = dictionary2.allValues; 147 | for (NSArray *array in resultingArray) { 148 | XCTAssertTrue([dict1Values containsObject:array.firstObject]); 149 | XCTAssertTrue([dict2Values containsObject:array.lastObject]); 150 | } 151 | } 152 | 153 | - (void)testZipDictionaryWithDifferentContainerTypes { 154 | // Arrange. 155 | NSDictionary *dictionary = @{ @"1" : @12, @"2" : @40 }; 156 | NSArray *array1 = @[ @"13", @"42", @"0" ]; 157 | NSUInteger expectedCount = MIN(dictionary.count, array1.count); 158 | 159 | // Act. 160 | NSArray *resultingArray = [dictionary fbl_zip:array1]; 161 | 162 | // Assert. 163 | XCTAssertEqual(resultingArray.count, expectedCount); 164 | NSArray *dictValues = dictionary.allValues; 165 | for (NSArray *array in resultingArray) { 166 | XCTAssertTrue([dictValues containsObject:array.firstObject]); 167 | XCTAssertTrue([array1 containsObject:array.lastObject]); 168 | } 169 | } 170 | 171 | @end 172 | -------------------------------------------------------------------------------- /Tests/FBLFunctionalTests/NSOrderedSet+FBLFunctionalTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2018 Google Inc. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at: 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import "NSOrderedSet+FBLFunctional.h" 18 | 19 | #import 20 | 21 | @interface NSOrderedSetFBLFunctionalTests : XCTestCase 22 | @end 23 | 24 | @implementation NSOrderedSetFBLFunctionalTests 25 | 26 | - (void)testFilterOrderedSet { 27 | // Arrange. 28 | NSOrderedSet *originalOrderedSet = 29 | [NSOrderedSet orderedSetWithArray:@[ @13, @42, @0 ]]; 30 | NSArray *expectedArray = @[ @13, @42 ]; 31 | 32 | // Act. 33 | NSOrderedSet *resultingSet = [originalOrderedSet fbl_filter:^BOOL(NSNumber *value) { 34 | return value.integerValue > 0; 35 | }]; 36 | 37 | // Assert. 38 | XCTAssertEqualObjects(resultingSet, [NSOrderedSet orderedSetWithArray:expectedArray]); 39 | } 40 | 41 | - (void)testFirstOrderedSet { 42 | // Arrange. 43 | NSOrderedSet *originalOrderedSet = 44 | [NSOrderedSet orderedSetWithArray:@[ @13, @42, @100 ]]; 45 | NSNumber *expectedValue = @42; 46 | 47 | // Act. 48 | NSNumber *resultingValue = [originalOrderedSet fbl_first:^BOOL(NSNumber *value) { 49 | return value.integerValue > 20; 50 | }]; 51 | 52 | // Assert. 53 | XCTAssertEqualObjects(resultingValue, expectedValue); 54 | } 55 | 56 | - (void)testFlatMapOrderedSet { 57 | // Arrange. 58 | NSOrderedSet *> *originalOrderedSet = 59 | [NSOrderedSet orderedSetWithArray:@[ 60 | [NSOrderedSet orderedSetWithArray:@[ @13, @42 ]], 61 | [NSOrderedSet orderedSetWithArray:@[ @14, @43 ]], [NSOrderedSet orderedSetWithArray:@[]] 62 | ]]; 63 | NSArray *expectedArray = @[ @13, @42, @14, @43 ]; 64 | 65 | // Act. 66 | NSArray *resultingArray = 67 | [originalOrderedSet fbl_flatMap:^id(NSOrderedSet *value) { 68 | return value.count > 0 ? value : nil; 69 | }]; 70 | 71 | // Assert. 72 | XCTAssertEqualObjects(resultingArray, expectedArray); 73 | } 74 | 75 | - (void)testForEachOrderedSet { 76 | // Arrange. 77 | NSOrderedSet *originalOrderedSet = 78 | [NSOrderedSet orderedSetWithArray:@[ @13, @42, @100 ]]; 79 | NSMutableArray *expectedArray = [[NSMutableArray alloc] init]; 80 | 81 | // Act. 82 | [originalOrderedSet fbl_forEach:^(NSNumber *value) { 83 | [expectedArray addObject:value]; 84 | }]; 85 | 86 | // Assert. 87 | XCTAssertEqualObjects(originalOrderedSet, [NSOrderedSet orderedSetWithArray:expectedArray]); 88 | } 89 | 90 | - (void)testMapOrderedSet { 91 | // Arrange. 92 | NSOrderedSet *originalOrderedSet = 93 | [NSOrderedSet orderedSetWithArray:@[ @13, @42, @0 ]]; 94 | NSArray *expectedArray = @[ @"13", @"42", (NSString *)[NSNull null] ]; 95 | 96 | // Act. 97 | NSArray *resultingArray = [originalOrderedSet fbl_map:^id(NSNumber *value) { 98 | if (value.integerValue == 0) { 99 | return nil; 100 | } 101 | return value.stringValue; 102 | }]; 103 | 104 | // Assert. 105 | XCTAssertEqualObjects(resultingArray, expectedArray); 106 | } 107 | 108 | - (void)testReduceOrderedSet { 109 | // Arrange. 110 | NSOrderedSet *originalOrderedSet = 111 | [NSOrderedSet orderedSetWithArray:@[ @13, @42, @100 ]]; 112 | NSNumber *expectedValue = @(13 + 42 + 100); 113 | 114 | // Act. 115 | NSNumber *resultingValue = 116 | [originalOrderedSet fbl_reduce:@0 117 | combine:^NSNumber *(NSNumber *accumulator, NSNumber *value) { 118 | return @(accumulator.integerValue + value.integerValue); 119 | }]; 120 | 121 | // Assert. 122 | XCTAssertEqualObjects(resultingValue, expectedValue); 123 | } 124 | 125 | - (void)testZipOrderedSet { 126 | // Arrange. 127 | NSOrderedSet *orderedSet1 = [NSOrderedSet orderedSetWithArray:@[ @13, @42 ]]; 128 | NSOrderedSet *orderedSet2 = 129 | [NSOrderedSet orderedSetWithArray:@[ @"100", @"14", @"43" ]]; 130 | NSArray *expectedArray = @[ @[ @13, @"100" ], @[ @42, @"14" ] ]; 131 | 132 | // Act. 133 | NSArray *resultingArray = [orderedSet1 fbl_zip:orderedSet2]; 134 | 135 | // Assert. 136 | XCTAssertEqualObjects(resultingArray, expectedArray); 137 | } 138 | 139 | - (void)testZipOrderedSetWithDifferentContainerTypes { 140 | // Arrange. 141 | NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:@[ @13, @42 ]]; 142 | NSSet *set = [NSSet setWithArray:@[ @14, @43, @100 ]]; 143 | NSUInteger expectedCount = MIN(orderedSet.count, set.count); 144 | 145 | // Act. 146 | NSArray *resultingArray = [orderedSet fbl_zip:set]; 147 | 148 | // Assert. 149 | XCTAssertEqual(resultingArray.count, expectedCount); 150 | for (NSArray *array in resultingArray) { 151 | XCTAssertTrue([orderedSet containsObject:array.firstObject]); 152 | XCTAssertTrue([set containsObject:array.lastObject]); 153 | } 154 | } 155 | 156 | @end 157 | -------------------------------------------------------------------------------- /Tests/FBLFunctionalTests/NSSet+FBLFunctionalTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2018 Google Inc. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at: 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #import "NSSet+FBLFunctional.h" 18 | 19 | #import 20 | 21 | @interface NSSetFBLFunctionalTests : XCTestCase 22 | @end 23 | 24 | @implementation NSSetFBLFunctionalTests 25 | 26 | - (void)testFilterSet { 27 | // Arrange. 28 | NSSet *originalSet = [NSSet setWithArray:@[ @13, @42, @0 ]]; 29 | NSArray *expectedArray = @[ @13, @42 ]; 30 | 31 | // Act. 32 | NSSet *resultingSet = [originalSet fbl_filter:^BOOL(NSNumber *value) { 33 | return value.integerValue > 0; 34 | }]; 35 | 36 | // Assert. 37 | XCTAssertEqualObjects(resultingSet, [NSSet setWithArray:expectedArray]); 38 | } 39 | 40 | - (void)testFirstSet { 41 | // Arrange. 42 | NSSet *originalSet = [NSSet setWithArray:@[ @13, @42, @100 ]]; 43 | NSNumber *expectedValue = @42; 44 | 45 | // Act. 46 | NSNumber *resultingValue = [originalSet fbl_first:^BOOL(NSNumber *value) { 47 | return value.integerValue > 20; 48 | }]; 49 | 50 | // Assert. 51 | XCTAssertEqualObjects(resultingValue, expectedValue); 52 | } 53 | 54 | - (void)testFlatMapSet { 55 | // Arrange. 56 | NSSet *> *originalSet = [NSSet setWithArray:@[ 57 | [NSSet setWithArray:@[ @13, @42 ]], [NSSet setWithArray:@[ @14, @43 ]], [NSSet setWithArray:@[]] 58 | ]]; 59 | NSArray *expectedArray = @[ @13, @42, @14, @43 ]; 60 | 61 | // Act. 62 | NSArray *resultingArray = [originalSet fbl_flatMap:^id(NSSet *value) { 63 | return value.count > 0 ? value : nil; 64 | }]; 65 | 66 | // Assert. 67 | XCTAssertEqualObjects([NSSet setWithArray:resultingArray], [NSSet setWithArray:expectedArray]); 68 | } 69 | 70 | - (void)testForEachSet { 71 | // Arrange. 72 | NSSet *originalSet = [NSSet setWithArray:@[ @13, @42, @100 ]]; 73 | NSMutableArray *expectedArray = [[NSMutableArray alloc] init]; 74 | 75 | // Act. 76 | [originalSet fbl_forEach:^(NSNumber *value) { 77 | [expectedArray addObject:value]; 78 | }]; 79 | 80 | // Assert. 81 | XCTAssertEqualObjects(originalSet, [NSSet setWithArray:expectedArray]); 82 | } 83 | 84 | - (void)testMapSet { 85 | // Arrange. 86 | NSSet *originalSet = [NSSet setWithArray:@[ @13, @42, @0 ]]; 87 | NSArray *expectedArray = @[ @"13", @"42", (NSString *)[NSNull null] ]; 88 | 89 | // Act. 90 | NSArray *resultingArray = [originalSet fbl_map:^id(NSNumber *value) { 91 | if (value.integerValue == 0) { 92 | return nil; 93 | } 94 | return value.stringValue; 95 | }]; 96 | 97 | // Assert. 98 | XCTAssertEqualObjects([NSSet setWithArray:resultingArray], [NSSet setWithArray:expectedArray]); 99 | } 100 | 101 | - (void)testReduceSet { 102 | // Arrange. 103 | NSSet *originalSet = [NSSet setWithArray:@[ @13, @42, @100 ]]; 104 | NSNumber *expectedValue = @(13 + 42 + 100); 105 | 106 | // Act. 107 | NSNumber *resultingValue = 108 | [originalSet fbl_reduce:@0 109 | combine:^NSNumber *(NSNumber *accumulator, NSNumber *value) { 110 | return @(accumulator.integerValue + value.integerValue); 111 | }]; 112 | 113 | // Assert. 114 | XCTAssertEqualObjects(resultingValue, expectedValue); 115 | } 116 | 117 | - (void)testZipSet { 118 | // Arrange. 119 | NSSet *set1 = [NSSet setWithArray:@[ @13, @42 ]]; 120 | NSSet *set2 = [NSSet setWithArray:@[ @"100", @"14", @"43" ]]; 121 | NSUInteger expectedCount = MIN(set1.count, set2.count); 122 | 123 | // Act. 124 | NSArray *resultingArray = [set1 fbl_zip:set2]; 125 | 126 | // Assert. 127 | XCTAssertEqual(resultingArray.count, expectedCount); 128 | for (NSArray *array in resultingArray) { 129 | XCTAssertTrue([set1 containsObject:array.firstObject]); 130 | XCTAssertTrue([set2 containsObject:array.lastObject]); 131 | } 132 | } 133 | 134 | - (void)testZipSetWithDifferentContainerTypes { 135 | // Arrange. 136 | NSSet *set = [NSSet setWithArray:@[ @13, @42 ]]; 137 | NSArray *array = @[ @"100", @"14", @"43" ]; 138 | NSUInteger expectedCount = MIN(set.count, array.count); 139 | 140 | // Act. 141 | NSArray *resultingArray = [set fbl_zip:array]; 142 | 143 | // Assert. 144 | XCTAssertEqual(resultingArray.count, expectedCount); 145 | for (NSArray *array in resultingArray) { 146 | XCTAssertTrue([set containsObject:array.firstObject]); 147 | XCTAssertTrue([array containsObject:array.lastObject]); 148 | } 149 | } 150 | 151 | @end 152 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | git_repository( 2 | name = "bazel_skylib", 3 | remote = "https://github.com/bazelbuild/bazel-skylib.git", 4 | tag = "0.5.0", 5 | ) 6 | 7 | git_repository( 8 | name = "build_bazel_rules_apple", 9 | remote = "https://github.com/bazelbuild/rules_apple.git", 10 | tag = "0.6.0", 11 | ) 12 | 13 | git_repository( 14 | name = "build_bazel_rules_swift", 15 | remote = "https://github.com/bazelbuild/rules_swift.git", 16 | tag = "0.2.0", 17 | ) 18 | 19 | http_file( 20 | name = "xctestrunner", 21 | executable = 1, 22 | url = "https://github.com/google/xctestrunner/releases/download/0.2.3/ios_test_runner.par", 23 | ) 24 | --------------------------------------------------------------------------------