├── .gitignore ├── .swift-version ├── .swiftlint.yml ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── Logo ├── logo.png └── logo.sketch ├── Package.swift ├── README.md ├── Source ├── ArrayExtensions.swift ├── CGFloatExtensions.swift ├── CGPointExtensions.swift ├── DateExtensions.swift ├── DictionaryExtensions.swift ├── Info-tvOS.plist ├── Info.plist ├── IntExtensions.swift ├── RangeExtensions.swift ├── StringExtensions.swift ├── Swiftly.h └── Swiftly.swift ├── SwiftlyExt.podspec ├── SwiftlyExt.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── SwiftlyExt iOS.xcscheme │ ├── SwiftlyExt macOS.xcscheme │ ├── SwiftlyExt tvOS.xcscheme │ └── SwiftlyExt watchOS.xcscheme ├── SwiftlyExt.xcworkspace └── contents.xcworkspacedata └── Tests ├── ArrayTests.swift ├── CGFloatTests.swift ├── CGPointTests.swift ├── DateTests.swift ├── DictionaryTests.swift ├── Info.plist ├── IntTests.swift ├── StringTests.swift └── SwiftlyTests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | 6 | ## Build generated 7 | build/ 8 | DerivedData 9 | 10 | ## Various settings 11 | *.pbxuser 12 | !default.pbxuser 13 | *.mode1v3 14 | !default.mode1v3 15 | *.mode2v3 16 | !default.mode2v3 17 | *.perspectivev3 18 | !default.perspectivev3 19 | xcuserdata 20 | 21 | ## Other 22 | *.xccheckout 23 | *.moved-aside 24 | *.xcuserstate 25 | *.xcscmblueprint 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | *.ipa 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | .build/ 37 | 38 | # Carthage 39 | Carthage/Build -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 3.0 -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | included: 2 | - Source 3 | excluded: 4 | - Tests 5 | opt_in_rules: 6 | - attributes 7 | - empty_count 8 | - vertical_whitespace 9 | - closure_end_indentation 10 | - closure_spacing 11 | - explicit_init 12 | - first_where 13 | - operator_usage_whitespace 14 | - overridden_super_call 15 | - prohibited_super_call 16 | - redundant_nil_coalescing 17 | - switch_case_on_newline 18 | disabled_rules: 19 | - variable_name 20 | - file_length 21 | line_length: 200 22 | 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode8 3 | env: 4 | global: 5 | - LC_CTYPE=en_US.UTF-8 6 | - LANG=en_US.UTF-8 7 | - WORKSPACE=SwiftlyExt.xcworkspace 8 | - IOS_FRAMEWORK_SCHEME="SwiftlyExt iOS" 9 | - MACOS_FRAMEWORK_SCHEME="SwiftlyExt macOS" 10 | - TVOS_FRAMEWORK_SCHEME="SwiftlyExt tvOS" 11 | - WATCHOS_FRAMEWORK_SCHEME="SwiftlyExt watchOS" 12 | - IOS_SDK=iphonesimulator10.0 13 | - MACOS_SDK=macosx10.12 14 | - TVOS_SDK=appletvsimulator10.0 15 | - WATCHOS_SDK=watchsimulator3.0 16 | matrix: 17 | - DESTINATION="OS=3.0,name=Apple Watch - 42mm" SCHEME="$WATCHOS_FRAMEWORK_SCHEME" SDK="$WATCHOS_SDK" RUN_TESTS="NO" POD_LINT="NO" 18 | - DESTINATION="OS=2.0,name=Apple Watch - 42mm" SCHEME="$WATCHOS_FRAMEWORK_SCHEME" SDK="$WATCHOS_SDK" RUN_TESTS="NO" POD_LINT="NO" 19 | 20 | - DESTINATION="OS=10.0,name=iPhone 7 Plus" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" RUN_TESTS="YES" POD_LINT="YES" 21 | - DESTINATION="OS=9.0,name=iPhone 5" SCHEME="$IOS_FRAMEWORK_SCHEME" SDK="$IOS_SDK" RUN_TESTS="YES" POD_LINT="NO" 22 | 23 | - DESTINATION="OS=10.0,name=Apple TV 1080p" SCHEME="$TVOS_FRAMEWORK_SCHEME" SDK="$TVOS_SDK" RUN_TESTS="YES" POD_LINT="NO" 24 | - DESTINATION="OS=9.0,name=Apple TV 1080p" SCHEME="$TVOS_FRAMEWORK_SCHEME" SDK="$TVOS_SDK" RUN_TESTS="YES" POD_LINT="NO" 25 | 26 | - DESTINATION="arch=x86_64" SCHEME="$MACOS_FRAMEWORK_SCHEME" SDK="$MACOS_SDK" RUN_TESTS="YES" POD_LINT="NO" 27 | before_install: 28 | - gem install cocoapods --pre --no-rdoc --no-ri --no-document --quiet 29 | script: 30 | - set -o pipefail 31 | - xcodebuild -version 32 | - xcodebuild -showsdks 33 | 34 | # Build Framework in Debug and Run Tests if specified 35 | - if [ $RUN_TESTS == "YES" ]; then 36 | travis_retry xcodebuild -workspace "$WORKSPACE" -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO ENABLE_TESTABILITY=YES test | xcpretty; 37 | else 38 | travis_retry xcodebuild -workspace "$WORKSPACE" -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO build | xcpretty; 39 | fi 40 | 41 | # Build Framework in Release and Run Tests if specified 42 | - if [ $RUN_TESTS == "YES" ]; then 43 | travis_retry xcodebuild -workspace "$WORKSPACE" -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Release ONLY_ACTIVE_ARCH=NO ENABLE_TESTABILITY=YES test | xcpretty; 44 | else 45 | travis_retry xcodebuild -workspace "$WORKSPACE" -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Release ONLY_ACTIVE_ARCH=NO build | xcpretty; 46 | fi 47 | 48 | # Run `pod lib lint` if specified 49 | - if [ $POD_LINT == "YES" ]; then 50 | pod lib lint; 51 | fi 52 | after_success: 53 | - bash <(curl -s https://codecov.io/bash) -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | `SwiftlyExt` adheres to [Semantic Versioning](http://semver.org/). 3 | 4 | ## [1.3.0](https://github.com/khoiln/SwiftlyExt/releases/tag/1.3.0) 5 | 6 | Remove Equatable on E of .groupBy 7 | 8 | ## [1.2.0](https://github.com/khoiln/SwiftlyExt/releases/tag/1.2.0) 9 | 10 | Added .groupBy, .reject 11 | 12 | ## [1.1.0](https://github.com/khoiln/SwiftlyExt/releases/tag/1.1.0) 13 | 14 | Added Swiftly struct for public static methods 15 | Added Array .random, .sample, .sampleSize 16 | Added String .between, .count, .initials, .isEmail, .hasNumbers, .hasLetters, .isAlpha, .isAlphaNumeric 17 | 18 | ## [1.0.2](https://github.com/khoiln/SwiftlyExt/releases/tag/1.0.2) 19 | 20 | Added Array .without, .shuffle, .shuffled 21 | 22 | ## [1.0.1](https://github.com/khoiln/SwiftlyExt/releases/tag/1.0.1) 23 | 24 | Added Array static methods: xor, xorBy, xorWith 25 | 26 | ## [1.0](https://github.com/khoiln/SwiftlyExt/releases/tag/1.0) 27 | 28 | First stable release 🚀 29 | 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Swiftly 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /Logo/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoi-backyard/SwiftlyExt/bffa775744b33250411b88a98ae4edca9b4bcc85/Logo/logo.png -------------------------------------------------------------------------------- /Logo/logo.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/khoi-backyard/SwiftlyExt/bffa775744b33250411b88a98ae4edca9b4bcc85/Logo/logo.sketch -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | import PackageDescription 2 | 3 | let package = Package( 4 | name: "SwiftlyExt", 5 | exclude: ["Tests"] 6 | ) 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](Logo/logo.png) 2 | 3 | [![Build Status](https://travis-ci.org/khoiln/SwiftlyExt.svg?branch=master)](https://travis-ci.org/khoiln/SwiftlyExt) 4 | [![codecov](https://codecov.io/gh/khoiln/SwiftlyExt/branch/master/graph/badge.svg)](https://codecov.io/gh/khoiln/SwiftlyExt) 5 | [![CocoaPods Compatible](https://img.shields.io/cocoapods/v/SwiftlyExt.svg)](https://img.shields.io/cocoapods/v/SwiftlyExt.svg) 6 | [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 7 | ![Swift 3.0.x](https://img.shields.io/badge/Swift-3.0.x-orange.svg) 8 | [![Platform](https://img.shields.io/cocoapods/p/SwiftlyExt.svg?style=flat)](http://cocoadocs.org/docsets/SwiftlyExt) 9 | [![MIT](https://img.shields.io/badge/License-MIT-red.svg)](https://opensource.org/licenses/MIT) 10 | 11 | SwiftlyExt is a library that extends certain Swift standard types and classes using extension feature in the Swift language. 12 | 13 | - [Requirements](#requirements) 14 | - [Installation](#installation) 15 | - [Documentation via CocoaDocs](http://cocoadocs.org/docsets/SwiftlyExt/) 16 | - [FAQ](#faq) 17 | - [License](#license) 18 | 19 | ## Requirements 20 | 21 | - iOS 9.0+ / macOS 10.11+ / tvOS 9.0+ / watchOS 2.0+ 22 | - Xcode 8.0+ 23 | - Swift 3.0+ 24 | 25 | ## Installation 26 | 27 | ### CocoaPods 28 | 29 | [CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command: 30 | 31 | ```bash 32 | $ gem install cocoapods 33 | ``` 34 | 35 | > CocoaPods 1.1.0+ is required to build SwiftlyExt. 36 | 37 | To integrate SwiftlyExt into your Xcode project using CocoaPods, specify it in your `Podfile`: 38 | 39 | ```ruby 40 | source 'https://github.com/CocoaPods/Specs.git' 41 | platform :ios, '10.0' 42 | use_frameworks! 43 | 44 | target '' do 45 | pod 'SwiftlyExt', '~> 1.3' 46 | end 47 | ``` 48 | 49 | Then, run the following command: 50 | 51 | ```bash 52 | $ pod install 53 | ``` 54 | 55 | ### Carthage 56 | 57 | [Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. 58 | 59 | You can install Carthage with [Homebrew](http://brew.sh/) using the following command: 60 | 61 | ```bash 62 | $ brew update 63 | $ brew install carthage 64 | ``` 65 | 66 | To integrate SwiftlyExt into your Xcode project using Carthage, specify it in your `Cartfile`: 67 | 68 | ```ogdl 69 | github "khoiln/SwiftlyExt" ~> 1.3 70 | ``` 71 | 72 | Run `carthage update` to build the framework and drag the built `SwiftlyExt.framework` into your Xcode project. U 73 | 74 | ### Swift Package Manager 75 | 76 | Adding SwiftlyExt as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift` file. 77 | 78 | ```swift 79 | dependencies: [ 80 | .Package(url: "https://github.com/khoiln/SwiftlyExt.git", majorVersion: 1) 81 | ] 82 | ``` 83 | 84 | Note that the [Swift Package Manager](https://swift.org/package-manager/) is still in early design and development, but SwiftlyExt does support its use on supported platforms. 85 | 86 | ## Usage 87 | 88 | There are many handy usages of `SwiftlyExt`, head over [CocoaDocs](http://cocoadocs.org/docsets/SwiftlyExt/) for the comprehensive documentation. 89 | 90 | We'll try to list some of the cool examples here. 91 | 92 | ### Array Extensions 93 | 94 | ```swift 95 | [😀,🤡,❤️,💋].sample() // Return a random element 96 | // => 💋 97 | [😀,🤡,❤️,💋].sampleSize(2) // Return n random elements 98 | // => [🤡, 💋] 99 | [1, 2, 3, 4, 5].dropWhile { $0 < 3 } //Drop elements that passes the predicate from the beginning to end 100 | // => [3, 4, 5] 101 | [1, 2, 3, 4, 5].dropWhile { $0 < 3 }.some {$0 % 2 == 0} //And YES you can use method chaining too 👍 102 | // => true 103 | [0, 11, 28, 10].every { $0 % 2 == 0 } //Check if all elements in the array passed the condition 104 | // => false 105 | [0, 11, 28, 10].some { $0 % 2 != 0 } //Check if one of the element passes the condition 106 | // => true 107 | [1, 2, 3, 4, 5].findLastIndex {$0 % 2 == 0} //Find index of the last number which predicate return true for. 108 | // => 3 109 | [1, 2, 3, 4, 5].groupBy { $0 % 2 == 0 ? "even" : "odd"} //Group common elements from an array to a dictionary of [Hashable : [Element]] 110 | // => ["even": [2,4], "odd": [1,3,5]] 111 | // Any many more.... 112 | ``` 113 | 114 | ### Date Extensions 115 | 116 | ```swift 117 | let now = Date() 118 | let tmr = now.date(byAddingDays: 1) 119 | .date(byAddingMinutes: 20) // You could also add year, month... and other time units 120 | 121 | now.isBefore(tmr) 122 | // => true 123 | 124 | now?.toString(format: "dd/MM/yyyy HH:mm:ss") // Return the string representation for a date. 125 | // => "03/15/2017 14:34:22" 126 | 127 | tmr.year == 2017 // Access time unit properties 128 | tmr.hour == 14 129 | tmr.minute == 54 130 | ``` 131 | 132 | ### String Extensions 133 | 134 | ```swift 135 | "John Doe".initials // Return the initials of the String 136 | // => "JD" 137 | "swift@swiftly.com".isEmail // Email validation 138 | // => true 139 | "

💯

".between("

", "

") // Find the string between two string 140 | // => "💯" 141 | "01/01/1970 00:34:22".date(format: "dd/MM/yyyy HH:mm:ss") // Return a date from current string 142 | // => Date("01/01/1970 00:34:22") 143 | "https://github.com/Swiftly".base64Encoded // Return base64encoded string 144 | // => "aHR0cHM6Ly9naXRodWIuY29tL1N3aWZ0bHk=" 145 | "\n\n\n Swiftly ".trimmed.reversed // Trim newline and spaces and reverse the string 146 | // => "yltfiwS" 147 | "Swiftly\t\nString\nTest".urlEncoded // URL Encoded 148 | // => "Swiftly%09%0AString%0ATest" 149 | "https%3A%2F%2Fgithub.com%2Fkhoiln%2FSwiftlyEXT".urlDecoded // URL Decoded 150 | // => "https://github.com/khoiln/SwiftlyEXT" 151 | // Any many more.... 152 | ``` 153 | 154 | ### Int Extensions 155 | 156 | ```swift 157 | 1.upTo(3) { print($0) } 158 | // print 1, 2, 3 159 | 5.times { print("🐶") } // Run a block n times 160 | // print 🐶 5 times 161 | 1234.digits() // Convert integer to array of digits 162 | // => [1,2,3,4] 163 | 201.isIn(range: 200..<300) // Test whether a int is in a range 164 | // => true 165 | // And many more 166 | ``` 167 | 168 | ## How to contribute 169 | Any help or feedback is highly appreciated. Please refer to the [contributing guidelines](https://github.com/khoiln/SwiftlyExt/blob/master/CONTRIBUTING.md) for more information. 170 | 171 | ## License 172 | 173 | SwiftyExt is released under the MIT license. See [LICENSE](https://github.com/khoiln/SwiftlyExt/blob/master/LICENSE) for details. 174 | -------------------------------------------------------------------------------- /Source/ArrayExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArrayExtensions.swift 3 | // Swiftly 4 | // 5 | // Created by Khoi Lai on 26/09/2016. 6 | // Copyright © 2016 Khoi Lai. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension Array { 12 | /// Create an array of elements split in to groups by the length of size. 13 | /// If array can't be split evenly, the final chunk contains all the remain elements. 14 | /// - parameter size: The length of each chunk. 0 by default. 15 | /// 16 | /// - returns: The new array contains chunks 17 | func chunk(size: Int = 0) -> [[Element]] { 18 | var result = [[Element]]() 19 | if size < 1 { 20 | return result 21 | } 22 | let length = self.count 23 | var i = 0 24 | while i < length { 25 | let start = i 26 | i += size 27 | result.append(self.slice(start: start, end: i)) 28 | } 29 | return result 30 | } 31 | 32 | /// Creates a new array concatenating additional values. 33 | /// 34 | /// - parameter values: The values to concatenate. 35 | /// 36 | /// - returns: The new concatenated array. 37 | func concat(values: Element...) -> [Element] { 38 | var result = Array(self) 39 | result.append(contentsOf: values) 40 | return result 41 | } 42 | 43 | /// This method is like difference except that it accepts comparator which is invoked to compare elements of array to values. 44 | /// 45 | /// - parameter values: The values to exclude. 46 | /// - parameter comparator: The comparator invoked per element. 47 | /// 48 | /// - returns: Returns the new array of filtered values. 49 | func differenceWith(_ values: [Element], comparator: (Element, Element) -> Bool) -> [Element] { 50 | return self._baseDifference(with: values, comparator: comparator, iteratee: nil) 51 | } 52 | 53 | /// Creates a new array concatenating additional arrays. 54 | /// 55 | /// - parameter arrays: The arrays to concatenate. 56 | /// 57 | /// - returns: The new concatenated array. 58 | func concat(arrays: [Element]...) -> [Element] { 59 | var result = Array(self) 60 | for arr in arrays { 61 | result.append(contentsOf: arr) 62 | } 63 | return result 64 | } 65 | 66 | /// Creates a new sliced array with n elements dropped from the beginning. 67 | /// 68 | /// - parameter n: The number of elements to drop. default to `1` 69 | /// 70 | /// - returns: Returns the new sliced array. 71 | func drop(_ n: Int = 1) -> [Element] { 72 | return self.slice(start: Swift.max(n, 0), end: self.count) 73 | } 74 | 75 | /// Creates a slice of array with n elements dropped from the end. 76 | /// 77 | /// - parameter n: The number of elements to drop. 78 | /// 79 | /// - returns: Returns the new sliced array. 80 | func dropRight(_ n: Int = 1) -> [Element] { 81 | let end = self.count - n 82 | return self.slice(start: 0, end: end < 0 ? 0 : end) 83 | } 84 | 85 | /// Creates a slice of array excluding elements dropped from the end. Elements are dropped until predicate returns false. 86 | /// 87 | /// - parameter predicate: The function invoked per iteration. 88 | /// 89 | /// - returns: Returns the new sliced array. 90 | func dropRightWhile(_ predicate: (Element) -> Bool) -> [Element] { 91 | return self._baseWhile(predicate, isDrop: true, fromRight: true) 92 | } 93 | 94 | /// Creates a slice of array excluding elements dropped from the beginning. Elements are dropped until predicate returns false. 95 | /// 96 | /// - parameter predicate: The function invoked per iteration. 97 | /// 98 | /// - returns: Returns the new sliced array. 99 | func dropWhile(_ predicate: (Element) -> Bool) -> [Element] { 100 | return self._baseWhile(predicate, isDrop: true) 101 | } 102 | 103 | /// Returns true if all of the values in the array pass the predicate test. Stop traversing the list once a falsey value found. 104 | /// 105 | /// - Parameter predicate: The function invoked per iteration. 106 | /// - Returns: Boolean 107 | func every(_ predicate: (Element) -> Bool) -> Bool { 108 | for elem in self { 109 | if !predicate(elem) { 110 | return false 111 | } 112 | } 113 | return true 114 | } 115 | 116 | /// Returns the index of the first element predicate returns true for. 117 | /// 118 | /// - parameter predicate: The function invoked per iteration. 119 | /// 120 | /// - returns: Returns the index of the found element, else nil. 121 | func findIndex(_ predicate: (Element) -> Bool) -> Int? { 122 | return _baseFindIndex(predicate) 123 | } 124 | 125 | /// This method is like .findIndex except it iterates over the elements of array from right to left. 126 | /// 127 | /// - parameter predicate: The function invoked per iteration. 128 | /// 129 | /// - returns: Returns the index of the found element, else nil. 130 | func findLastIndex(_ predicate: (Element) -> Bool) -> Int? { 131 | return _baseFindIndex(predicate, fromRight: true) 132 | } 133 | 134 | /// This method is like .intersection except that it accepts comparator which is invoked to compare elements of arrays. 135 | /// 136 | /// - parameter arrays: The arrays to inspect. 137 | /// - parameter comparator: The comparator invoked per element. 138 | /// 139 | /// - returns: Returns the new array of shared values. 140 | func intersectionWith(_ arrays: [Element]..., comparator: (Element, Element) -> Bool) -> [Element] { 141 | return self._baseIntersection(arrays: arrays, comparator: comparator) 142 | } 143 | 144 | /// Create a dictionary where the key is a Hashable got by run iteratee through the element, and the value is the arrays of the elements responsible for getting that key 145 | /// 146 | /// - Parameter iteratee: The iteratee invoked per element. 147 | /// - Returns: Returns the dictionary [Hashable: [Element]] 148 | func groupBy(_ iteratee: (Element) -> T) -> [T: [Element]] { 149 | var result = [T: [Element]]() 150 | for elem in self { 151 | let key = iteratee(elem) 152 | result[key] == nil ? result[key] = [elem] : result[key]?.append(elem) 153 | } 154 | return result 155 | } 156 | 157 | /// Return an array by slicing from start up to, but not including, end. 158 | /// 159 | /// - parameter start: The start position. 160 | /// - parameter end: The end position. `nil` by default 161 | /// 162 | /// - returns: The sliced array 163 | func slice(start: Int, end: Int? = nil) -> [Element] { 164 | let end = Swift.min(end ?? self.count, self.count) 165 | if start > self.count || start > end { 166 | return [] 167 | } 168 | return Array(self[start.. Bool) -> Bool { 176 | for elem in self { 177 | if predicate(elem) { 178 | return true 179 | } 180 | } 181 | return false 182 | } 183 | 184 | /// Returns a shuffled copy of the array, using a version of the Fisher-Yates shuffle. 185 | /// 186 | /// - Returns: Returns the new shuffled array. 187 | func shuffled() -> [Element] { 188 | var newArray = Array(self) 189 | newArray.shuffle() 190 | return newArray 191 | } 192 | 193 | /// Shuffle the elements of the collection in place. 194 | mutating func shuffle() { 195 | for index in 0.. Bool) -> [Element] { 208 | return _baseXor(arrays: arrays, isXorBy:false, comparator:comparator) 209 | } 210 | } 211 | 212 | // MARK: Element: Equatable 213 | public extension Array where Element: Equatable { 214 | 215 | /// Creates an array of unique array values not included in the other provided arrays. 216 | /// 217 | /// - parameter values: The values to exclude. 218 | /// 219 | /// - returns: Returns the new array of filtered values. 220 | func difference(_ values: [Element]) -> [Element] { 221 | return self._baseDifference(with: values, comparator: ==) 222 | } 223 | 224 | /// This method is like difference except that it accepts iteratee which is invoked for each element of array and values to generate the criterion by which uniqueness is computed. 225 | /// 226 | /// - parameter values: The values to exclude. 227 | /// - parameter iteratee: The iteratee invoked per element. 228 | /// 229 | /// - returns: Returns the new array of filtered values. 230 | func differenceBy(_ values: [Element], iteratee: @escaping ((Element) -> Element)) -> [Element] { 231 | return self._baseDifference(with: values, comparator: ==, iteratee: iteratee) 232 | } 233 | 234 | /// Creates an array of unique values that are included in all of the provided arrays. 235 | /// 236 | /// - parameter arrays: The arrays to inspect. 237 | /// 238 | /// - returns: Returns the new array of shared values. 239 | func intersection(_ arrays: [Element]...) -> [Element] { 240 | return self._baseIntersection(arrays: arrays, comparator: ==) 241 | } 242 | 243 | /// This method is like .intersection except that it accepts iteratee which is invoked for each element of each arrays to generate the criterion by which uniqueness is computed. 244 | /// 245 | /// - parameter arrays: The arrays to inspect. 246 | /// - parameter iteratee: The iteratee invoked per element. 247 | /// 248 | /// - returns: Returns the new array of shared values. 249 | func intersectionBy(_ arrays: [Element]..., iteratee: @escaping (Element) -> Element) -> [Element] { 250 | return self._baseIntersection(arrays: arrays, comparator: ==, iteratee: iteratee) 251 | } 252 | 253 | /// Creates an array excluding all given values using == comparator 254 | /// 255 | /// - Parameter values: The values to exclude. 256 | /// - Returns: Returns the new array of filtered values. 257 | func without(_ values: Element...) -> [Element] { 258 | return _baseDifference(with: values, comparator: ==) 259 | } 260 | 261 | /// Alias of .sample 262 | /// 263 | /// - Returns: A random element 264 | func random() -> Element { 265 | return sample() 266 | } 267 | 268 | /// Return a random value from the array 269 | /// 270 | /// - Returns: A random value 271 | func sample() -> Element { 272 | return self[Swiftly.random(lower: 0, upper: count - 1)] 273 | } 274 | 275 | /// Gets n random elements from collection. 276 | /// Using [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). 277 | /// 278 | /// - Parameter n: The number of elements to sample. 0 by default. 279 | /// - Returns: Array of random elements 280 | func sampleSize(_ n: Int = 0) -> [Element] { 281 | let number = Swift.max(0, Swift.min(n, count)) 282 | return shuffled().slice(start: 0, end: number) 283 | } 284 | 285 | /// The opposite of .filter; this method returns the elements of collection that predicate does not return true for. 286 | /// 287 | /// - Parameter predicate: The function invoked per iteration 288 | /// - Returns: Returns the new filtered array. 289 | func reject(_ predicate: (Element) -> Bool) -> [Element] { 290 | return filter { !predicate($0) } 291 | } 292 | 293 | /// Creates an array of unique values that is the symmetric difference of the provided arrays. 294 | /// 295 | /// - Parameter arrays: The arrays to inspect. 296 | /// - Returns: Returns the new array of values. 297 | static func xor(arrays: [Element]...) -> [Element] { 298 | return _baseXor(arrays: arrays, isXorBy: false, comparator: ==, iteratee: nil) 299 | } 300 | 301 | /// This method is like .xor except that it accepts iteratee which is invoked for each element of each arrays to generate the criterion by which uniqueness is computed. 302 | /// 303 | /// - Parameters: 304 | /// - arrays: The arrays to inspect. 305 | /// - iteratee: The iteratee invoked per element. 306 | /// - Returns: Returns the new array of values. 307 | static func xorBy(arrays: [Element]..., iteratee: @escaping ((Element) -> Element)) -> [Element] { 308 | return _baseXor(arrays: arrays, isXorBy: true, comparator: ==, iteratee: iteratee) 309 | } 310 | } 311 | 312 | // MARK: fileprivate helper methods 313 | fileprivate extension Array { 314 | func _baseDifference(with values: [Element], 315 | comparator: (Element, Element) -> Bool, 316 | iteratee: ((Element) -> Element)? = nil) -> [Element] { 317 | var result = [Element]() 318 | for elem1 in self { 319 | var isUnique = true 320 | let val1 = iteratee != nil ? iteratee!(elem1) : elem1 321 | for elem2 in values { 322 | let val2 = iteratee != nil ? iteratee!(elem2) : elem2 323 | if comparator(val1, val2) { 324 | isUnique = false 325 | break 326 | } 327 | } 328 | if isUnique { result.append(elem1) } 329 | } 330 | return result 331 | } 332 | 333 | func _baseWhile(_ predicate: ((Element) -> Bool), 334 | isDrop: Bool = false, 335 | fromRight: Bool = false) -> [Element] { 336 | let length = self.count 337 | var index = fromRight ? length : -1 338 | 339 | repeat { 340 | index += fromRight ? -1 : 1 341 | } while (fromRight ? index >= 0 : index < length) && predicate(self[index]) 342 | 343 | return isDrop ? self.slice(start: fromRight ? 0 : index, end: fromRight ? index + 1 : length) : self.slice(start: fromRight ? index + 1 : 0, end: fromRight ? length : index) 344 | } 345 | 346 | func _baseFindIndex(_ predicate: ((Element) -> Bool), 347 | fromRight: Bool = false) -> Int? { 348 | let length = self.count 349 | 350 | let strideRange = fromRight ? stride(from: length - 1, to: 0, by: -1) : stride(from: 0, to: length - 1, by: 1) 351 | 352 | for i in strideRange { 353 | if predicate(self[i]) { return i } 354 | } 355 | 356 | return nil 357 | } 358 | 359 | func _baseIntersection(arrays: [[Element]], 360 | comparator: (Element, Element) -> Bool, 361 | iteratee: ((Element) -> Element)? = nil) -> [Element] { 362 | var result = self 363 | 364 | for i in 0..(arrays: [[T]], isXorBy: Bool, comparator: (T, T) -> Bool, iteratee: ((T) -> T)?=nil) -> [T] { 387 | guard !arrays.isEmpty else { return [] } 388 | guard arrays.count > 1 else { return arrays[0] } 389 | 390 | var result = arrays[arrays.count - 1] 391 | 392 | for i in (0...arrays.count - 2).reversed() { 393 | let nextArr = arrays[i] 394 | var tmp = [T]() 395 | var uniqueElemMarker = [Bool](repeating: true, count: result.count) 396 | 397 | for elem1 in nextArr { 398 | var isUnique = true 399 | for j in 0.. CGFloat { 18 | return (self * .pi) / 180.0 19 | } 20 | 21 | /// Convert from radians to degrees 22 | /// 23 | /// - Returns: Degree value 24 | func radiansToDegrees() -> CGFloat { 25 | return (self * 180.0) / .pi 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Source/CGPointExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGPointExtensions.swift 3 | // SwiftlyExt 4 | // 5 | // Created by Khoi Lai on 12/30/16. 6 | // Copyright © 2016 Khoi Lai. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CoreGraphics 11 | 12 | public extension CGPoint { 13 | 14 | /// Calculate distance from self to another point. 15 | /// 16 | /// - Parameter to: destination point 17 | /// - Returns: distance between two points. 18 | func distance(to point: CGPoint) -> CGFloat { 19 | return CGPoint.distance(from: self, to: point) 20 | } 21 | 22 | /// Calculate distance between 2 CGPoint. 23 | /// 24 | /// - Parameters: 25 | /// - from: origin point 26 | /// - to: destination point 27 | /// - Returns: distance between two points. 28 | static func distance(from: CGPoint, to: CGPoint) -> CGFloat { 29 | return sqrt(pow(to.x - from.x, 2) + pow(to.y - from.y, 2)) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Source/DateExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DateExtensions.swift 3 | // Swiftly 4 | // 5 | // Created by Khoi Lai on 08/10/2016. 6 | // Copyright © 2016 Khoi Lai. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension Date { 12 | 13 | fileprivate var components: DateComponents { 14 | return calendar.dateComponents([.era, .year, .month, .day, .hour, .minute, .second, .nanosecond, .weekday, .weekdayOrdinal, .quarter, .weekOfMonth, .weekOfYear], from: self) 15 | } 16 | 17 | fileprivate var calendar: Calendar { 18 | return Calendar.current 19 | } 20 | 21 | /// An era or count of eras. 22 | /// - note: This value is for Calendar.current 23 | var era: Int { 24 | return components.era! 25 | } 26 | 27 | /// A year or count of years. 28 | /// - note: This value is for Calendar.current 29 | var year: Int { 30 | return components.year! 31 | } 32 | 33 | /// A month or count of months. 34 | /// - note: This value is for Calendar.current 35 | var month: Int { 36 | return components.month! 37 | } 38 | 39 | /// A day or count of days. 40 | /// - note: This value is for Calendar.current 41 | var day: Int { 42 | return components.day! 43 | } 44 | 45 | /// An hour or count of hours. 46 | /// - note: This value is for Calendar.current 47 | var hour: Int { 48 | return components.hour! 49 | } 50 | 51 | /// A minute or count of minutes. 52 | /// - note: This value is for Calendar.current 53 | var minute: Int { 54 | return components.minute! 55 | } 56 | 57 | /// A second or count of seconds. 58 | /// - note: This value is for Calendar.current 59 | var second: Int { 60 | return components.second! 61 | } 62 | 63 | /// A nanosecond or count of nanoseconds. 64 | /// - note: This value is for Calendar.current 65 | var nanosecond: Int { 66 | return components.nanosecond! 67 | } 68 | 69 | /// A weekday or count of weekdays. 70 | /// - note: This value is for Calendar.current 71 | var weekday: Int { 72 | return components.weekday! 73 | } 74 | 75 | /// A weekday ordinal or count of weekday ordinals. 76 | /// - note: This value is for Calendar.current 77 | var weekdayOrdinal: Int { 78 | return components.weekdayOrdinal! 79 | } 80 | 81 | /// A quarter or count of quarters. 82 | /// - note: This value is for Calendar.current 83 | var quarter: Int { 84 | return components.quarter! 85 | } 86 | 87 | /// A week of the month or a count of weeks of the month. 88 | /// - note: This value is for Calendar.current 89 | var weekOfMonth: Int { 90 | return components.weekOfMonth! 91 | } 92 | 93 | /// A week of the year or count of the weeks of the year. 94 | /// - note: This value is for Calendar.current 95 | var weekOfYear: Int { 96 | return components.weekOfYear! 97 | } 98 | 99 | public init?(from string: String, format: String) { 100 | let df = DateFormatter() 101 | df.dateFormat = format 102 | guard let date = df.date(from: string) else { return nil } 103 | self = date 104 | } 105 | 106 | /// Return the string representation for a date. 107 | /// 108 | /// - parameter dateStyle: A DateFormatter.Style for the date. default to `.medium`. 109 | /// - parameter timeStyle: A DateFormatter.Style for the time. default to `.medium`. 110 | /// - parameter locale: Locale of the string. default to the current locale. 111 | /// 112 | /// - returns: The date string. 113 | func toString(dateStyle: DateFormatter.Style = .medium, timeStyle: DateFormatter.Style = .medium, locale: Locale = Locale.current) -> String { 114 | let df = DateFormatter() 115 | df.dateStyle = dateStyle 116 | df.timeStyle = timeStyle 117 | df.locale = locale 118 | return df.string(from: self) 119 | } 120 | 121 | /// Return the string representation for a date using a date format. 122 | /// 123 | /// - parameter format: The date format string. 124 | /// - parameter locale: Locale of the string. default to `.locale` 125 | /// 126 | /// - returns: The date string. 127 | func toString(format: String, locale: Locale = Locale.current) -> String { 128 | let df = DateFormatter() 129 | df.dateFormat = format 130 | df.locale = locale 131 | return df.string(from: self) 132 | } 133 | 134 | /// Check if self is before input date. 135 | /// 136 | /// - parameter date: The date to compare to. 137 | /// 138 | /// - returns: True if self is before input date, false otherwise. 139 | func isBefore(_ date: Date) -> Bool { 140 | return self.compare(date) == .orderedAscending 141 | } 142 | 143 | /// Check if self is after input date. 144 | /// 145 | /// - parameter date: The date to compare to. 146 | /// 147 | /// - returns: True if self is after input date, false otherwise. 148 | func isAfter(_ date: Date) -> Bool { 149 | return self.compare(date) == .orderedDescending 150 | } 151 | } 152 | 153 | // MARK: Adding date 154 | public extension Date { 155 | fileprivate func _date(byAddingYears years: Int = 0, 156 | byAddingMonths months: Int = 0, 157 | byAddingDays days: Int = 0, 158 | byAddingHours hours: Int = 0, 159 | byAddingMinutes minutes: Int = 0, 160 | byAddingSeconds seconds: Int = 0) -> Date? { 161 | var dc = DateComponents() 162 | dc.year = years 163 | dc.month = months 164 | dc.day = days 165 | dc.hour = hours 166 | dc.minute = minutes 167 | dc.second = seconds 168 | return calendar.date(byAdding: dc, to: self) 169 | } 170 | 171 | /// Return a new Date instance by adding n years to it. 172 | /// 173 | /// - parameter years: Number of years to add. 174 | /// 175 | /// - returns: The new Date. 176 | func date(byAddingYears years: Int) -> Date? { 177 | return _date(byAddingYears: years) 178 | } 179 | 180 | /// Return a new Date instance by adding n months to it. 181 | /// 182 | /// - parameter months: Number of months to add. 183 | /// 184 | /// - returns: The new Date. 185 | func date(byAddingMonths months: Int) -> Date? { 186 | return _date(byAddingMonths: months) 187 | } 188 | 189 | /// Return a new Date instance by adding n days to it. 190 | /// 191 | /// - parameter days: Number of days to add. 192 | /// 193 | /// - returns: The new Date. 194 | func date(byAddingDays days: Int) -> Date? { 195 | return _date(byAddingDays: days) 196 | } 197 | 198 | /// Return a new Date instance by adding n hours to it. 199 | /// 200 | /// - parameter hours: Number of hours to add. 201 | /// 202 | /// - returns: The new Date. 203 | func date(byAddingHours hours: Int) -> Date? { 204 | return _date(byAddingHours: hours) 205 | } 206 | 207 | /// Return a new Date instance by adding n minutes to it. 208 | /// 209 | /// - parameter minutes: Number of minutes to add. 210 | /// 211 | /// - returns: The new Date. 212 | func date(byAddingMinutes minutes: Int) -> Date? { 213 | return _date(byAddingMinutes: minutes) 214 | } 215 | 216 | /// Return a new Date instance by adding n seconds to it. 217 | /// 218 | /// - parameter seconds: Number of seconds to add. 219 | /// 220 | /// - returns: The new Date. 221 | func date(byAddingSeconds seconds: Int) -> Date? { 222 | return _date(byAddingSeconds: seconds) 223 | } 224 | 225 | } 226 | -------------------------------------------------------------------------------- /Source/DictionaryExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DictionaryExtensions.swift 3 | // SwiftlyExt 4 | // 5 | // Created by Khoi Lai on 12/30/16. 6 | // Copyright © 2016 Khoi Lai. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension Dictionary { 12 | 13 | init?(fromJsonString json: String) { 14 | guard let data = (try? JSONSerialization.jsonObject(with: json.data(using: String.Encoding.utf8, allowLossyConversion: true)!, 15 | options: JSONSerialization.ReadingOptions.mutableContainers)) as? Dictionary else { 16 | return nil 17 | } 18 | self = data 19 | } 20 | 21 | /// Convert from dictionary to Json String 22 | /// 23 | /// - Parameter prettify: Pretty printed or not 24 | /// - Returns: Json String if exist 25 | func toJsonString(prettify: Bool = false) -> String? { 26 | guard let data = try? JSONSerialization.data(withJSONObject: self, options: prettify ? .prettyPrinted : JSONSerialization.WritingOptions()) else { return nil } 27 | let str = String(data: data, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue)) 28 | return String(str ?? "") 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Source/Info-tvOS.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | UIRequiredDeviceCapabilities 24 | 25 | arm64 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Source/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Source/IntExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IntExtensions.swift 3 | // Swiftly 4 | // 5 | // Created by Khoi Lai on 9/19/16. 6 | // Copyright © 2016 Khoi Lai. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension Int { 12 | /// Convert current int to an [Int] 13 | /// 14 | /// - returns: An array of digits 15 | func digits() -> [Int] { 16 | 17 | var digits: [Int] = [] 18 | var curr = self 19 | 20 | while curr > 0 { 21 | digits.append(curr % 10) 22 | curr /= 10 23 | } 24 | 25 | return digits.reversed() 26 | } 27 | 28 | /// Invoke the callback with indexes from current int down to and including n. 29 | /// 30 | /// - parameter lowBound: The lowBound to go to 31 | /// - parameter callback: The block to invoke with current index 32 | func downTo(_ lowBound: Int, callback: (Int) -> Void) { 33 | var curr = self 34 | while curr >= lowBound { 35 | callback(curr) 36 | curr -= 1 37 | } 38 | } 39 | 40 | /// Return the factorial of int 41 | /// 42 | /// - returns: Factorial of int 43 | func factorial() -> Int { 44 | guard self > 0 else { return 1 } 45 | return self * (self - 1).factorial() 46 | } 47 | 48 | /// Check if the integer is even. 49 | /// 50 | /// - returns: Bool whether the int is even 51 | func isEven() -> Bool { 52 | return self % 2 == 0 53 | } 54 | 55 | /// Test whether the int is in a range 56 | /// 57 | /// - parameter range: The range to check 58 | /// 59 | /// - returns: BOOL whether the int is in range 60 | func isIn(range: Range) -> Bool { 61 | return range ~= self 62 | } 63 | 64 | /// Test whether the int is in a range 65 | /// 66 | /// - parameter range: The range to check 67 | /// 68 | /// - returns: BOOL whether the int is in range 69 | func isIn(range: ClosedRange) -> Bool { 70 | return range ~= self 71 | } 72 | 73 | /// Check if the integer is odd. 74 | /// 75 | /// - returns: Bool whether the int is odd 76 | func isOdd() -> Bool { 77 | return !isEven() 78 | } 79 | 80 | /// Invoke the callback function n times with zero-based indexes. 81 | /// 82 | /// - parameter callback: The block with current index 83 | func times(_ callback: (Int) -> Void) { 84 | guard self > 0 else { return } 85 | (0.. Void) { 95 | guard self <= upBound else { return } 96 | (self...upBound).each { (idx) in 97 | callback(idx) 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Source/RangeExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RangeExtensions.swift 3 | // Swiftly 4 | // 5 | // Created by Khoi Lai on 9/19/16. 6 | // Copyright © 2016 Khoi Lai. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | internal extension CountableRange { 12 | 13 | func each(callback: (Bound) -> Void) { 14 | for i in self { 15 | callback(i) 16 | } 17 | } 18 | 19 | func each(callback: () -> Void) { 20 | for _ in self { 21 | callback() 22 | } 23 | } 24 | 25 | func toArray() -> [Bound] { 26 | var result = [Bound]() 27 | self.each { (bound) in 28 | result.append(bound) 29 | } 30 | return result 31 | } 32 | } 33 | 34 | internal extension CountableClosedRange { 35 | func each(callback: (Bound) -> Void) { 36 | for i in self { 37 | callback(i) 38 | } 39 | } 40 | 41 | func each(callback: () -> Void) { 42 | for _ in self { 43 | callback() 44 | } 45 | } 46 | 47 | func toArray() -> [Bound] { 48 | var result = [Bound]() 49 | self.each { (bound) in 50 | result.append(bound) 51 | } 52 | return result 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /Source/StringExtensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StringExtensions.swift 3 | // SwiftlyExt 4 | // 5 | // Created by Khoi Lai on 10/10/2016. 6 | // Copyright © 2016 Khoi Lai. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension String { 12 | 13 | /// Find the string between two string. 14 | /// 15 | /// - Parameters: 16 | /// - left: The left bookend 17 | /// - right: The right bookend 18 | /// - Returns: Return the String if found else `nil` 19 | func between(_ left: String, _ right: String) -> String? { 20 | guard let leftRange = range(of: left), 21 | let rightRange = range(of: right, options: .backwards), 22 | left != right && leftRange.upperBound != rightRange.lowerBound else { 23 | return nil 24 | } 25 | return self[leftRange.upperBound...index(before: rightRange.lowerBound)] 26 | } 27 | 28 | /// Count number of occurences for a substring 29 | /// 30 | /// - Parameter str: The string to count 31 | /// - Returns: Number of occurences 32 | func count(_ str: String) -> Int { 33 | return components(separatedBy: str).count - 1 34 | } 35 | 36 | /// Return a date from current string. 37 | /// 38 | /// - parameter format: The date format 39 | /// - parameter locale: The locale. default to `.current` 40 | /// 41 | /// - returns: A Date. 42 | func date(format: String, locale: Locale = .current) -> Date? { 43 | let df = DateFormatter() 44 | df.dateFormat = format 45 | df.locale = locale 46 | return df.date(from: self) 47 | } 48 | 49 | /// Check whether the string is an email or not. 50 | var isEmail: Bool { 51 | let regex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}" 52 | let predicate = NSPredicate(format:"SELF MATCHES %@", regex) 53 | return predicate.evaluate(with: self) 54 | } 55 | 56 | /// Check whether the string contains one or more letters. 57 | public var hasLetters: Bool { 58 | return rangeOfCharacter(from: .letters, options: .literal) != nil 59 | } 60 | 61 | /// Check whether the string contains one or more numbers. 62 | public var hasNumbers: Bool { 63 | return rangeOfCharacter(from: .decimalDigits, options: .literal) != nil 64 | } 65 | 66 | /// Check whether the string contains only letters. 67 | var isAlpha: Bool { 68 | for c in characters { 69 | if !(c >= "a" && c <= "z") && !(c >= "A" && c <= "Z") { 70 | return false 71 | } 72 | } 73 | return true 74 | } 75 | 76 | /// Check if string contains at least one letter and one number 77 | var isAlphaNumeric: Bool { 78 | return components(separatedBy: .alphanumerics).joined(separator: "").characters.isEmpty 79 | } 80 | 81 | /// Return the initials of the String 82 | var initials: String { 83 | return self.components(separatedBy: " ").reduce("") { $0 + $1[0...0] } 84 | } 85 | 86 | /// Decoded Base 64 String if applicable 87 | var base64Decoded: String? { 88 | guard let decodedData = Data(base64Encoded: self) else { return nil } 89 | return String(data: decodedData, encoding: .utf8) 90 | } 91 | 92 | /// Encoded Base 64 String if applicable 93 | var base64Encoded: String? { 94 | return data(using: .utf8)?.base64EncodedString() 95 | } 96 | 97 | /// Reversed String 98 | var reversed: String { 99 | return String(self.characters.reversed()) 100 | } 101 | 102 | /// A String without white spaces and new lines 103 | var trimmed: String { 104 | return trimmingCharacters(in: .whitespacesAndNewlines) 105 | } 106 | 107 | /// Decoded URL String 108 | var urlDecoded: String { 109 | return removingPercentEncoding ?? self 110 | } 111 | 112 | /// Encoded URL String 113 | var urlEncoded: String { 114 | return self.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? self 115 | } 116 | 117 | } 118 | 119 | extension String { 120 | subscript (r: CountableClosedRange) -> String { 121 | get { 122 | let startIndex = self.index(self.startIndex, offsetBy: r.lowerBound) 123 | let endIndex = self.index(startIndex, offsetBy: r.upperBound - r.lowerBound) 124 | return self[startIndex...endIndex] 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /Source/Swiftly.h: -------------------------------------------------------------------------------- 1 | // 2 | // Swiftly.h 3 | // Swiftly 4 | // 5 | // Created by Khoi Lai on 9/19/16. 6 | // Copyright © 2016 Khoi Lai. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | 11 | FOUNDATION_EXPORT double SwiftlyVersionNumber; 12 | 13 | FOUNDATION_EXPORT const unsigned char SwiftlyVersionString[]; 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Source/Swiftly.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Swiftly.swift 3 | // SwiftlyExt 4 | // 5 | // Created by Khoi Lai on 1/30/17. 6 | // Copyright © 2017 Khoi Lai. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct Swiftly { 12 | /// Return a random integer from lowerbound to upperbound inclusively 13 | /// 14 | /// - Parameters: 15 | /// - lower: The lower bound 16 | /// - upper: The upper bound 17 | /// - Returns: A random Int 18 | public static func random(lower: Int = 0, upper: Int = 1) -> Int { 19 | precondition(upper >= lower, "Lowerbound must be smaller than upper bound") 20 | return Int(arc4random_uniform(UInt32(upper - lower + 1))) + lower 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SwiftlyExt.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'SwiftlyExt' 3 | s.version = '1.3.0' 4 | s.license = 'MIT' 5 | s.summary = 'Extensions for native standard Swift types and classes' 6 | s.homepage = 'https://github.com/khoiln/Swiftly' 7 | s.authors = {'Khoi Lai' => 'k@khoi.io' } 8 | s.source = { :git => 'https://github.com/khoiln/Swiftly.git', :tag => s.version } 9 | s.ios.deployment_target = '9.0' 10 | s.osx.deployment_target = '10.11' 11 | s.tvos.deployment_target = '9.0' 12 | s.watchos.deployment_target = '2.0' 13 | s.source_files = 'Source/*.swift' 14 | end -------------------------------------------------------------------------------- /SwiftlyExt.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7C135F641D99637800994840 /* SwiftlyExt.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7CB10DA31D99621700731EE9 /* SwiftlyExt.framework */; }; 11 | 7C135F791D99658600994840 /* Swiftly.h in Headers */ = {isa = PBXBuildFile; fileRef = 7CD99CE21D9002F900668467 /* Swiftly.h */; settings = {ATTRIBUTES = (Public, ); }; }; 12 | 7C135F7A1D99658B00994840 /* IntExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CD99CE41D901C3800668467 /* IntExtensions.swift */; }; 13 | 7C135F7B1D99658B00994840 /* RangeExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CD99CF71D9020BF00668467 /* RangeExtensions.swift */; }; 14 | 7C135F7C1D99658B00994840 /* ArrayExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CB10D871D99344700731EE9 /* ArrayExtensions.swift */; }; 15 | 7C135F951D99660E00994840 /* SwiftlyExt.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7C135F711D9964A000994840 /* SwiftlyExt.framework */; }; 16 | 7C14D21B1DA8E4DD00204587 /* DateExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C14D21A1DA8E4DD00204587 /* DateExtensions.swift */; }; 17 | 7C14D21C1DA8E51D00204587 /* DateExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C14D21A1DA8E4DD00204587 /* DateExtensions.swift */; }; 18 | 7C14D21D1DA8E51E00204587 /* DateExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C14D21A1DA8E4DD00204587 /* DateExtensions.swift */; }; 19 | 7C14D21E1DA8E51E00204587 /* DateExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C14D21A1DA8E4DD00204587 /* DateExtensions.swift */; }; 20 | 7C4B8DB21E3F28FE00004E9A /* Swiftly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4B8DB11E3F28FE00004E9A /* Swiftly.swift */; }; 21 | 7C4B8DB31E3F28FE00004E9A /* Swiftly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4B8DB11E3F28FE00004E9A /* Swiftly.swift */; }; 22 | 7C4B8DB41E3F28FE00004E9A /* Swiftly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4B8DB11E3F28FE00004E9A /* Swiftly.swift */; }; 23 | 7C4B8DB51E3F28FE00004E9A /* Swiftly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4B8DB11E3F28FE00004E9A /* Swiftly.swift */; }; 24 | 7C4EFA0A1E16469200DC9B08 /* CGPointExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4EFA091E16469200DC9B08 /* CGPointExtensions.swift */; }; 25 | 7C4EFA101E1648D600DC9B08 /* CGPointExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4EFA091E16469200DC9B08 /* CGPointExtensions.swift */; }; 26 | 7C4EFA111E1648D700DC9B08 /* CGPointExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4EFA091E16469200DC9B08 /* CGPointExtensions.swift */; }; 27 | 7C4EFA121E1648D700DC9B08 /* CGPointExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4EFA091E16469200DC9B08 /* CGPointExtensions.swift */; }; 28 | 7C4EFA141E164A7700DC9B08 /* CGFloatExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4EFA131E164A7700DC9B08 /* CGFloatExtensions.swift */; }; 29 | 7C4EFA151E164A8200DC9B08 /* CGFloatExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4EFA131E164A7700DC9B08 /* CGFloatExtensions.swift */; }; 30 | 7C4EFA161E164A8200DC9B08 /* CGFloatExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4EFA131E164A7700DC9B08 /* CGFloatExtensions.swift */; }; 31 | 7C4EFA171E164A8300DC9B08 /* CGFloatExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4EFA131E164A7700DC9B08 /* CGFloatExtensions.swift */; }; 32 | 7C4EFA1D1E164D3A00DC9B08 /* DictionaryExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4EFA1C1E164D3A00DC9B08 /* DictionaryExtensions.swift */; }; 33 | 7C4EFA1E1E164D6B00DC9B08 /* DictionaryExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4EFA1C1E164D3A00DC9B08 /* DictionaryExtensions.swift */; }; 34 | 7C4EFA1F1E164D6C00DC9B08 /* DictionaryExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4EFA1C1E164D3A00DC9B08 /* DictionaryExtensions.swift */; }; 35 | 7C4EFA201E164D6C00DC9B08 /* DictionaryExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4EFA1C1E164D3A00DC9B08 /* DictionaryExtensions.swift */; }; 36 | 7C5EEE641E446ADF001C4E7A /* ArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE561E446AD8001C4E7A /* ArrayTests.swift */; }; 37 | 7C5EEE651E446ADF001C4E7A /* CGFloatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE571E446AD8001C4E7A /* CGFloatTests.swift */; }; 38 | 7C5EEE661E446ADF001C4E7A /* CGPointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE581E446AD8001C4E7A /* CGPointTests.swift */; }; 39 | 7C5EEE671E446ADF001C4E7A /* DateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE591E446AD8001C4E7A /* DateTests.swift */; }; 40 | 7C5EEE681E446ADF001C4E7A /* DictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE5A1E446AD8001C4E7A /* DictionaryTests.swift */; }; 41 | 7C5EEE691E446ADF001C4E7A /* ArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE561E446AD8001C4E7A /* ArrayTests.swift */; }; 42 | 7C5EEE6A1E446ADF001C4E7A /* CGFloatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE571E446AD8001C4E7A /* CGFloatTests.swift */; }; 43 | 7C5EEE6B1E446ADF001C4E7A /* CGPointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE581E446AD8001C4E7A /* CGPointTests.swift */; }; 44 | 7C5EEE6C1E446ADF001C4E7A /* DateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE591E446AD8001C4E7A /* DateTests.swift */; }; 45 | 7C5EEE6D1E446ADF001C4E7A /* DictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE5A1E446AD8001C4E7A /* DictionaryTests.swift */; }; 46 | 7C5EEE6E1E446ADF001C4E7A /* ArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE561E446AD8001C4E7A /* ArrayTests.swift */; }; 47 | 7C5EEE6F1E446ADF001C4E7A /* CGFloatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE571E446AD8001C4E7A /* CGFloatTests.swift */; }; 48 | 7C5EEE701E446ADF001C4E7A /* CGPointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE581E446AD8001C4E7A /* CGPointTests.swift */; }; 49 | 7C5EEE711E446ADF001C4E7A /* DateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE591E446AD8001C4E7A /* DateTests.swift */; }; 50 | 7C5EEE721E446ADF001C4E7A /* DictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE5A1E446AD8001C4E7A /* DictionaryTests.swift */; }; 51 | 7C5EEE731E446AE2001C4E7A /* IntTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE5C1E446AD8001C4E7A /* IntTests.swift */; }; 52 | 7C5EEE741E446AE2001C4E7A /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE5D1E446AD8001C4E7A /* StringTests.swift */; }; 53 | 7C5EEE751E446AE2001C4E7A /* SwiftlyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE5E1E446AD8001C4E7A /* SwiftlyTests.swift */; }; 54 | 7C5EEE761E446AE3001C4E7A /* IntTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE5C1E446AD8001C4E7A /* IntTests.swift */; }; 55 | 7C5EEE771E446AE3001C4E7A /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE5D1E446AD8001C4E7A /* StringTests.swift */; }; 56 | 7C5EEE781E446AE3001C4E7A /* SwiftlyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE5E1E446AD8001C4E7A /* SwiftlyTests.swift */; }; 57 | 7C5EEE791E446AE3001C4E7A /* IntTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE5C1E446AD8001C4E7A /* IntTests.swift */; }; 58 | 7C5EEE7A1E446AE3001C4E7A /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE5D1E446AD8001C4E7A /* StringTests.swift */; }; 59 | 7C5EEE7B1E446AE3001C4E7A /* SwiftlyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C5EEE5E1E446AD8001C4E7A /* SwiftlyTests.swift */; }; 60 | 7CB10D881D99344700731EE9 /* ArrayExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CB10D871D99344700731EE9 /* ArrayExtensions.swift */; }; 61 | 7CB10D9A1D99619C00731EE9 /* Swiftly.h in Headers */ = {isa = PBXBuildFile; fileRef = 7CD99CE21D9002F900668467 /* Swiftly.h */; settings = {ATTRIBUTES = (Public, ); }; }; 62 | 7CB10D9B1D9961A400731EE9 /* IntExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CD99CE41D901C3800668467 /* IntExtensions.swift */; }; 63 | 7CB10D9C1D9961A400731EE9 /* RangeExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CD99CF71D9020BF00668467 /* RangeExtensions.swift */; }; 64 | 7CB10D9D1D9961A400731EE9 /* ArrayExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CB10D871D99344700731EE9 /* ArrayExtensions.swift */; }; 65 | 7CB10DAB1D99627800731EE9 /* Swiftly.h in Headers */ = {isa = PBXBuildFile; fileRef = 7CD99CE21D9002F900668467 /* Swiftly.h */; settings = {ATTRIBUTES = (Public, ); }; }; 66 | 7CB10DAC1D99627D00731EE9 /* IntExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CD99CE41D901C3800668467 /* IntExtensions.swift */; }; 67 | 7CB10DAD1D99627D00731EE9 /* RangeExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CD99CF71D9020BF00668467 /* RangeExtensions.swift */; }; 68 | 7CB10DAE1D99627D00731EE9 /* ArrayExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CB10D871D99344700731EE9 /* ArrayExtensions.swift */; }; 69 | 7CD99CE31D9002FD00668467 /* Swiftly.h in Headers */ = {isa = PBXBuildFile; fileRef = 7CD99CE21D9002F900668467 /* Swiftly.h */; settings = {ATTRIBUTES = (Public, ); }; }; 70 | 7CD99CE51D901C3800668467 /* IntExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CD99CE41D901C3800668467 /* IntExtensions.swift */; }; 71 | 7CD99CEF1D901F0300668467 /* SwiftlyExt.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7CD99CD51D9002E100668467 /* SwiftlyExt.framework */; }; 72 | 7CD99CF81D9020BF00668467 /* RangeExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CD99CF71D9020BF00668467 /* RangeExtensions.swift */; }; 73 | 7CF95F761DAB9D5D00C61E03 /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CF95F751DAB9D5D00C61E03 /* StringExtensions.swift */; }; 74 | 7CF95F7D1DAB9FA700C61E03 /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CF95F751DAB9D5D00C61E03 /* StringExtensions.swift */; }; 75 | 7CF95F7E1DAB9FA800C61E03 /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CF95F751DAB9D5D00C61E03 /* StringExtensions.swift */; }; 76 | 7CF95F7F1DAB9FA800C61E03 /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CF95F751DAB9D5D00C61E03 /* StringExtensions.swift */; }; 77 | /* End PBXBuildFile section */ 78 | 79 | /* Begin PBXContainerItemProxy section */ 80 | 7C135F651D99637800994840 /* PBXContainerItemProxy */ = { 81 | isa = PBXContainerItemProxy; 82 | containerPortal = 7CD99CCC1D9002E100668467 /* Project object */; 83 | proxyType = 1; 84 | remoteGlobalIDString = 7CB10DA21D99621700731EE9; 85 | remoteInfo = "Swiftly tvOS"; 86 | }; 87 | 7C135F961D99660E00994840 /* PBXContainerItemProxy */ = { 88 | isa = PBXContainerItemProxy; 89 | containerPortal = 7CD99CCC1D9002E100668467 /* Project object */; 90 | proxyType = 1; 91 | remoteGlobalIDString = 7C135F701D9964A000994840; 92 | remoteInfo = "Swiftly macOS"; 93 | }; 94 | 7CD99CF01D901F0300668467 /* PBXContainerItemProxy */ = { 95 | isa = PBXContainerItemProxy; 96 | containerPortal = 7CD99CCC1D9002E100668467 /* Project object */; 97 | proxyType = 1; 98 | remoteGlobalIDString = 7CD99CD41D9002E100668467; 99 | remoteInfo = Swiftly; 100 | }; 101 | /* End PBXContainerItemProxy section */ 102 | 103 | /* Begin PBXFileReference section */ 104 | 7C135F5F1D99637800994840 /* SwiftlyExt tvOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftlyExt tvOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 105 | 7C135F711D9964A000994840 /* SwiftlyExt.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftlyExt.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 106 | 7C135F901D99660E00994840 /* SwiftlyExt macOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftlyExt macOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 107 | 7C14D21A1DA8E4DD00204587 /* DateExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateExtensions.swift; sourceTree = ""; }; 108 | 7C4B8DB11E3F28FE00004E9A /* Swiftly.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Swiftly.swift; sourceTree = ""; }; 109 | 7C4EFA091E16469200DC9B08 /* CGPointExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGPointExtensions.swift; sourceTree = ""; }; 110 | 7C4EFA131E164A7700DC9B08 /* CGFloatExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGFloatExtensions.swift; sourceTree = ""; }; 111 | 7C4EFA1C1E164D3A00DC9B08 /* DictionaryExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DictionaryExtensions.swift; sourceTree = ""; }; 112 | 7C5EEE561E446AD8001C4E7A /* ArrayTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayTests.swift; sourceTree = ""; }; 113 | 7C5EEE571E446AD8001C4E7A /* CGFloatTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGFloatTests.swift; sourceTree = ""; }; 114 | 7C5EEE581E446AD8001C4E7A /* CGPointTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGPointTests.swift; sourceTree = ""; }; 115 | 7C5EEE591E446AD8001C4E7A /* DateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTests.swift; sourceTree = ""; }; 116 | 7C5EEE5A1E446AD8001C4E7A /* DictionaryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DictionaryTests.swift; sourceTree = ""; }; 117 | 7C5EEE5B1E446AD8001C4E7A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 118 | 7C5EEE5C1E446AD8001C4E7A /* IntTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntTests.swift; sourceTree = ""; }; 119 | 7C5EEE5D1E446AD8001C4E7A /* StringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringTests.swift; sourceTree = ""; }; 120 | 7C5EEE5E1E446AD8001C4E7A /* SwiftlyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftlyTests.swift; sourceTree = ""; }; 121 | 7CB10D871D99344700731EE9 /* ArrayExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayExtensions.swift; sourceTree = ""; }; 122 | 7CB10D8B1D99609A00731EE9 /* Info-tvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-tvOS.plist"; sourceTree = ""; }; 123 | 7CB10D921D99613C00731EE9 /* SwiftlyExt.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftlyExt.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 124 | 7CB10DA31D99621700731EE9 /* SwiftlyExt.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftlyExt.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 125 | 7CD99CD51D9002E100668467 /* SwiftlyExt.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftlyExt.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 126 | 7CD99CE11D9002F900668467 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 127 | 7CD99CE21D9002F900668467 /* Swiftly.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Swiftly.h; sourceTree = ""; }; 128 | 7CD99CE41D901C3800668467 /* IntExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntExtensions.swift; sourceTree = ""; }; 129 | 7CD99CEA1D901F0300668467 /* SwiftlyExt iOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SwiftlyExt iOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 130 | 7CD99CF71D9020BF00668467 /* RangeExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RangeExtensions.swift; sourceTree = ""; }; 131 | 7CF95F751DAB9D5D00C61E03 /* StringExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtensions.swift; sourceTree = ""; }; 132 | /* End PBXFileReference section */ 133 | 134 | /* Begin PBXFrameworksBuildPhase section */ 135 | 7C135F5C1D99637800994840 /* Frameworks */ = { 136 | isa = PBXFrameworksBuildPhase; 137 | buildActionMask = 2147483647; 138 | files = ( 139 | 7C135F641D99637800994840 /* SwiftlyExt.framework in Frameworks */, 140 | ); 141 | runOnlyForDeploymentPostprocessing = 0; 142 | }; 143 | 7C135F6D1D9964A000994840 /* Frameworks */ = { 144 | isa = PBXFrameworksBuildPhase; 145 | buildActionMask = 2147483647; 146 | files = ( 147 | ); 148 | runOnlyForDeploymentPostprocessing = 0; 149 | }; 150 | 7C135F8D1D99660E00994840 /* Frameworks */ = { 151 | isa = PBXFrameworksBuildPhase; 152 | buildActionMask = 2147483647; 153 | files = ( 154 | 7C135F951D99660E00994840 /* SwiftlyExt.framework in Frameworks */, 155 | ); 156 | runOnlyForDeploymentPostprocessing = 0; 157 | }; 158 | 7CB10D8E1D99613C00731EE9 /* Frameworks */ = { 159 | isa = PBXFrameworksBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | ); 163 | runOnlyForDeploymentPostprocessing = 0; 164 | }; 165 | 7CB10D9F1D99621700731EE9 /* Frameworks */ = { 166 | isa = PBXFrameworksBuildPhase; 167 | buildActionMask = 2147483647; 168 | files = ( 169 | ); 170 | runOnlyForDeploymentPostprocessing = 0; 171 | }; 172 | 7CD99CD11D9002E100668467 /* Frameworks */ = { 173 | isa = PBXFrameworksBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | ); 177 | runOnlyForDeploymentPostprocessing = 0; 178 | }; 179 | 7CD99CE71D901F0300668467 /* Frameworks */ = { 180 | isa = PBXFrameworksBuildPhase; 181 | buildActionMask = 2147483647; 182 | files = ( 183 | 7CD99CEF1D901F0300668467 /* SwiftlyExt.framework in Frameworks */, 184 | ); 185 | runOnlyForDeploymentPostprocessing = 0; 186 | }; 187 | /* End PBXFrameworksBuildPhase section */ 188 | 189 | /* Begin PBXGroup section */ 190 | 7C5EEE551E446AD8001C4E7A /* Tests */ = { 191 | isa = PBXGroup; 192 | children = ( 193 | 7C5EEE561E446AD8001C4E7A /* ArrayTests.swift */, 194 | 7C5EEE571E446AD8001C4E7A /* CGFloatTests.swift */, 195 | 7C5EEE581E446AD8001C4E7A /* CGPointTests.swift */, 196 | 7C5EEE591E446AD8001C4E7A /* DateTests.swift */, 197 | 7C5EEE5A1E446AD8001C4E7A /* DictionaryTests.swift */, 198 | 7C5EEE5B1E446AD8001C4E7A /* Info.plist */, 199 | 7C5EEE5C1E446AD8001C4E7A /* IntTests.swift */, 200 | 7C5EEE5D1E446AD8001C4E7A /* StringTests.swift */, 201 | 7C5EEE5E1E446AD8001C4E7A /* SwiftlyTests.swift */, 202 | ); 203 | path = Tests; 204 | sourceTree = ""; 205 | }; 206 | 7CB10D8C1D9960AE00731EE9 /* Supporting Files */ = { 207 | isa = PBXGroup; 208 | children = ( 209 | 7CD99CE11D9002F900668467 /* Info.plist */, 210 | 7CB10D8B1D99609A00731EE9 /* Info-tvOS.plist */, 211 | 7CD99CE21D9002F900668467 /* Swiftly.h */, 212 | ); 213 | name = "Supporting Files"; 214 | sourceTree = ""; 215 | }; 216 | 7CD99CCB1D9002E100668467 = { 217 | isa = PBXGroup; 218 | children = ( 219 | 7CD99CE01D9002F900668467 /* Source */, 220 | 7C5EEE551E446AD8001C4E7A /* Tests */, 221 | 7CD99CD61D9002E100668467 /* Products */, 222 | ); 223 | sourceTree = ""; 224 | }; 225 | 7CD99CD61D9002E100668467 /* Products */ = { 226 | isa = PBXGroup; 227 | children = ( 228 | 7CD99CD51D9002E100668467 /* SwiftlyExt.framework */, 229 | 7CD99CEA1D901F0300668467 /* SwiftlyExt iOS Tests.xctest */, 230 | 7CB10D921D99613C00731EE9 /* SwiftlyExt.framework */, 231 | 7CB10DA31D99621700731EE9 /* SwiftlyExt.framework */, 232 | 7C135F5F1D99637800994840 /* SwiftlyExt tvOS Tests.xctest */, 233 | 7C135F711D9964A000994840 /* SwiftlyExt.framework */, 234 | 7C135F901D99660E00994840 /* SwiftlyExt macOS Tests.xctest */, 235 | ); 236 | name = Products; 237 | sourceTree = ""; 238 | }; 239 | 7CD99CE01D9002F900668467 /* Source */ = { 240 | isa = PBXGroup; 241 | children = ( 242 | 7CB10D8C1D9960AE00731EE9 /* Supporting Files */, 243 | 7CD99CE41D901C3800668467 /* IntExtensions.swift */, 244 | 7CD99CF71D9020BF00668467 /* RangeExtensions.swift */, 245 | 7CB10D871D99344700731EE9 /* ArrayExtensions.swift */, 246 | 7C14D21A1DA8E4DD00204587 /* DateExtensions.swift */, 247 | 7CF95F751DAB9D5D00C61E03 /* StringExtensions.swift */, 248 | 7C4EFA091E16469200DC9B08 /* CGPointExtensions.swift */, 249 | 7C4EFA131E164A7700DC9B08 /* CGFloatExtensions.swift */, 250 | 7C4EFA1C1E164D3A00DC9B08 /* DictionaryExtensions.swift */, 251 | 7C4B8DB11E3F28FE00004E9A /* Swiftly.swift */, 252 | ); 253 | path = Source; 254 | sourceTree = ""; 255 | }; 256 | /* End PBXGroup section */ 257 | 258 | /* Begin PBXHeadersBuildPhase section */ 259 | 7C135F6E1D9964A000994840 /* Headers */ = { 260 | isa = PBXHeadersBuildPhase; 261 | buildActionMask = 2147483647; 262 | files = ( 263 | 7C135F791D99658600994840 /* Swiftly.h in Headers */, 264 | ); 265 | runOnlyForDeploymentPostprocessing = 0; 266 | }; 267 | 7CB10D8F1D99613C00731EE9 /* Headers */ = { 268 | isa = PBXHeadersBuildPhase; 269 | buildActionMask = 2147483647; 270 | files = ( 271 | 7CB10D9A1D99619C00731EE9 /* Swiftly.h in Headers */, 272 | ); 273 | runOnlyForDeploymentPostprocessing = 0; 274 | }; 275 | 7CB10DA01D99621700731EE9 /* Headers */ = { 276 | isa = PBXHeadersBuildPhase; 277 | buildActionMask = 2147483647; 278 | files = ( 279 | 7CB10DAB1D99627800731EE9 /* Swiftly.h in Headers */, 280 | ); 281 | runOnlyForDeploymentPostprocessing = 0; 282 | }; 283 | 7CD99CD21D9002E100668467 /* Headers */ = { 284 | isa = PBXHeadersBuildPhase; 285 | buildActionMask = 2147483647; 286 | files = ( 287 | 7CD99CE31D9002FD00668467 /* Swiftly.h in Headers */, 288 | ); 289 | runOnlyForDeploymentPostprocessing = 0; 290 | }; 291 | /* End PBXHeadersBuildPhase section */ 292 | 293 | /* Begin PBXNativeTarget section */ 294 | 7C135F5E1D99637800994840 /* SwiftlyExt tvOS Tests */ = { 295 | isa = PBXNativeTarget; 296 | buildConfigurationList = 7C135F671D99637800994840 /* Build configuration list for PBXNativeTarget "SwiftlyExt tvOS Tests" */; 297 | buildPhases = ( 298 | 7C135F5B1D99637800994840 /* Sources */, 299 | 7C135F5C1D99637800994840 /* Frameworks */, 300 | 7C135F5D1D99637800994840 /* Resources */, 301 | ); 302 | buildRules = ( 303 | ); 304 | dependencies = ( 305 | 7C135F661D99637800994840 /* PBXTargetDependency */, 306 | ); 307 | name = "SwiftlyExt tvOS Tests"; 308 | productName = tvostests; 309 | productReference = 7C135F5F1D99637800994840 /* SwiftlyExt tvOS Tests.xctest */; 310 | productType = "com.apple.product-type.bundle.unit-test"; 311 | }; 312 | 7C135F701D9964A000994840 /* SwiftlyExt macOS */ = { 313 | isa = PBXNativeTarget; 314 | buildConfigurationList = 7C135F761D9964A000994840 /* Build configuration list for PBXNativeTarget "SwiftlyExt macOS" */; 315 | buildPhases = ( 316 | 7CA7C87D1E24E80800EA2F6A /* SwiftLint */, 317 | 7C135F6C1D9964A000994840 /* Sources */, 318 | 7C135F6D1D9964A000994840 /* Frameworks */, 319 | 7C135F6E1D9964A000994840 /* Headers */, 320 | 7C135F6F1D9964A000994840 /* Resources */, 321 | ); 322 | buildRules = ( 323 | ); 324 | dependencies = ( 325 | ); 326 | name = "SwiftlyExt macOS"; 327 | productName = Swiftlymac; 328 | productReference = 7C135F711D9964A000994840 /* SwiftlyExt.framework */; 329 | productType = "com.apple.product-type.framework"; 330 | }; 331 | 7C135F8F1D99660E00994840 /* SwiftlyExt macOS Tests */ = { 332 | isa = PBXNativeTarget; 333 | buildConfigurationList = 7C135F981D99660E00994840 /* Build configuration list for PBXNativeTarget "SwiftlyExt macOS Tests" */; 334 | buildPhases = ( 335 | 7C135F8C1D99660E00994840 /* Sources */, 336 | 7C135F8D1D99660E00994840 /* Frameworks */, 337 | 7C135F8E1D99660E00994840 /* Resources */, 338 | ); 339 | buildRules = ( 340 | ); 341 | dependencies = ( 342 | 7C135F971D99660E00994840 /* PBXTargetDependency */, 343 | ); 344 | name = "SwiftlyExt macOS Tests"; 345 | productName = SwiftlyTests; 346 | productReference = 7C135F901D99660E00994840 /* SwiftlyExt macOS Tests.xctest */; 347 | productType = "com.apple.product-type.bundle.unit-test"; 348 | }; 349 | 7CB10D911D99613C00731EE9 /* SwiftlyExt watchOS */ = { 350 | isa = PBXNativeTarget; 351 | buildConfigurationList = 7CB10D971D99613C00731EE9 /* Build configuration list for PBXNativeTarget "SwiftlyExt watchOS" */; 352 | buildPhases = ( 353 | 7CA7C87F1E24E82000EA2F6A /* SwiftLint */, 354 | 7CB10D8D1D99613C00731EE9 /* Sources */, 355 | 7CB10D8E1D99613C00731EE9 /* Frameworks */, 356 | 7CB10D8F1D99613C00731EE9 /* Headers */, 357 | 7CB10D901D99613C00731EE9 /* Resources */, 358 | ); 359 | buildRules = ( 360 | ); 361 | dependencies = ( 362 | ); 363 | name = "SwiftlyExt watchOS"; 364 | productName = "Swiftly-watchOS"; 365 | productReference = 7CB10D921D99613C00731EE9 /* SwiftlyExt.framework */; 366 | productType = "com.apple.product-type.framework"; 367 | }; 368 | 7CB10DA21D99621700731EE9 /* SwiftlyExt tvOS */ = { 369 | isa = PBXNativeTarget; 370 | buildConfigurationList = 7CB10DA81D99621700731EE9 /* Build configuration list for PBXNativeTarget "SwiftlyExt tvOS" */; 371 | buildPhases = ( 372 | 7CA7C87E1E24E81200EA2F6A /* SwiftLint */, 373 | 7CB10D9E1D99621700731EE9 /* Sources */, 374 | 7CB10D9F1D99621700731EE9 /* Frameworks */, 375 | 7CB10DA01D99621700731EE9 /* Headers */, 376 | 7CB10DA11D99621700731EE9 /* Resources */, 377 | ); 378 | buildRules = ( 379 | ); 380 | dependencies = ( 381 | ); 382 | name = "SwiftlyExt tvOS"; 383 | productName = swiftlytv; 384 | productReference = 7CB10DA31D99621700731EE9 /* SwiftlyExt.framework */; 385 | productType = "com.apple.product-type.framework"; 386 | }; 387 | 7CD99CD41D9002E100668467 /* SwiftlyExt iOS */ = { 388 | isa = PBXNativeTarget; 389 | buildConfigurationList = 7CD99CDD1D9002E100668467 /* Build configuration list for PBXNativeTarget "SwiftlyExt iOS" */; 390 | buildPhases = ( 391 | 7CA7C87C1E24E7EF00EA2F6A /* SwiftLint */, 392 | 7CD99CD01D9002E100668467 /* Sources */, 393 | 7CD99CD11D9002E100668467 /* Frameworks */, 394 | 7CD99CD21D9002E100668467 /* Headers */, 395 | 7CD99CD31D9002E100668467 /* Resources */, 396 | ); 397 | buildRules = ( 398 | ); 399 | dependencies = ( 400 | ); 401 | name = "SwiftlyExt iOS"; 402 | productName = Swiftly; 403 | productReference = 7CD99CD51D9002E100668467 /* SwiftlyExt.framework */; 404 | productType = "com.apple.product-type.framework"; 405 | }; 406 | 7CD99CE91D901F0300668467 /* SwiftlyExt iOS Tests */ = { 407 | isa = PBXNativeTarget; 408 | buildConfigurationList = 7CD99CF21D901F0300668467 /* Build configuration list for PBXNativeTarget "SwiftlyExt iOS Tests" */; 409 | buildPhases = ( 410 | 7CD99CE61D901F0300668467 /* Sources */, 411 | 7CD99CE71D901F0300668467 /* Frameworks */, 412 | 7CD99CE81D901F0300668467 /* Resources */, 413 | ); 414 | buildRules = ( 415 | ); 416 | dependencies = ( 417 | 7CD99CF11D901F0300668467 /* PBXTargetDependency */, 418 | ); 419 | name = "SwiftlyExt iOS Tests"; 420 | productName = SwiftlyTests; 421 | productReference = 7CD99CEA1D901F0300668467 /* SwiftlyExt iOS Tests.xctest */; 422 | productType = "com.apple.product-type.bundle.unit-test"; 423 | }; 424 | /* End PBXNativeTarget section */ 425 | 426 | /* Begin PBXProject section */ 427 | 7CD99CCC1D9002E100668467 /* Project object */ = { 428 | isa = PBXProject; 429 | attributes = { 430 | LastSwiftUpdateCheck = 0800; 431 | LastUpgradeCheck = 0820; 432 | ORGANIZATIONNAME = "Khoi Lai"; 433 | TargetAttributes = { 434 | 7C135F5E1D99637800994840 = { 435 | CreatedOnToolsVersion = 8.0; 436 | ProvisioningStyle = Automatic; 437 | }; 438 | 7C135F701D9964A000994840 = { 439 | CreatedOnToolsVersion = 8.0; 440 | ProvisioningStyle = Automatic; 441 | }; 442 | 7C135F8F1D99660E00994840 = { 443 | CreatedOnToolsVersion = 8.0; 444 | DevelopmentTeam = 7G5K6NH4YV; 445 | ProvisioningStyle = Automatic; 446 | }; 447 | 7CB10D911D99613C00731EE9 = { 448 | CreatedOnToolsVersion = 8.0; 449 | ProvisioningStyle = Automatic; 450 | }; 451 | 7CB10DA21D99621700731EE9 = { 452 | CreatedOnToolsVersion = 8.0; 453 | ProvisioningStyle = Automatic; 454 | }; 455 | 7CD99CD41D9002E100668467 = { 456 | CreatedOnToolsVersion = 8.0; 457 | LastSwiftMigration = 0800; 458 | ProvisioningStyle = Automatic; 459 | }; 460 | 7CD99CE91D901F0300668467 = { 461 | CreatedOnToolsVersion = 8.0; 462 | ProvisioningStyle = Automatic; 463 | }; 464 | }; 465 | }; 466 | buildConfigurationList = 7CD99CCF1D9002E100668467 /* Build configuration list for PBXProject "SwiftlyExt" */; 467 | compatibilityVersion = "Xcode 3.2"; 468 | developmentRegion = English; 469 | hasScannedForEncodings = 0; 470 | knownRegions = ( 471 | en, 472 | ); 473 | mainGroup = 7CD99CCB1D9002E100668467; 474 | productRefGroup = 7CD99CD61D9002E100668467 /* Products */; 475 | projectDirPath = ""; 476 | projectRoot = ""; 477 | targets = ( 478 | 7CD99CD41D9002E100668467 /* SwiftlyExt iOS */, 479 | 7CD99CE91D901F0300668467 /* SwiftlyExt iOS Tests */, 480 | 7C135F701D9964A000994840 /* SwiftlyExt macOS */, 481 | 7C135F8F1D99660E00994840 /* SwiftlyExt macOS Tests */, 482 | 7CB10DA21D99621700731EE9 /* SwiftlyExt tvOS */, 483 | 7C135F5E1D99637800994840 /* SwiftlyExt tvOS Tests */, 484 | 7CB10D911D99613C00731EE9 /* SwiftlyExt watchOS */, 485 | ); 486 | }; 487 | /* End PBXProject section */ 488 | 489 | /* Begin PBXResourcesBuildPhase section */ 490 | 7C135F5D1D99637800994840 /* Resources */ = { 491 | isa = PBXResourcesBuildPhase; 492 | buildActionMask = 2147483647; 493 | files = ( 494 | ); 495 | runOnlyForDeploymentPostprocessing = 0; 496 | }; 497 | 7C135F6F1D9964A000994840 /* Resources */ = { 498 | isa = PBXResourcesBuildPhase; 499 | buildActionMask = 2147483647; 500 | files = ( 501 | ); 502 | runOnlyForDeploymentPostprocessing = 0; 503 | }; 504 | 7C135F8E1D99660E00994840 /* Resources */ = { 505 | isa = PBXResourcesBuildPhase; 506 | buildActionMask = 2147483647; 507 | files = ( 508 | ); 509 | runOnlyForDeploymentPostprocessing = 0; 510 | }; 511 | 7CB10D901D99613C00731EE9 /* Resources */ = { 512 | isa = PBXResourcesBuildPhase; 513 | buildActionMask = 2147483647; 514 | files = ( 515 | ); 516 | runOnlyForDeploymentPostprocessing = 0; 517 | }; 518 | 7CB10DA11D99621700731EE9 /* Resources */ = { 519 | isa = PBXResourcesBuildPhase; 520 | buildActionMask = 2147483647; 521 | files = ( 522 | ); 523 | runOnlyForDeploymentPostprocessing = 0; 524 | }; 525 | 7CD99CD31D9002E100668467 /* Resources */ = { 526 | isa = PBXResourcesBuildPhase; 527 | buildActionMask = 2147483647; 528 | files = ( 529 | ); 530 | runOnlyForDeploymentPostprocessing = 0; 531 | }; 532 | 7CD99CE81D901F0300668467 /* Resources */ = { 533 | isa = PBXResourcesBuildPhase; 534 | buildActionMask = 2147483647; 535 | files = ( 536 | ); 537 | runOnlyForDeploymentPostprocessing = 0; 538 | }; 539 | /* End PBXResourcesBuildPhase section */ 540 | 541 | /* Begin PBXShellScriptBuildPhase section */ 542 | 7CA7C87C1E24E7EF00EA2F6A /* SwiftLint */ = { 543 | isa = PBXShellScriptBuildPhase; 544 | buildActionMask = 2147483647; 545 | files = ( 546 | ); 547 | inputPaths = ( 548 | ); 549 | name = SwiftLint; 550 | outputPaths = ( 551 | ); 552 | runOnlyForDeploymentPostprocessing = 0; 553 | shellPath = /bin/sh; 554 | shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; 555 | }; 556 | 7CA7C87D1E24E80800EA2F6A /* SwiftLint */ = { 557 | isa = PBXShellScriptBuildPhase; 558 | buildActionMask = 2147483647; 559 | files = ( 560 | ); 561 | inputPaths = ( 562 | ); 563 | name = SwiftLint; 564 | outputPaths = ( 565 | ); 566 | runOnlyForDeploymentPostprocessing = 0; 567 | shellPath = /bin/sh; 568 | shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; 569 | }; 570 | 7CA7C87E1E24E81200EA2F6A /* SwiftLint */ = { 571 | isa = PBXShellScriptBuildPhase; 572 | buildActionMask = 2147483647; 573 | files = ( 574 | ); 575 | inputPaths = ( 576 | ); 577 | name = SwiftLint; 578 | outputPaths = ( 579 | ); 580 | runOnlyForDeploymentPostprocessing = 0; 581 | shellPath = /bin/sh; 582 | shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; 583 | }; 584 | 7CA7C87F1E24E82000EA2F6A /* SwiftLint */ = { 585 | isa = PBXShellScriptBuildPhase; 586 | buildActionMask = 2147483647; 587 | files = ( 588 | ); 589 | inputPaths = ( 590 | ); 591 | name = SwiftLint; 592 | outputPaths = ( 593 | ); 594 | runOnlyForDeploymentPostprocessing = 0; 595 | shellPath = /bin/sh; 596 | shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; 597 | }; 598 | /* End PBXShellScriptBuildPhase section */ 599 | 600 | /* Begin PBXSourcesBuildPhase section */ 601 | 7C135F5B1D99637800994840 /* Sources */ = { 602 | isa = PBXSourcesBuildPhase; 603 | buildActionMask = 2147483647; 604 | files = ( 605 | 7C5EEE651E446ADF001C4E7A /* CGFloatTests.swift in Sources */, 606 | 7C5EEE741E446AE2001C4E7A /* StringTests.swift in Sources */, 607 | 7C5EEE751E446AE2001C4E7A /* SwiftlyTests.swift in Sources */, 608 | 7C5EEE641E446ADF001C4E7A /* ArrayTests.swift in Sources */, 609 | 7C5EEE671E446ADF001C4E7A /* DateTests.swift in Sources */, 610 | 7C5EEE731E446AE2001C4E7A /* IntTests.swift in Sources */, 611 | 7C5EEE681E446ADF001C4E7A /* DictionaryTests.swift in Sources */, 612 | 7C5EEE661E446ADF001C4E7A /* CGPointTests.swift in Sources */, 613 | ); 614 | runOnlyForDeploymentPostprocessing = 0; 615 | }; 616 | 7C135F6C1D9964A000994840 /* Sources */ = { 617 | isa = PBXSourcesBuildPhase; 618 | buildActionMask = 2147483647; 619 | files = ( 620 | 7C4B8DB31E3F28FE00004E9A /* Swiftly.swift in Sources */, 621 | 7C135F7C1D99658B00994840 /* ArrayExtensions.swift in Sources */, 622 | 7C4EFA1E1E164D6B00DC9B08 /* DictionaryExtensions.swift in Sources */, 623 | 7C135F7A1D99658B00994840 /* IntExtensions.swift in Sources */, 624 | 7C4EFA151E164A8200DC9B08 /* CGFloatExtensions.swift in Sources */, 625 | 7CF95F7D1DAB9FA700C61E03 /* StringExtensions.swift in Sources */, 626 | 7C14D21C1DA8E51D00204587 /* DateExtensions.swift in Sources */, 627 | 7C4EFA101E1648D600DC9B08 /* CGPointExtensions.swift in Sources */, 628 | 7C135F7B1D99658B00994840 /* RangeExtensions.swift in Sources */, 629 | ); 630 | runOnlyForDeploymentPostprocessing = 0; 631 | }; 632 | 7C135F8C1D99660E00994840 /* Sources */ = { 633 | isa = PBXSourcesBuildPhase; 634 | buildActionMask = 2147483647; 635 | files = ( 636 | 7C5EEE6A1E446ADF001C4E7A /* CGFloatTests.swift in Sources */, 637 | 7C5EEE771E446AE3001C4E7A /* StringTests.swift in Sources */, 638 | 7C5EEE781E446AE3001C4E7A /* SwiftlyTests.swift in Sources */, 639 | 7C5EEE691E446ADF001C4E7A /* ArrayTests.swift in Sources */, 640 | 7C5EEE6C1E446ADF001C4E7A /* DateTests.swift in Sources */, 641 | 7C5EEE761E446AE3001C4E7A /* IntTests.swift in Sources */, 642 | 7C5EEE6D1E446ADF001C4E7A /* DictionaryTests.swift in Sources */, 643 | 7C5EEE6B1E446ADF001C4E7A /* CGPointTests.swift in Sources */, 644 | ); 645 | runOnlyForDeploymentPostprocessing = 0; 646 | }; 647 | 7CB10D8D1D99613C00731EE9 /* Sources */ = { 648 | isa = PBXSourcesBuildPhase; 649 | buildActionMask = 2147483647; 650 | files = ( 651 | 7C4B8DB51E3F28FE00004E9A /* Swiftly.swift in Sources */, 652 | 7CB10D9D1D9961A400731EE9 /* ArrayExtensions.swift in Sources */, 653 | 7C4EFA201E164D6C00DC9B08 /* DictionaryExtensions.swift in Sources */, 654 | 7CB10D9B1D9961A400731EE9 /* IntExtensions.swift in Sources */, 655 | 7C4EFA171E164A8300DC9B08 /* CGFloatExtensions.swift in Sources */, 656 | 7CF95F7F1DAB9FA800C61E03 /* StringExtensions.swift in Sources */, 657 | 7C14D21E1DA8E51E00204587 /* DateExtensions.swift in Sources */, 658 | 7C4EFA121E1648D700DC9B08 /* CGPointExtensions.swift in Sources */, 659 | 7CB10D9C1D9961A400731EE9 /* RangeExtensions.swift in Sources */, 660 | ); 661 | runOnlyForDeploymentPostprocessing = 0; 662 | }; 663 | 7CB10D9E1D99621700731EE9 /* Sources */ = { 664 | isa = PBXSourcesBuildPhase; 665 | buildActionMask = 2147483647; 666 | files = ( 667 | 7C4B8DB41E3F28FE00004E9A /* Swiftly.swift in Sources */, 668 | 7CB10DAE1D99627D00731EE9 /* ArrayExtensions.swift in Sources */, 669 | 7C4EFA1F1E164D6C00DC9B08 /* DictionaryExtensions.swift in Sources */, 670 | 7CB10DAC1D99627D00731EE9 /* IntExtensions.swift in Sources */, 671 | 7C4EFA161E164A8200DC9B08 /* CGFloatExtensions.swift in Sources */, 672 | 7CF95F7E1DAB9FA800C61E03 /* StringExtensions.swift in Sources */, 673 | 7C14D21D1DA8E51E00204587 /* DateExtensions.swift in Sources */, 674 | 7C4EFA111E1648D700DC9B08 /* CGPointExtensions.swift in Sources */, 675 | 7CB10DAD1D99627D00731EE9 /* RangeExtensions.swift in Sources */, 676 | ); 677 | runOnlyForDeploymentPostprocessing = 0; 678 | }; 679 | 7CD99CD01D9002E100668467 /* Sources */ = { 680 | isa = PBXSourcesBuildPhase; 681 | buildActionMask = 2147483647; 682 | files = ( 683 | 7C4B8DB21E3F28FE00004E9A /* Swiftly.swift in Sources */, 684 | 7CB10D881D99344700731EE9 /* ArrayExtensions.swift in Sources */, 685 | 7C4EFA1D1E164D3A00DC9B08 /* DictionaryExtensions.swift in Sources */, 686 | 7CD99CE51D901C3800668467 /* IntExtensions.swift in Sources */, 687 | 7C4EFA141E164A7700DC9B08 /* CGFloatExtensions.swift in Sources */, 688 | 7CF95F761DAB9D5D00C61E03 /* StringExtensions.swift in Sources */, 689 | 7C14D21B1DA8E4DD00204587 /* DateExtensions.swift in Sources */, 690 | 7C4EFA0A1E16469200DC9B08 /* CGPointExtensions.swift in Sources */, 691 | 7CD99CF81D9020BF00668467 /* RangeExtensions.swift in Sources */, 692 | ); 693 | runOnlyForDeploymentPostprocessing = 0; 694 | }; 695 | 7CD99CE61D901F0300668467 /* Sources */ = { 696 | isa = PBXSourcesBuildPhase; 697 | buildActionMask = 2147483647; 698 | files = ( 699 | 7C5EEE6F1E446ADF001C4E7A /* CGFloatTests.swift in Sources */, 700 | 7C5EEE7A1E446AE3001C4E7A /* StringTests.swift in Sources */, 701 | 7C5EEE7B1E446AE3001C4E7A /* SwiftlyTests.swift in Sources */, 702 | 7C5EEE6E1E446ADF001C4E7A /* ArrayTests.swift in Sources */, 703 | 7C5EEE711E446ADF001C4E7A /* DateTests.swift in Sources */, 704 | 7C5EEE791E446AE3001C4E7A /* IntTests.swift in Sources */, 705 | 7C5EEE721E446ADF001C4E7A /* DictionaryTests.swift in Sources */, 706 | 7C5EEE701E446ADF001C4E7A /* CGPointTests.swift in Sources */, 707 | ); 708 | runOnlyForDeploymentPostprocessing = 0; 709 | }; 710 | /* End PBXSourcesBuildPhase section */ 711 | 712 | /* Begin PBXTargetDependency section */ 713 | 7C135F661D99637800994840 /* PBXTargetDependency */ = { 714 | isa = PBXTargetDependency; 715 | target = 7CB10DA21D99621700731EE9 /* SwiftlyExt tvOS */; 716 | targetProxy = 7C135F651D99637800994840 /* PBXContainerItemProxy */; 717 | }; 718 | 7C135F971D99660E00994840 /* PBXTargetDependency */ = { 719 | isa = PBXTargetDependency; 720 | target = 7C135F701D9964A000994840 /* SwiftlyExt macOS */; 721 | targetProxy = 7C135F961D99660E00994840 /* PBXContainerItemProxy */; 722 | }; 723 | 7CD99CF11D901F0300668467 /* PBXTargetDependency */ = { 724 | isa = PBXTargetDependency; 725 | target = 7CD99CD41D9002E100668467 /* SwiftlyExt iOS */; 726 | targetProxy = 7CD99CF01D901F0300668467 /* PBXContainerItemProxy */; 727 | }; 728 | /* End PBXTargetDependency section */ 729 | 730 | /* Begin XCBuildConfiguration section */ 731 | 7C135F681D99637800994840 /* Debug */ = { 732 | isa = XCBuildConfiguration; 733 | buildSettings = { 734 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "iPhone Developer"; 735 | DEVELOPMENT_TEAM = ""; 736 | INFOPLIST_FILE = Tests/Info.plist; 737 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 738 | PRODUCT_BUNDLE_IDENTIFIER = io.github.khoiln.SwiftlyTests; 739 | PRODUCT_NAME = "$(TARGET_NAME)"; 740 | SDKROOT = appletvos; 741 | SWIFT_VERSION = 3.0; 742 | TVOS_DEPLOYMENT_TARGET = 10.0; 743 | }; 744 | name = Debug; 745 | }; 746 | 7C135F691D99637800994840 /* Release */ = { 747 | isa = XCBuildConfiguration; 748 | buildSettings = { 749 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "iPhone Developer"; 750 | DEVELOPMENT_TEAM = ""; 751 | INFOPLIST_FILE = Tests/Info.plist; 752 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 753 | PRODUCT_BUNDLE_IDENTIFIER = io.github.khoiln.SwiftlyTests; 754 | PRODUCT_NAME = "$(TARGET_NAME)"; 755 | SDKROOT = appletvos; 756 | SWIFT_VERSION = 3.0; 757 | TVOS_DEPLOYMENT_TARGET = 10.0; 758 | }; 759 | name = Release; 760 | }; 761 | 7C135F771D9964A000994840 /* Debug */ = { 762 | isa = XCBuildConfiguration; 763 | buildSettings = { 764 | CODE_SIGN_IDENTITY = "-"; 765 | COMBINE_HIDPI_IMAGES = YES; 766 | DEFINES_MODULE = YES; 767 | DEVELOPMENT_TEAM = ""; 768 | DYLIB_COMPATIBILITY_VERSION = 1; 769 | DYLIB_CURRENT_VERSION = 1; 770 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 771 | FRAMEWORK_VERSION = A; 772 | INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist"; 773 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 774 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 775 | MACOSX_DEPLOYMENT_TARGET = 10.11; 776 | PRODUCT_BUNDLE_IDENTIFIER = io.github.khoiln.Swiftly; 777 | PRODUCT_NAME = SwiftlyExt; 778 | SDKROOT = macosx; 779 | SKIP_INSTALL = YES; 780 | SWIFT_VERSION = 3.0; 781 | }; 782 | name = Debug; 783 | }; 784 | 7C135F781D9964A000994840 /* Release */ = { 785 | isa = XCBuildConfiguration; 786 | buildSettings = { 787 | CODE_SIGN_IDENTITY = "-"; 788 | COMBINE_HIDPI_IMAGES = YES; 789 | DEFINES_MODULE = YES; 790 | DEVELOPMENT_TEAM = ""; 791 | DYLIB_COMPATIBILITY_VERSION = 1; 792 | DYLIB_CURRENT_VERSION = 1; 793 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 794 | FRAMEWORK_VERSION = A; 795 | INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist"; 796 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 797 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 798 | MACOSX_DEPLOYMENT_TARGET = 10.11; 799 | PRODUCT_BUNDLE_IDENTIFIER = io.github.khoiln.Swiftly; 800 | PRODUCT_NAME = SwiftlyExt; 801 | SDKROOT = macosx; 802 | SKIP_INSTALL = YES; 803 | SWIFT_VERSION = 3.0; 804 | }; 805 | name = Release; 806 | }; 807 | 7C135F991D99660E00994840 /* Debug */ = { 808 | isa = XCBuildConfiguration; 809 | buildSettings = { 810 | CODE_SIGN_IDENTITY = "-"; 811 | COMBINE_HIDPI_IMAGES = YES; 812 | DEVELOPMENT_TEAM = 7G5K6NH4YV; 813 | INFOPLIST_FILE = Tests/Info.plist; 814 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 815 | MACOSX_DEPLOYMENT_TARGET = 10.12; 816 | PRODUCT_BUNDLE_IDENTIFIER = io.github.khoiln.SwiftlyTests; 817 | PRODUCT_NAME = "$(TARGET_NAME)"; 818 | SDKROOT = macosx; 819 | SWIFT_VERSION = 3.0; 820 | }; 821 | name = Debug; 822 | }; 823 | 7C135F9A1D99660E00994840 /* Release */ = { 824 | isa = XCBuildConfiguration; 825 | buildSettings = { 826 | CODE_SIGN_IDENTITY = "-"; 827 | COMBINE_HIDPI_IMAGES = YES; 828 | DEVELOPMENT_TEAM = 7G5K6NH4YV; 829 | INFOPLIST_FILE = Tests/Info.plist; 830 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 831 | MACOSX_DEPLOYMENT_TARGET = 10.12; 832 | PRODUCT_BUNDLE_IDENTIFIER = io.github.khoiln.SwiftlyTests; 833 | PRODUCT_NAME = "$(TARGET_NAME)"; 834 | SDKROOT = macosx; 835 | SWIFT_VERSION = 3.0; 836 | }; 837 | name = Release; 838 | }; 839 | 7CB10D981D99613C00731EE9 /* Debug */ = { 840 | isa = XCBuildConfiguration; 841 | buildSettings = { 842 | APPLICATION_EXTENSION_API_ONLY = YES; 843 | CODE_SIGN_IDENTITY = ""; 844 | DEFINES_MODULE = YES; 845 | DEVELOPMENT_TEAM = ""; 846 | DYLIB_COMPATIBILITY_VERSION = 1; 847 | DYLIB_CURRENT_VERSION = 1; 848 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 849 | INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist"; 850 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 851 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 852 | PRODUCT_BUNDLE_IDENTIFIER = io.github.khoiln.Swiftly; 853 | PRODUCT_NAME = SwiftlyExt; 854 | SDKROOT = watchos; 855 | SKIP_INSTALL = YES; 856 | SWIFT_VERSION = 3.0; 857 | TARGETED_DEVICE_FAMILY = 4; 858 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 859 | }; 860 | name = Debug; 861 | }; 862 | 7CB10D991D99613C00731EE9 /* Release */ = { 863 | isa = XCBuildConfiguration; 864 | buildSettings = { 865 | APPLICATION_EXTENSION_API_ONLY = YES; 866 | CODE_SIGN_IDENTITY = ""; 867 | DEFINES_MODULE = YES; 868 | DEVELOPMENT_TEAM = ""; 869 | DYLIB_COMPATIBILITY_VERSION = 1; 870 | DYLIB_CURRENT_VERSION = 1; 871 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 872 | INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist"; 873 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 874 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 875 | PRODUCT_BUNDLE_IDENTIFIER = io.github.khoiln.Swiftly; 876 | PRODUCT_NAME = SwiftlyExt; 877 | SDKROOT = watchos; 878 | SKIP_INSTALL = YES; 879 | SWIFT_VERSION = 3.0; 880 | TARGETED_DEVICE_FAMILY = 4; 881 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 882 | }; 883 | name = Release; 884 | }; 885 | 7CB10DA91D99621700731EE9 /* Debug */ = { 886 | isa = XCBuildConfiguration; 887 | buildSettings = { 888 | CODE_SIGN_IDENTITY = ""; 889 | DEFINES_MODULE = YES; 890 | DEVELOPMENT_TEAM = ""; 891 | DYLIB_COMPATIBILITY_VERSION = 1; 892 | DYLIB_CURRENT_VERSION = 1; 893 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 894 | INFOPLIST_FILE = "$(SRCROOT)/Source/Info-tvOS.plist"; 895 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 896 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 897 | PRODUCT_BUNDLE_IDENTIFIER = io.github.khoiln.Swiftly; 898 | PRODUCT_NAME = SwiftlyExt; 899 | SDKROOT = appletvos; 900 | SKIP_INSTALL = YES; 901 | SWIFT_VERSION = 3.0; 902 | TARGETED_DEVICE_FAMILY = 3; 903 | TVOS_DEPLOYMENT_TARGET = 9.0; 904 | }; 905 | name = Debug; 906 | }; 907 | 7CB10DAA1D99621700731EE9 /* Release */ = { 908 | isa = XCBuildConfiguration; 909 | buildSettings = { 910 | CODE_SIGN_IDENTITY = ""; 911 | DEFINES_MODULE = YES; 912 | DEVELOPMENT_TEAM = ""; 913 | DYLIB_COMPATIBILITY_VERSION = 1; 914 | DYLIB_CURRENT_VERSION = 1; 915 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 916 | INFOPLIST_FILE = "$(SRCROOT)/Source/Info-tvOS.plist"; 917 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 918 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 919 | PRODUCT_BUNDLE_IDENTIFIER = io.github.khoiln.Swiftly; 920 | PRODUCT_NAME = SwiftlyExt; 921 | SDKROOT = appletvos; 922 | SKIP_INSTALL = YES; 923 | SWIFT_VERSION = 3.0; 924 | TARGETED_DEVICE_FAMILY = 3; 925 | TVOS_DEPLOYMENT_TARGET = 9.0; 926 | }; 927 | name = Release; 928 | }; 929 | 7CD99CDB1D9002E100668467 /* Debug */ = { 930 | isa = XCBuildConfiguration; 931 | buildSettings = { 932 | ALWAYS_SEARCH_USER_PATHS = NO; 933 | CLANG_ANALYZER_NONNULL = YES; 934 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 935 | CLANG_CXX_LIBRARY = "libc++"; 936 | CLANG_ENABLE_MODULES = YES; 937 | CLANG_ENABLE_OBJC_ARC = YES; 938 | CLANG_WARN_BOOL_CONVERSION = YES; 939 | CLANG_WARN_CONSTANT_CONVERSION = YES; 940 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 941 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 942 | CLANG_WARN_EMPTY_BODY = YES; 943 | CLANG_WARN_ENUM_CONVERSION = YES; 944 | CLANG_WARN_INFINITE_RECURSION = YES; 945 | CLANG_WARN_INT_CONVERSION = YES; 946 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 947 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 948 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 949 | CLANG_WARN_UNREACHABLE_CODE = YES; 950 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 951 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 952 | COPY_PHASE_STRIP = NO; 953 | CURRENT_PROJECT_VERSION = 1; 954 | DEBUG_INFORMATION_FORMAT = dwarf; 955 | ENABLE_STRICT_OBJC_MSGSEND = YES; 956 | ENABLE_TESTABILITY = YES; 957 | GCC_C_LANGUAGE_STANDARD = gnu99; 958 | GCC_DYNAMIC_NO_PIC = NO; 959 | GCC_NO_COMMON_BLOCKS = YES; 960 | GCC_OPTIMIZATION_LEVEL = 0; 961 | GCC_PREPROCESSOR_DEFINITIONS = ( 962 | "DEBUG=1", 963 | "$(inherited)", 964 | ); 965 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 966 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 967 | GCC_WARN_UNDECLARED_SELECTOR = YES; 968 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 969 | GCC_WARN_UNUSED_FUNCTION = YES; 970 | GCC_WARN_UNUSED_VARIABLE = YES; 971 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 972 | MTL_ENABLE_DEBUG_INFO = YES; 973 | ONLY_ACTIVE_ARCH = YES; 974 | SDKROOT = iphoneos; 975 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 976 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 977 | TARGETED_DEVICE_FAMILY = "1,2"; 978 | VERSIONING_SYSTEM = "apple-generic"; 979 | VERSION_INFO_PREFIX = ""; 980 | }; 981 | name = Debug; 982 | }; 983 | 7CD99CDC1D9002E100668467 /* Release */ = { 984 | isa = XCBuildConfiguration; 985 | buildSettings = { 986 | ALWAYS_SEARCH_USER_PATHS = NO; 987 | CLANG_ANALYZER_NONNULL = YES; 988 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 989 | CLANG_CXX_LIBRARY = "libc++"; 990 | CLANG_ENABLE_MODULES = YES; 991 | CLANG_ENABLE_OBJC_ARC = YES; 992 | CLANG_WARN_BOOL_CONVERSION = YES; 993 | CLANG_WARN_CONSTANT_CONVERSION = YES; 994 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 995 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 996 | CLANG_WARN_EMPTY_BODY = YES; 997 | CLANG_WARN_ENUM_CONVERSION = YES; 998 | CLANG_WARN_INFINITE_RECURSION = YES; 999 | CLANG_WARN_INT_CONVERSION = YES; 1000 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 1001 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 1002 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 1003 | CLANG_WARN_UNREACHABLE_CODE = YES; 1004 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 1005 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 1006 | COPY_PHASE_STRIP = NO; 1007 | CURRENT_PROJECT_VERSION = 1; 1008 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 1009 | ENABLE_NS_ASSERTIONS = NO; 1010 | ENABLE_STRICT_OBJC_MSGSEND = YES; 1011 | GCC_C_LANGUAGE_STANDARD = gnu99; 1012 | GCC_NO_COMMON_BLOCKS = YES; 1013 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 1014 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 1015 | GCC_WARN_UNDECLARED_SELECTOR = YES; 1016 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 1017 | GCC_WARN_UNUSED_FUNCTION = YES; 1018 | GCC_WARN_UNUSED_VARIABLE = YES; 1019 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 1020 | MTL_ENABLE_DEBUG_INFO = NO; 1021 | SDKROOT = iphoneos; 1022 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 1023 | TARGETED_DEVICE_FAMILY = "1,2"; 1024 | VALIDATE_PRODUCT = YES; 1025 | VERSIONING_SYSTEM = "apple-generic"; 1026 | VERSION_INFO_PREFIX = ""; 1027 | }; 1028 | name = Release; 1029 | }; 1030 | 7CD99CDE1D9002E100668467 /* Debug */ = { 1031 | isa = XCBuildConfiguration; 1032 | buildSettings = { 1033 | CLANG_ENABLE_MODULES = YES; 1034 | CODE_SIGN_IDENTITY = ""; 1035 | DEFINES_MODULE = YES; 1036 | DEVELOPMENT_TEAM = ""; 1037 | DYLIB_COMPATIBILITY_VERSION = 1; 1038 | DYLIB_CURRENT_VERSION = 1; 1039 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 1040 | INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist"; 1041 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 1042 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 1043 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1044 | PRODUCT_BUNDLE_IDENTIFIER = io.github.khoiln.Swiftly; 1045 | PRODUCT_NAME = SwiftlyExt; 1046 | SKIP_INSTALL = YES; 1047 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 1048 | SWIFT_VERSION = 3.0; 1049 | }; 1050 | name = Debug; 1051 | }; 1052 | 7CD99CDF1D9002E100668467 /* Release */ = { 1053 | isa = XCBuildConfiguration; 1054 | buildSettings = { 1055 | CLANG_ENABLE_MODULES = YES; 1056 | CODE_SIGN_IDENTITY = ""; 1057 | DEFINES_MODULE = YES; 1058 | DEVELOPMENT_TEAM = ""; 1059 | DYLIB_COMPATIBILITY_VERSION = 1; 1060 | DYLIB_CURRENT_VERSION = 1; 1061 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 1062 | INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist"; 1063 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 1064 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 1065 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1066 | PRODUCT_BUNDLE_IDENTIFIER = io.github.khoiln.Swiftly; 1067 | PRODUCT_NAME = SwiftlyExt; 1068 | SKIP_INSTALL = YES; 1069 | SWIFT_VERSION = 3.0; 1070 | }; 1071 | name = Release; 1072 | }; 1073 | 7CD99CF31D901F0300668467 /* Debug */ = { 1074 | isa = XCBuildConfiguration; 1075 | buildSettings = { 1076 | DEVELOPMENT_TEAM = ""; 1077 | INFOPLIST_FILE = Tests/Info.plist; 1078 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1079 | PRODUCT_BUNDLE_IDENTIFIER = io.github.khoiln.SwiftlyTests; 1080 | PRODUCT_NAME = "$(TARGET_NAME)"; 1081 | SWIFT_VERSION = 3.0; 1082 | }; 1083 | name = Debug; 1084 | }; 1085 | 7CD99CF41D901F0300668467 /* Release */ = { 1086 | isa = XCBuildConfiguration; 1087 | buildSettings = { 1088 | DEVELOPMENT_TEAM = ""; 1089 | INFOPLIST_FILE = Tests/Info.plist; 1090 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1091 | PRODUCT_BUNDLE_IDENTIFIER = io.github.khoiln.SwiftlyTests; 1092 | PRODUCT_NAME = "$(TARGET_NAME)"; 1093 | SWIFT_VERSION = 3.0; 1094 | }; 1095 | name = Release; 1096 | }; 1097 | /* End XCBuildConfiguration section */ 1098 | 1099 | /* Begin XCConfigurationList section */ 1100 | 7C135F671D99637800994840 /* Build configuration list for PBXNativeTarget "SwiftlyExt tvOS Tests" */ = { 1101 | isa = XCConfigurationList; 1102 | buildConfigurations = ( 1103 | 7C135F681D99637800994840 /* Debug */, 1104 | 7C135F691D99637800994840 /* Release */, 1105 | ); 1106 | defaultConfigurationIsVisible = 0; 1107 | defaultConfigurationName = Release; 1108 | }; 1109 | 7C135F761D9964A000994840 /* Build configuration list for PBXNativeTarget "SwiftlyExt macOS" */ = { 1110 | isa = XCConfigurationList; 1111 | buildConfigurations = ( 1112 | 7C135F771D9964A000994840 /* Debug */, 1113 | 7C135F781D9964A000994840 /* Release */, 1114 | ); 1115 | defaultConfigurationIsVisible = 0; 1116 | defaultConfigurationName = Release; 1117 | }; 1118 | 7C135F981D99660E00994840 /* Build configuration list for PBXNativeTarget "SwiftlyExt macOS Tests" */ = { 1119 | isa = XCConfigurationList; 1120 | buildConfigurations = ( 1121 | 7C135F991D99660E00994840 /* Debug */, 1122 | 7C135F9A1D99660E00994840 /* Release */, 1123 | ); 1124 | defaultConfigurationIsVisible = 0; 1125 | defaultConfigurationName = Release; 1126 | }; 1127 | 7CB10D971D99613C00731EE9 /* Build configuration list for PBXNativeTarget "SwiftlyExt watchOS" */ = { 1128 | isa = XCConfigurationList; 1129 | buildConfigurations = ( 1130 | 7CB10D981D99613C00731EE9 /* Debug */, 1131 | 7CB10D991D99613C00731EE9 /* Release */, 1132 | ); 1133 | defaultConfigurationIsVisible = 0; 1134 | defaultConfigurationName = Release; 1135 | }; 1136 | 7CB10DA81D99621700731EE9 /* Build configuration list for PBXNativeTarget "SwiftlyExt tvOS" */ = { 1137 | isa = XCConfigurationList; 1138 | buildConfigurations = ( 1139 | 7CB10DA91D99621700731EE9 /* Debug */, 1140 | 7CB10DAA1D99621700731EE9 /* Release */, 1141 | ); 1142 | defaultConfigurationIsVisible = 0; 1143 | defaultConfigurationName = Release; 1144 | }; 1145 | 7CD99CCF1D9002E100668467 /* Build configuration list for PBXProject "SwiftlyExt" */ = { 1146 | isa = XCConfigurationList; 1147 | buildConfigurations = ( 1148 | 7CD99CDB1D9002E100668467 /* Debug */, 1149 | 7CD99CDC1D9002E100668467 /* Release */, 1150 | ); 1151 | defaultConfigurationIsVisible = 0; 1152 | defaultConfigurationName = Release; 1153 | }; 1154 | 7CD99CDD1D9002E100668467 /* Build configuration list for PBXNativeTarget "SwiftlyExt iOS" */ = { 1155 | isa = XCConfigurationList; 1156 | buildConfigurations = ( 1157 | 7CD99CDE1D9002E100668467 /* Debug */, 1158 | 7CD99CDF1D9002E100668467 /* Release */, 1159 | ); 1160 | defaultConfigurationIsVisible = 0; 1161 | defaultConfigurationName = Release; 1162 | }; 1163 | 7CD99CF21D901F0300668467 /* Build configuration list for PBXNativeTarget "SwiftlyExt iOS Tests" */ = { 1164 | isa = XCConfigurationList; 1165 | buildConfigurations = ( 1166 | 7CD99CF31D901F0300668467 /* Debug */, 1167 | 7CD99CF41D901F0300668467 /* Release */, 1168 | ); 1169 | defaultConfigurationIsVisible = 0; 1170 | defaultConfigurationName = Release; 1171 | }; 1172 | /* End XCConfigurationList section */ 1173 | }; 1174 | rootObject = 7CD99CCC1D9002E100668467 /* Project object */; 1175 | } 1176 | -------------------------------------------------------------------------------- /SwiftlyExt.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftlyExt.xcodeproj/xcshareddata/xcschemes/SwiftlyExt iOS.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 | 65 | 66 | 72 | 73 | 74 | 75 | 79 | 80 | 81 | 82 | 83 | 84 | 90 | 91 | 97 | 98 | 99 | 100 | 102 | 103 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /SwiftlyExt.xcodeproj/xcshareddata/xcschemes/SwiftlyExt macOS.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 | 65 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 84 | 90 | 91 | 92 | 93 | 95 | 96 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /SwiftlyExt.xcodeproj/xcshareddata/xcschemes/SwiftlyExt tvOS.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 | 65 | 66 | 72 | 73 | 74 | 75 | 79 | 80 | 81 | 82 | 83 | 84 | 90 | 91 | 97 | 98 | 99 | 100 | 102 | 103 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /SwiftlyExt.xcodeproj/xcshareddata/xcschemes/SwiftlyExt watchOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 46 | 47 | 53 | 54 | 55 | 56 | 57 | 58 | 64 | 65 | 71 | 72 | 73 | 74 | 76 | 77 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /SwiftlyExt.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Tests/ArrayTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArrayTests.swift 3 | // Swiftly 4 | // 5 | // Created by Khoi Lai on 26/09/2016. 6 | // Copyright © 2016 Khoi Lai. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import SwiftlyExt 11 | 12 | class ArrayTests: XCTestCase { 13 | 14 | 15 | var a = [Int]() 16 | 17 | override func setUp() { 18 | super.setUp() 19 | a = [1, 2,3, 4,5] 20 | } 21 | 22 | func testSlice() { 23 | XCTAssertEqual(a.slice(start: 0, end: 2), [1, 2]) 24 | XCTAssertEqual(a.slice(start: 0), [1, 2, 3, 4, 5]) 25 | XCTAssertEqual(a.slice(start: 3), [4, 5]) 26 | XCTAssertEqual(a.slice(start: 8), []) 27 | XCTAssertEqual(a.slice(start: 8, end: 10), []) 28 | XCTAssertEqual(a.slice(start: 1, end: 1), []) 29 | XCTAssertEqual(a.slice(start: 8, end: 2), []) 30 | XCTAssertEqual(a.slice(start: 3, end: 3), []) 31 | XCTAssertEqual(a.slice(start: 2, end: 5), [3, 4,5]) 32 | XCTAssertEqual(a.slice(start: 0, end: 9), [1, 2,3, 4,5]) 33 | 34 | } 35 | 36 | func testChunk() { 37 | XCTAssertEqual([Int]().chunk().count, 0, "chunk for empty array returns an empty array") 38 | XCTAssertEqual(a.chunk(size: 0).count, 0, "chunk into parts of 0 elements returns empty array") 39 | XCTAssertEqual(a.chunk(size: -1).count, 0, "chunk into parts of negative amount of elements returns an empty array") 40 | XCTAssertEqual(a.chunk().count, 0, "defaults to empty array (chunk size 0)") 41 | XCTAssert(a.chunk(size: 1) == [[1], [2], [3], [4], [5]], "chunk into parts of 1 elements returns original array") 42 | XCTAssert(a.chunk(size: 5) == [[1, 2, 3, 4, 5]], "chunk into parts of current array length elements returns the original array") 43 | XCTAssert(a.chunk(size: 7) == [[1, 2, 3, 4, 5]], "chunk into parts of more then current array length elements returns the original array") 44 | XCTAssert([10, 20, 30, 40, 50, 60, 70].chunk(size: 2) == [[10, 20], [30, 40], [50, 60], [70]], "chunk into parts of less then current array length elements") 45 | XCTAssert([10, 20, 30, 40, 50, 60, 70].chunk(size: 3) == [[10, 20, 30], [40, 50, 60], [70]], "chunk into parts of less then current array length elements") 46 | } 47 | 48 | func testDifference() { 49 | XCTAssertEqual(a.difference([1, 2,3]), [4, 5]) 50 | XCTAssertEqual(a.difference([Int]()), [1, 2,3, 4,5]) 51 | XCTAssertEqual(a.difference([1, 2,3, 4,5]), []) 52 | XCTAssertEqual(a.difference([1, 2,3, 4,5, 6,8]), []) 53 | } 54 | 55 | func testDifferenceBy() { 56 | XCTAssertEqual([3.1, 2.2, 1.3].differenceBy([4.4, 2.5], iteratee: floor), [3.1, 1.3]) 57 | } 58 | 59 | func testDifferenceWith() { 60 | XCTAssert([["x":1, "y":2], ["x":2, "y":1]].differenceWith([["x":1, "y":2]], comparator: compare) == [["x":2, "y":1]]) 61 | } 62 | 63 | func testConcat() { 64 | XCTAssertEqual(a.concat(values: 6, 7,8), [1, 2,3, 4,5, 6,7, 8]) 65 | XCTAssertEqual(a.concat(arrays: []), [1, 2,3, 4,5]) 66 | XCTAssertEqual(a.concat(arrays: [1, 2], [3, 4], [0], []), [1, 2,3, 4,5, 1,2, 3,4, 0]) 67 | } 68 | 69 | func testDrop() { 70 | XCTAssertEqual(a.drop(), [2, 3,4, 5], "Should drop first element") 71 | XCTAssertEqual(a.drop(2), [3, 4,5], "Should drop more than 1 element") 72 | XCTAssertEqual(a.drop(9), [], "Should drop if n > array length") 73 | XCTAssertEqual(a.drop(0), [1, 2,3, 4,5], "Should return array if n == 0") 74 | XCTAssertEqual(a.drop(-1), [1, 2,3, 4,5], "Should return array if n < 0") 75 | } 76 | 77 | func testDropRight() { 78 | XCTAssertEqual(a.dropRight(), [1, 2,3, 4], "Should drop last element") 79 | XCTAssertEqual(a.dropRight(2), [1, 2,3], "Should drop more than 1 element") 80 | XCTAssertEqual(a.dropRight(9), [], "Should drop if n > array count") 81 | XCTAssertEqual(a.dropRight(0), [1, 2,3, 4,5], "Should return array if n == 0") 82 | XCTAssertEqual(a.dropRight(-1), [1, 2,3, 4,5], "Should return array if n < 0") 83 | } 84 | 85 | func testDropWhile() { 86 | XCTAssertEqual(a.dropWhile { $0 < 3 }, [3, 4,5], "Should drop elements") 87 | XCTAssertEqual(a.dropWhile { _ in return false }, [1, 2,3, 4,5]) 88 | XCTAssertEqual(a.dropWhile { _ in return true }, []) 89 | } 90 | 91 | func testDropRightWhile() { 92 | XCTAssertEqual(a.dropRightWhile { $0 > 3 }, [1, 2, 3], "Should drop elements") 93 | XCTAssertEqual(a.dropRightWhile { _ in return false }, [1, 2,3, 4,5]) 94 | XCTAssertEqual(a.dropRightWhile { _ in return true }, []) 95 | } 96 | 97 | func testFindIndex() { 98 | XCTAssertEqual(a.findIndex {$0 % 2 == 0}, 1, "Should find first index") 99 | XCTAssertEqual([1, 2,2].findIndex {$0 % 2 == 0}, 1, "Should return the first index") 100 | XCTAssertNil(a.findIndex {$0 > 5}, "Should return nil if not found") 101 | } 102 | 103 | func testFindLastIndex() { 104 | XCTAssertEqual(a.findLastIndex {$0 % 2 == 0}, 3, "Should find last index") 105 | XCTAssertEqual([1, 2,2].findLastIndex {$0 % 2 == 0}, 2, "Should return the last index") 106 | XCTAssertNil(a.findLastIndex {$0 > 5}, "Should return nil if not found") 107 | } 108 | 109 | func testIntersection() { 110 | XCTAssertEqual([2, 1].intersection([4, 2], [1, 2]), [2], "Should return the array of common elements") 111 | XCTAssertEqual([2, 7,5, 1].intersection([5, 9,4, 2], [5, 10, 1,2]), [2, 5], "Should return the array of common elements") 112 | XCTAssertEqual(a.intersection([1, 2,3, 4,5]), [1, 2,3, 4,5], "Should return the array") 113 | XCTAssertEqual(a.intersection([Int]()), [], "Should return blank array") 114 | } 115 | 116 | func testIntersectionBy() { 117 | XCTAssertEqual([2.1, 1.2].intersectionBy([4.3, 2.4], iteratee: floor), [2.1], "Should intersect with one array") 118 | XCTAssertEqual([2.1, 1.2].intersectionBy([4.5, 3.4, 2.3], [2.8, 3.2, 4.7], iteratee: floor), [2.1], "Should intersect with more than 1 array") 119 | } 120 | 121 | func testIntersectionWith() { 122 | let objects1 = [["x":1, "y":2], ["x":2, "y":1]] 123 | let objects2 = [["x":1, "y":1], ["x":1, "y":2]] 124 | XCTAssert(objects1.intersectionWith(objects2, comparator: compare) == [["x":1, "y":2]]) 125 | } 126 | 127 | func testEvery() { 128 | XCTAssert([true, true, true].every { $0 == true }, "every true values") 129 | XCTAssertFalse([true, false, true].every { $0 == true }, "one false value") 130 | 131 | var count = 0 132 | XCTAssert([0, 10, 28].every { 133 | count += 1 134 | return $0 % 2 == 0 135 | }, "Even number") 136 | 137 | XCTAssert(count == 3, "Runtime \(count) should be 3") 138 | 139 | count = 0 140 | 141 | XCTAssertFalse([0, 11, 28, 10].every { 142 | count += 1 143 | return $0 % 2 == 0 144 | }, "An odd number") 145 | 146 | XCTAssert(count == 2, "Runtime \(count) should be 1") 147 | } 148 | 149 | func testSome() { 150 | XCTAssert([false, true, false].some { $0 == true }, "one true value") 151 | XCTAssertFalse([false, false, false].some { $0 == true }, "all false value") 152 | 153 | 154 | var count = 0 155 | 156 | XCTAssert([11, 23, 25, 26].some { 157 | count += 1 158 | return $0 % 2 == 0 }, "Even number at the end") 159 | XCTAssert(count == 4, "Runtime \(count) should be 4") 160 | 161 | count = 0 162 | XCTAssert([0, 11, 28, 10].some { 163 | count += 1 164 | return $0 % 2 == 0 165 | }, "An odd number") 166 | XCTAssert(count == 1, "Runtime \(count) should be 1") 167 | } 168 | 169 | func testXor() { 170 | let objects1 = [["x":1, "y":2], ["x":2, "y":1]] 171 | let objects2 = [["x":1, "y":1], ["x":1, "y":2]] 172 | 173 | 174 | 175 | XCTAssert([Int].xor(arrays: [2, 1], [4, 2]) == [1, 4]) 176 | XCTAssert([Int].xor(arrays: []) == []) 177 | XCTAssert([Int].xor(arrays: [1, 2,3], [4, 5,6]) == [1, 2,3, 4,5, 6]) 178 | XCTAssert([Double].xorBy(arrays: [2.1, 1.2], [4.3, 2.4], iteratee: floor) == [1.2, 4.3]) 179 | XCTAssert([Dictionary].xorWith(arrays: objects1, objects2, comparator: compare) == [["x":2, "y":1], ["x":1, "y":1]]) 180 | } 181 | 182 | func testWithout() { 183 | XCTAssert([1, 2, 1, 0, 3, 1, 4].without(0, 1) == [2, 3,4]) 184 | 185 | } 186 | 187 | func testShuffle() { 188 | XCTAssert([1].shuffled() == [1], "Behave correctly with 1 element") 189 | 190 | let oneToTwentys = Array(1...20) 191 | let shuffled = oneToTwentys.shuffled() 192 | XCTAssert(shuffled != oneToTwentys, "does change the order") // Chance of false negative: 1 in ~2.4*10^18 193 | XCTAssert(oneToTwentys == shuffled.sorted(), "Same number of elements and value after sorted") 194 | } 195 | 196 | func testRandomAndSample() { 197 | let a = [0, 1] 198 | (0...100).forEach { _ in 199 | let rand = a.random() 200 | let sample = a.sample() 201 | XCTAssert(a.some { $0 == rand }, "Must be either 0 or 1") 202 | XCTAssert(a.some { $0 == sample }, "Same goes for sample") 203 | } 204 | 205 | 206 | } 207 | 208 | func testsampleSize() { 209 | let a = [0,1,2,3,4,5] 210 | 211 | XCTAssert(a.sampleSize() == [], "Default must be zero") 212 | XCTAssert(a.sampleSize(0) == [], "passing 0 should works too") 213 | XCTAssert(a.sampleSize(-10) == [], "Negative size works") 214 | 215 | (0...10).forEach{ _ in 216 | let numberOfElement = Swiftly.random(lower: 0, upper: a.count - 1) 217 | XCTAssert(a.sampleSize(numberOfElement).every{ aSample in 218 | return a.some {$0 == aSample} 219 | }, "Taking samples should work") 220 | } 221 | 222 | } 223 | 224 | func testGroupBy(){ 225 | let a = [1,2,3,4,5] 226 | let test = a.groupBy { $0 % 2 == 0 ? "even" : "odd"} 227 | XCTAssertEqual(test["even"]!, [2,4], "SHould have even group") 228 | XCTAssertEqual(test["odd"]!, [1,3,5], "SHould have odd group") 229 | 230 | } 231 | 232 | func testReject(){ 233 | XCTAssertEqual([1,2,3,4,5].reject{$0 % 2 == 0}, [1,3,5], "should return odd values") 234 | XCTAssertEqual([1,2,3,4,5].reject{$0 % 2 != 0}, [2,4], "should return even values") 235 | 236 | } 237 | } 238 | 239 | 240 | fileprivate func compare(obj1: [String:Int], obj2: [String:Int]) -> Bool { 241 | return obj1["x"] == obj2["x"] && obj1["y"] == obj2["y"] 242 | } 243 | 244 | fileprivate func ==(lhs: [[String: Int]], rhs: [[String: Int]]) -> Bool { 245 | guard lhs.count == rhs.count else { return false } 246 | var currentIdx = 0 247 | while currentIdx < lhs.count { 248 | if !compare(obj1: lhs[currentIdx], obj2: rhs[currentIdx]) { 249 | return false 250 | } 251 | currentIdx += 1 252 | } 253 | return true 254 | } 255 | 256 | fileprivate func ==(lhs: [[Int]], rhs: [[Int]]) -> Bool { 257 | guard lhs.count == rhs.count else { return false } 258 | var currentIdx = 0 259 | while currentIdx < lhs.count { 260 | if lhs[currentIdx] != rhs[currentIdx] { 261 | return false 262 | } 263 | currentIdx += 1 264 | } 265 | return true 266 | } 267 | -------------------------------------------------------------------------------- /Tests/CGFloatTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGFloatTests.swift 3 | // SwiftlyExt 4 | // 5 | // Created by Khoi Lai on 12/30/16. 6 | // Copyright © 2016 Khoi Lai. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class CGFloatTests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | super.tearDown() 21 | } 22 | 23 | func testDegreeToRadians() { 24 | XCTAssert(CGFloat(180).degreesToRadians() == CGFloat.pi) 25 | } 26 | 27 | func testRadiansToDegrees() { 28 | XCTAssert(CGFloat(CGFloat.pi).radiansToDegrees() == 180) 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Tests/CGPointTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGPointTests.swift 3 | // SwiftlyExt 4 | // 5 | // Created by Khoi Lai on 12/30/16. 6 | // Copyright © 2016 Khoi Lai. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class CGPointTests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | super.tearDown() 21 | } 22 | 23 | func testDistance() { 24 | XCTAssert(CGPoint(x: 0, y: 0).distance(to: CGPoint(x: 0, y: 0)) == 0) 25 | XCTAssert(CGPoint(x: 4, y: 4).distance(to: CGPoint(x: 4, y: 4)) == 0) 26 | XCTAssert(CGPoint(x: 2, y: 8).distance(to: CGPoint(x: 5, y: 4)) == 5) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Tests/DateTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DateTests.swift 3 | // Swiftly 4 | // 5 | // Created by Khoi Lai on 08/10/2016. 6 | // Copyright © 2016 Khoi Lai. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class DateTests: XCTestCase { 12 | 13 | 14 | let dateFormatString = "dd/MM/yyyy HH:mm:ss" 15 | 16 | let currentDate = Date() 17 | 18 | var sameDate: Date? 19 | var futureDate: Date? 20 | var pastDate: Date? 21 | 22 | 23 | let calendar = Calendar.current 24 | 25 | override func setUp() { 26 | super.setUp() 27 | sameDate = calendar.date(byAdding: .day, value: 0, to: currentDate) 28 | futureDate = calendar.date(byAdding: .day, value: 1, to: currentDate) 29 | pastDate = calendar.date(byAdding: .day, value: -1, to: currentDate) 30 | } 31 | 32 | func testBefore() { 33 | XCTAssert(currentDate.isBefore(futureDate!)) 34 | XCTAssertFalse(currentDate.isBefore(pastDate!)) 35 | XCTAssertFalse(currentDate.isBefore(sameDate!)) 36 | } 37 | 38 | func testAfter() { 39 | XCTAssert(currentDate.isAfter(pastDate!)) 40 | XCTAssertFalse(currentDate.isAfter(futureDate!)) 41 | XCTAssertFalse(currentDate.isAfter(sameDate!)) 42 | } 43 | 44 | func testCustomInit() { 45 | XCTAssertNotNil(Date(from: "01/01/1970 00:34:22", format: dateFormatString), "Should return a valid date") 46 | XCTAssertNil(Date(from: "01/34/1970 00:34:22", format: dateFormatString), "Should return a invalid date") 47 | } 48 | 49 | func testCustomerProperty() { 50 | let aDate = Date(from: "01/01/1970 00:34:22", format: dateFormatString) 51 | XCTAssertEqual(aDate?.era, 1) 52 | XCTAssertEqual(aDate?.year, 1970) 53 | XCTAssertEqual(aDate?.month, 1) 54 | XCTAssertEqual(aDate?.day, 1) 55 | XCTAssertEqual(aDate?.hour, 00) 56 | XCTAssertEqual(aDate?.minute, 34) 57 | XCTAssertEqual(aDate?.second, 22) 58 | XCTAssertEqual(aDate?.weekday, 5) 59 | } 60 | 61 | func testStringFormat() { 62 | let aDate = Date(from: "30/12/2016 14:34:22", format: dateFormatString) 63 | XCTAssertEqual(aDate?.toString(format: dateFormatString), "30/12/2016 14:34:22") 64 | XCTAssertEqual(aDate?.toString(format: "MMM yyyy"), "Dec 2016") 65 | } 66 | 67 | func testAddingDate() { 68 | let aDate = Date(from: "30/12/2016 14:34:22", format: dateFormatString) 69 | XCTAssertEqual(aDate?.date(byAddingYears: 1)?.year, 2017) 70 | XCTAssertEqual(aDate?.date(byAddingYears: -1)?.year, 2015) 71 | 72 | XCTAssertEqual(aDate?.date(byAddingMonths: 1)?.year, 2017, "Should switch to next year if current month is 12") 73 | XCTAssertEqual(aDate?.date(byAddingMonths: 1)?.month, 1) 74 | XCTAssertEqual(aDate?.date(byAddingMonths: -1)?.month, 11) 75 | 76 | XCTAssertEqual(aDate?.date(byAddingDays: 1)?.day, 31) 77 | XCTAssertEqual(aDate?.date(byAddingDays: 2)?.day, 1) 78 | XCTAssertEqual(aDate?.date(byAddingDays: -1)?.day, 29) 79 | 80 | XCTAssertEqual(aDate?.date(byAddingHours: 1)?.hour, 15) 81 | XCTAssertEqual(aDate?.date(byAddingHours: -1)?.hour, 13) 82 | XCTAssertEqual(aDate?.date(byAddingHours: 10)?.hour, 0) 83 | XCTAssertEqual(aDate?.date(byAddingHours: 10)?.day, 31) 84 | 85 | XCTAssertEqual(aDate?.date(byAddingMinutes: 1)?.minute, 35) 86 | XCTAssertEqual(aDate?.date(byAddingMinutes: -1)?.minute, 33) 87 | XCTAssertEqual(aDate?.date(byAddingMinutes: 26)?.hour, 15) 88 | XCTAssertEqual(aDate?.date(byAddingMinutes: 26)?.minute, 0) 89 | 90 | XCTAssertEqual(aDate?.date(byAddingSeconds: 1)?.second, 23) 91 | XCTAssertEqual(aDate?.date(byAddingSeconds: -1)?.second, 21) 92 | XCTAssertEqual(aDate?.date(byAddingSeconds: 38)?.second, 0) 93 | XCTAssertEqual(aDate?.date(byAddingSeconds: 38)?.minute, 35) 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Tests/DictionaryTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DictionaryTests.swift 3 | // SwiftlyExt 4 | // 5 | // Created by Khoi Lai on 12/30/16. 6 | // Copyright © 2016 Khoi Lai. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class DictionaryTests: XCTestCase { 12 | 13 | 14 | typealias JSONDict = [String: Any] 15 | 16 | let jsonString = "{\"list\":[1234,45.234],\"number\":5443.1,\"name\":\"Swiftly\",\"object\":{\"sub_number\":877.2323,\"sub_name\":\"SwiftlySub\"},\"bool\":true}" 17 | 18 | override func setUp() { 19 | super.setUp() 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | override func tearDown() { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | super.tearDown() 26 | } 27 | 28 | 29 | func testInitFromJSON() { 30 | let dict = JSONDict(fromJsonString: jsonString)! 31 | XCTAssert((dict["number"] as! Double) == 5443.1, "number prop") 32 | XCTAssert((dict["name"] as! String) == "Swiftly", "string prop") 33 | 34 | 35 | XCTAssert((dict["list"] as! [Double])[0] == 1234, "array list prop int") 36 | XCTAssert((dict["list"] as! [Double])[1] == 45.234, "array list prop double") 37 | XCTAssert((dict["object"] as! JSONDict)["sub_number"] as! Double == 877.2323, "subobject number") 38 | XCTAssert((dict["object"] as! JSONDict)["sub_name"] as! String == "SwiftlySub", "subobject string") 39 | XCTAssert(dict["bool"] as! Bool, "bool prop") 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tests/IntTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IntTests.swift 3 | // IntTests 4 | // 5 | // Created by Khoi Lai on 9/19/16. 6 | // Copyright © 2016 Khoi Lai. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import SwiftlyExt 11 | 12 | class IntTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | 17 | 1.upTo(3) { print($0) } 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | } 20 | 21 | override func tearDown() { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | super.tearDown() 24 | } 25 | 26 | func testTimes() { 27 | var count = 0 28 | 29 | 5.times { _ in 30 | count += 1 31 | } 32 | XCTAssertEqual(count, 5) 33 | 34 | var zero = 0 35 | 0.times { _ in 36 | zero += 1 37 | } 38 | XCTAssertEqual(zero, 0) 39 | 40 | 41 | (-9).times { _ in 42 | zero += 1 43 | } 44 | XCTAssertEqual(zero, 0) 45 | 46 | } 47 | 48 | func testTimesWithIndex() { 49 | var indexes = [Int]() 50 | 51 | 5.times { (idx) in 52 | indexes.append(idx) 53 | } 54 | 55 | XCTAssertEqual(indexes, [0, 1,2, 3,4]) 56 | } 57 | 58 | func testOddAndEven() { 59 | XCTAssert(4.isEven()) 60 | XCTAssert(0.isEven()) 61 | XCTAssertFalse(1.isEven()) 62 | XCTAssertFalse(3.isEven()) 63 | 64 | XCTAssertFalse(4.isOdd()) 65 | XCTAssertFalse(0.isOdd()) 66 | XCTAssert(1.isOdd()) 67 | XCTAssert(3.isOdd()) 68 | } 69 | 70 | func testUpTo() { 71 | var count = 0 72 | 0.upTo(5) { _ in 73 | count += 1 74 | } 75 | XCTAssertEqual(count, 6) 76 | 77 | var zero = 0 78 | 0.upTo(-1) { _ in 79 | zero += 1 80 | } 81 | XCTAssertEqual(zero, 0) 82 | 83 | 12.upTo(-1) { _ in 84 | zero += 1 85 | } 86 | XCTAssertEqual(zero, 0) 87 | 88 | var indexes = [Int]() 89 | 90 | 0.upTo(5) { (idx) in 91 | indexes.append(idx) 92 | } 93 | 94 | XCTAssertEqual(indexes, [0, 1,2, 3,4, 5]) 95 | } 96 | 97 | 98 | func testDownTo() { 99 | var count = 0 100 | 5.downTo(0) { _ in 101 | count += 1 102 | } 103 | XCTAssertEqual(count, 6) 104 | 105 | var zero = 0 106 | (-1).downTo(0) { _ in 107 | zero += 1 108 | } 109 | XCTAssertEqual(zero, 0) 110 | 111 | (-1).downTo(12) { _ in 112 | zero += 1 113 | } 114 | XCTAssertEqual(zero, 0) 115 | 116 | var indexes = [Int]() 117 | 5.downTo(0) { (idx) in 118 | indexes.append(idx) 119 | } 120 | XCTAssertEqual(indexes, [5, 4,3, 2,1, 0]) 121 | } 122 | 123 | 124 | 125 | func testDigits() { 126 | XCTAssertEqual(1234.digits(), [1, 2,3, 4]) 127 | XCTAssertEqual(01234.digits(), [1, 2,3, 4]) 128 | } 129 | 130 | func testIsIn() { 131 | XCTAssert(0.isIn(range: 0..<200)) 132 | XCTAssertFalse(200.isIn(range: 0..<200)) 133 | XCTAssertFalse((-1).isIn(range: 0..<200)) 134 | 135 | XCTAssert(0.isIn(range: 0...200)) 136 | XCTAssert(200.isIn(range: 0...200)) 137 | XCTAssertFalse((-1).isIn(range: 0...200)) 138 | XCTAssertFalse(201.isIn(range: 0...200)) 139 | } 140 | 141 | func testFactorial() { 142 | XCTAssertEqual(5.factorial(), 120) 143 | XCTAssertEqual(10.factorial(), 3628800) 144 | XCTAssertEqual(0.factorial(), 1) 145 | 146 | 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Tests/StringTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StringTests.swift 3 | // SwiftlyExt 4 | // 5 | // Created by Khoi Lai on 10/10/2016. 6 | // Copyright © 2016 Khoi Lai. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class StringTests: XCTestCase { 12 | 13 | let dateFormatString = "dd/MM/yyyy HH:mm:ss" 14 | 15 | override func setUp() { 16 | super.setUp() 17 | } 18 | 19 | func testInitials(){ 20 | XCTAssert("John Doe".initials == "JD") 21 | XCTAssert("John With Middle Name Doe".initials == "JWMND") 22 | } 23 | 24 | func testIsEmail(){ 25 | XCTAssertTrue("swift@swiftly.com".isEmail) 26 | XCTAssertFalse("swift@@swiftly.com".isEmail) 27 | } 28 | 29 | func testCount(){ 30 | XCTAssert("Swiftlylylyly ly".count("as") == 0) 31 | XCTAssert("Swiftlylylyly ly".count("ly") == 5) 32 | } 33 | 34 | func testBetween(){ 35 | XCTAssert("foo".between("", "") == "foo") 36 | XCTAssert("foo".between("", "") == "foo") 37 | XCTAssert("foo".between("", "") == nil) 38 | XCTAssert("Some strings } are very {weird}, dont you think?".between("{", "}") == "weird") 39 | XCTAssert("".between("", "") == nil) 40 | XCTAssert("foo".between("", "") == nil) 41 | } 42 | 43 | func testDate() { 44 | guard let date = "01/01/1970 00:34:22".date(format: dateFormatString) else { 45 | XCTFail("Can't parse a valid date") 46 | return 47 | } 48 | XCTAssertNil("13/14/1780 14:38:88".date(format: dateFormatString), "Should return nil for invalid date") 49 | XCTAssertEqual(date.year, 1970) 50 | XCTAssertEqual(date.month, 1) 51 | XCTAssertEqual(date.day, 1) 52 | XCTAssertEqual(date.hour, 0) 53 | XCTAssertEqual(date.minute, 34) 54 | XCTAssertEqual(date.second, 22) 55 | XCTAssertEqual(date.nanosecond, 0) 56 | } 57 | 58 | func testBase64Encode() { 59 | XCTAssert("a".base64Encoded == "YQ==", "2 padding chars") 60 | XCTAssert("aa".base64Encoded == "YWE=", "1 padding char") 61 | XCTAssert("aaa".base64Encoded == "YWFh", "0 padding char") 62 | XCTAssert("foo\0".base64Encoded == "Zm9vAA==", "U+0000") 63 | XCTAssert("foo\0\0".base64Encoded == "Zm9vAAA=", "0 padding char") 64 | XCTAssert("https://github.com/Swiftly".base64Encoded == "aHR0cHM6Ly9naXRodWIuY29tL1N3aWZ0bHk=") 65 | } 66 | 67 | func testBase64Decode() { 68 | XCTAssert("aHR0cHM6Ly9naXRodWIuY29tL1N3aWZ0bHk=".base64Decoded == "https://github.com/Swiftly") 69 | } 70 | 71 | func testReversed() { 72 | XCTAssert("Swiftly".reversed == "yltfiwS") 73 | XCTAssert("abcdef".reversed == "fedcba") 74 | XCTAssert("a".reversed == "a") 75 | XCTAssert("".reversed == "") 76 | } 77 | 78 | func testTrimmed() { 79 | XCTAssert("\r\n\n\n Swiftly \r\n\n".trimmed == "Swiftly") 80 | XCTAssert("\n\n\n Swiftly ".trimmed.reversed == "yltfiwS") 81 | } 82 | 83 | func testURLEncoded() { 84 | XCTAssert("abcd".urlEncoded == "abcd", "String must be unchanged") 85 | XCTAssert("\n\t".urlEncoded == "%0A%09") 86 | XCTAssert("Swiftly\t\nString\nTest".urlEncoded == "Swiftly%09%0AString%0ATest") 87 | } 88 | 89 | func testURLDecoded() { 90 | XCTAssert("https%3A%2F%2Fgithub.com%2Fkhoiln%2FSwiftlyEXT".urlDecoded == "https://github.com/khoiln/SwiftlyEXT") 91 | } 92 | 93 | func testHasNumbers(){ 94 | XCTAssertTrue("hoho2".hasNumbers) 95 | XCTAssertFalse("swiftly".hasNumbers) 96 | } 97 | 98 | func testHasLetters(){ 99 | XCTAssertFalse("12389723".hasLetters) 100 | XCTAssertTrue("3749347a98423".hasLetters) 101 | XCTAssertFalse("!@#$%^&*()🐶".hasLetters) 102 | } 103 | 104 | func testIsAlpha(){ 105 | XCTAssertFalse("fdafaf3".isAlpha) 106 | XCTAssert("afaf".isAlpha) 107 | XCTAssertFalse("dfda@#(*&@#dfd".isAlpha) 108 | } 109 | 110 | func testIsAlphaNumeric() { 111 | XCTAssert("afaf35353afaf".isAlphaNumeric) 112 | XCTAssert("FFFF99fff".isAlphaNumeric) 113 | XCTAssert("99".isAlphaNumeric) 114 | XCTAssert("afff".isAlphaNumeric) 115 | XCTAssertFalse("-33".isAlphaNumeric) 116 | XCTAssertFalse("aaff..".isAlphaNumeric) 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /Tests/SwiftlyTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftlyTests.swift 3 | // SwiftlyExt 4 | // 5 | // Created by Khoi Lai on 1/30/17. 6 | // Copyright © 2017 Khoi Lai. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import SwiftlyExt 11 | 12 | class SwiftlyTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testRandom(){ 25 | (0...100).forEach { _ in 26 | let random = Swiftly.random(lower: 0, upper: 1) 27 | XCTAssert( [0,1].some{ $0 == random } , "Should return number 0 or 1") 28 | } 29 | 30 | XCTAssert(Swiftly.random(lower: 2, upper: 2) == 2, "Return the same number if lower == upper") 31 | } 32 | 33 | 34 | } 35 | --------------------------------------------------------------------------------