├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── ExSwift.podspec ├── ExSwift.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── ExSwift-Mac.xcscheme │ └── ExSwift-iOS.xcscheme ├── ExSwift.xcworkspace └── contents.xcworkspacedata ├── ExSwift ├── Array.swift ├── Bool.swift ├── Character.swift ├── Dictionary.swift ├── Double.swift ├── ExSwift.h ├── ExSwift.swift ├── Float.swift ├── Info.plist ├── Int.swift ├── NSArray.swift ├── NSDate.swift ├── Range.swift ├── Sequence.swift └── String.swift ├── ExSwiftTests ├── ArrayExtensionsTests.swift ├── CharacterExtensionsTests.swift ├── DictionaryExtensionsTests.swift ├── DoubleExtensionsTests.swift ├── ExSwiftBoolTests.swift ├── ExSwiftTests.swift ├── FloatExtensionsTests.swift ├── Info.plist ├── IntExtensionsTests.swift ├── NSArrayExtensionsTests.swift ├── NSDateExtensionsTests.swift ├── RangeExtensionsTests.swift ├── SequenceExtensionsTests.swift └── StringExtensionsTests.swift ├── LICENSE ├── Podfile ├── Podfile.lock └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | */build/* 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | profile 14 | *.moved-aside 15 | DerivedData 16 | .idea/ 17 | *.hmap 18 | *.xccheckout 19 | Build/* 20 | 21 | #CocoaPods 22 | Pods 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: beta-xcode6.3 3 | 4 | xcode_workspace: ExSwift.xcworkspace 5 | xcode_scheme: 6 | - ExSwift-iOS 7 | - ExSwift-Mac 8 | xcode_sdk: 9 | - iphonesimulator8.3 10 | - macosx10.10 11 | 12 | matrix: 13 | exclude: 14 | - xcode_scheme: ExSwift-iOS 15 | xcode_sdk: macosx10.10 16 | - xcode_scheme: ExSwift-Mac 17 | xcode_sdk: iphonesimulator8.3 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [Unreleased](https://github.com/pNre/ExSwift/tree/HEAD) 4 | 5 | [Full Changelog](https://github.com/pNre/ExSwift/compare/0.1.9...HEAD) 6 | 7 | **Closed issues:** 8 | 9 | - NSDate addUnit stuff not working in ios7 [\#97](https://github.com/pNre/ExSwift/issues/97) 10 | 11 | - weak support [\#96](https://github.com/pNre/ExSwift/issues/96) 12 | 13 | - @synchronized support [\#95](https://github.com/pNre/ExSwift/issues/95) 14 | 15 | - string.toDouble\(\) should accept "1.23e4" [\#94](https://github.com/pNre/ExSwift/issues/94) 16 | 17 | - Compile fix for Swift 1.2 [\#90](https://github.com/pNre/ExSwift/issues/90) 18 | 19 | - Swift-1.2 branch causing Segmentation fault: 11 [\#81](https://github.com/pNre/ExSwift/issues/81) 20 | 21 | - Support for Swift 1.2 [\#80](https://github.com/pNre/ExSwift/issues/80) 22 | 23 | - Still breaks range literals [\#71](https://github.com/pNre/ExSwift/issues/71) 24 | 25 | - flatMap [\#62](https://github.com/pNre/ExSwift/issues/62) 26 | 27 | - Nil filter method on array [\#59](https://github.com/pNre/ExSwift/issues/59) 28 | 29 | - don't use array extension function [\#54](https://github.com/pNre/ExSwift/issues/54) 30 | 31 | - Documentation small issue [\#53](https://github.com/pNre/ExSwift/issues/53) 32 | 33 | - Spare the TakeSequence and TakeWhileSequence structs [\#52](https://github.com/pNre/ExSwift/issues/52) 34 | 35 | - No one is merging in changes [\#49](https://github.com/pNre/ExSwift/issues/49) 36 | 37 | - Swift Compile Error on Xcode 6.1 [\#38](https://github.com/pNre/ExSwift/issues/38) 38 | 39 | - ExSwift breaks range subscripting [\#32](https://github.com/pNre/ExSwift/issues/32) 40 | 41 | - skipWhile [\#31](https://github.com/pNre/ExSwift/issues/31) 42 | 43 | **Merged pull requests:** 44 | 45 | - Enhance Carthage Support [\#103](https://github.com/pNre/ExSwift/pull/103) ([nebhale](https://github.com/nebhale)) 46 | 47 | - Remove Deprecation Warnings [\#102](https://github.com/pNre/ExSwift/pull/102) ([nebhale](https://github.com/nebhale)) 48 | 49 | - Fix compatibility issue NSDate add [\#101](https://github.com/pNre/ExSwift/pull/101) ([PGLongo](https://github.com/PGLongo)) 50 | 51 | - Ex.cached for 1-arg functions. [\#93](https://github.com/pNre/ExSwift/pull/93) ([hiltonc](https://github.com/hiltonc)) 52 | 53 | - fixed for Xcode Version 6.3 beta 3 [\#89](https://github.com/pNre/ExSwift/pull/89) ([katopz](https://github.com/katopz)) 54 | 55 | - fix compiler error 'missing argument \#2' [\#88](https://github.com/pNre/ExSwift/pull/88) ([sebbean](https://github.com/sebbean)) 56 | 57 | - Format Number [\#86](https://github.com/pNre/ExSwift/pull/86) ([PGLongo](https://github.com/PGLongo)) 58 | 59 | - Fix compiler errors in second Xcode 6.3 beta \(6D532l\). [\#84](https://github.com/pNre/ExSwift/pull/84) ([JakobR](https://github.com/JakobR)) 60 | 61 | - Add Lisp's find method to Arrays. [\#83](https://github.com/pNre/ExSwift/pull/83) ([nickmshelley](https://github.com/nickmshelley)) 62 | 63 | - Add Bool extension [\#79](https://github.com/pNre/ExSwift/pull/79) ([davidman](https://github.com/davidman)) 64 | 65 | - Swift 1.2 \(Xcode 6.3\) support [\#78](https://github.com/pNre/ExSwift/pull/78) ([markusl](https://github.com/markusl)) 66 | 67 | - Made Framework and Unit Test iOS / OS X universal [\#76](https://github.com/pNre/ExSwift/pull/76) ([colemancda](https://github.com/colemancda)) 68 | 69 | - added method and tests [\#73](https://github.com/pNre/ExSwift/pull/73) ([michaeleisel](https://github.com/michaeleisel)) 70 | 71 | - added methods and tests [\#72](https://github.com/pNre/ExSwift/pull/72) ([michaeleisel](https://github.com/michaeleisel)) 72 | 73 | - added method and tests [\#70](https://github.com/pNre/ExSwift/pull/70) ([michaeleisel](https://github.com/michaeleisel)) 74 | 75 | - added method, tests, and whitespace changes [\#69](https://github.com/pNre/ExSwift/pull/69) ([michaeleisel](https://github.com/michaeleisel)) 76 | 77 | - Round to nearest [\#68](https://github.com/pNre/ExSwift/pull/68) ([michaeleisel](https://github.com/michaeleisel)) 78 | 79 | - added arithmetic methods [\#67](https://github.com/pNre/ExSwift/pull/67) ([michaeleisel](https://github.com/michaeleisel)) 80 | 81 | - added strideable methods [\#66](https://github.com/pNre/ExSwift/pull/66) ([michaeleisel](https://github.com/michaeleisel)) 82 | 83 | - removed unnecessary methods [\#65](https://github.com/pNre/ExSwift/pull/65) ([michaeleisel](https://github.com/michaeleisel)) 84 | 85 | - completely redid permutation generating [\#64](https://github.com/pNre/ExSwift/pull/64) ([michaeleisel](https://github.com/michaeleisel)) 86 | 87 | - Add shared schemes for installation by Carthage. [\#63](https://github.com/pNre/ExSwift/pull/63) ([yoichitgy](https://github.com/yoichitgy)) 88 | 89 | - Add getter and comparison to NSDate [\#61](https://github.com/pNre/ExSwift/pull/61) ([PGLongo](https://github.com/PGLongo)) 90 | 91 | - mapAccum for Array [\#60](https://github.com/pNre/ExSwift/pull/60) ([phatmann](https://github.com/phatmann)) 92 | 93 | - Added to\* methods to readme docs. [\#58](https://github.com/pNre/ExSwift/pull/58) ([mikeckennedy](https://github.com/mikeckennedy)) 94 | 95 | - Trimmed methods fail on string that contains only whitespace [\#57](https://github.com/pNre/ExSwift/pull/57) ([pizthewiz](https://github.com/pizthewiz)) 96 | 97 | - Add toNumeric \(e.g. toDouble\) conversions to string extensions [\#56](https://github.com/pNre/ExSwift/pull/56) ([mikeckennedy](https://github.com/mikeckennedy)) 98 | 99 | - Added overloaded ltrimmed and rtrimmed methods [\#55](https://github.com/pNre/ExSwift/pull/55) ([hhoangnl](https://github.com/hhoangnl)) 100 | 101 | - Update Dictionary.swift [\#51](https://github.com/pNre/ExSwift/pull/51) ([davidman](https://github.com/davidman)) 102 | 103 | - Added Charater extension [\#50](https://github.com/pNre/ExSwift/pull/50) ([cennydavidsson](https://github.com/cennydavidsson)) 104 | 105 | - Repeated permutations [\#48](https://github.com/pNre/ExSwift/pull/48) ([michaeleisel](https://github.com/michaeleisel)) 106 | 107 | - Added NSDate methods [\#47](https://github.com/pNre/ExSwift/pull/47) ([PGLongo](https://github.com/PGLongo)) 108 | 109 | - Repeated combinations [\#46](https://github.com/pNre/ExSwift/pull/46) ([michaeleisel](https://github.com/michaeleisel)) 110 | 111 | - Fill [\#45](https://github.com/pNre/ExSwift/pull/45) ([michaeleisel](https://github.com/michaeleisel)) 112 | 113 | - Transpose [\#44](https://github.com/pNre/ExSwift/pull/44) ([michaeleisel](https://github.com/michaeleisel)) 114 | 115 | - Permutations [\#43](https://github.com/pNre/ExSwift/pull/43) ([michaeleisel](https://github.com/michaeleisel)) 116 | 117 | - added combinations method [\#42](https://github.com/pNre/ExSwift/pull/42) ([michaeleisel](https://github.com/michaeleisel)) 118 | 119 | - Unique by method [\#41](https://github.com/pNre/ExSwift/pull/41) ([michaeleisel](https://github.com/michaeleisel)) 120 | 121 | - Added UIColor extension [\#39](https://github.com/pNre/ExSwift/pull/39) ([PGLongo](https://github.com/PGLongo)) 122 | 123 | - Added minBy and maxBy methods [\#37](https://github.com/pNre/ExSwift/pull/37) ([michaeleisel](https://github.com/michaeleisel)) 124 | 125 | - Add installation instruction [\#35](https://github.com/pNre/ExSwift/pull/35) ([kostiakoval](https://github.com/kostiakoval)) 126 | 127 | - the script can generation a Framework of StaticLibrary [\#30](https://github.com/pNre/ExSwift/pull/30) ([zhfish](https://github.com/zhfish)) 128 | 129 | ## [0.1.9](https://github.com/pNre/ExSwift/tree/0.1.9) (2014-08-20) 130 | 131 | [Full Changelog](https://github.com/pNre/ExSwift/compare/0.1.8...0.1.9) 132 | 133 | **Merged pull requests:** 134 | 135 | - Added count methods [\#27](https://github.com/pNre/ExSwift/pull/27) ([jmnavarro](https://github.com/jmnavarro)) 136 | 137 | ## [0.1.8](https://github.com/pNre/ExSwift/tree/0.1.8) (2014-08-05) 138 | 139 | [Full Changelog](https://github.com/pNre/ExSwift/compare/0.1.7...0.1.8) 140 | 141 | **Closed issues:** 142 | 143 | - ExSwift broken in beta 5 [\#26](https://github.com/pNre/ExSwift/issues/26) 144 | 145 | - Single index string subscripting results in compiler error [\#25](https://github.com/pNre/ExSwift/issues/25) 146 | 147 | - Array.indexOf not working with \[UInt\] [\#21](https://github.com/pNre/ExSwift/issues/21) 148 | 149 | **Merged pull requests:** 150 | 151 | - Changes =~ to take regular expression. [\#22](https://github.com/pNre/ExSwift/pull/22) ([nomothetis](https://github.com/nomothetis)) 152 | 153 | ## [0.1.7](https://github.com/pNre/ExSwift/tree/0.1.7) (2014-07-25) 154 | 155 | [Full Changelog](https://github.com/pNre/ExSwift/compare/0.1.6...0.1.7) 156 | 157 | **Closed issues:** 158 | 159 | - Breaks in Xcode6-Beta4 [\#19](https://github.com/pNre/ExSwift/issues/19) 160 | 161 | **Merged pull requests:** 162 | 163 | - Added access modifiers [\#20](https://github.com/pNre/ExSwift/pull/20) ([vmartinelli](https://github.com/vmartinelli)) 164 | 165 | ## [0.1.6](https://github.com/pNre/ExSwift/tree/0.1.6) (2014-07-22) 166 | 167 | [Full Changelog](https://github.com/pNre/ExSwift/compare/0.1.5...0.1.6) 168 | 169 | ## [0.1.5](https://github.com/pNre/ExSwift/tree/0.1.5) (2014-07-19) 170 | 171 | [Full Changelog](https://github.com/pNre/ExSwift/compare/0.1.4...0.1.5) 172 | 173 | **Closed issues:** 174 | 175 | - Support for Double / Integer [\#18](https://github.com/pNre/ExSwift/issues/18) 176 | 177 | - Help, got so many compile errors [\#17](https://github.com/pNre/ExSwift/issues/17) 178 | 179 | ## [0.1.4](https://github.com/pNre/ExSwift/tree/0.1.4) (2014-07-07) 180 | 181 | [Full Changelog](https://github.com/pNre/ExSwift/compare/0.1.3...0.1.4) 182 | 183 | **Merged pull requests:** 184 | 185 | - used shuffle\(\) to shuffle in shuffled\(\) [\#16](https://github.com/pNre/ExSwift/pull/16) ([natecook1000](https://github.com/natecook1000)) 186 | 187 | ## [0.1.3](https://github.com/pNre/ExSwift/tree/0.1.3) (2014-07-03) 188 | 189 | [Full Changelog](https://github.com/pNre/ExSwift/compare/0.1.2...0.1.3) 190 | 191 | **Merged pull requests:** 192 | 193 | - Sequence ops [\#15](https://github.com/pNre/ExSwift/pull/15) ([ColinEberhardt](https://github.com/ColinEberhardt)) 194 | 195 | - Added a toDictionary method [\#13](https://github.com/pNre/ExSwift/pull/13) ([ColinEberhardt](https://github.com/ColinEberhardt)) 196 | 197 | - Added a sortBy method [\#12](https://github.com/pNre/ExSwift/pull/12) ([ColinEberhardt](https://github.com/ColinEberhardt)) 198 | 199 | - Define iOS module with the same name as OS X, cleanup duplicate files [\#11](https://github.com/pNre/ExSwift/pull/11) ([garnett](https://github.com/garnett)) 200 | 201 | - Simplify partition tests [\#10](https://github.com/pNre/ExSwift/pull/10) ([zolrath](https://github.com/zolrath)) 202 | 203 | ## [0.1.2](https://github.com/pNre/ExSwift/tree/0.1.2) (2014-06-18) 204 | 205 | [Full Changelog](https://github.com/pNre/ExSwift/compare/0.1.1...0.1.2) 206 | 207 | **Fixed bugs:** 208 | 209 | - Compile error: Access String array by subscript [\#6](https://github.com/pNre/ExSwift/issues/6) 210 | 211 | **Closed issues:** 212 | 213 | - Result of indexOf, lastIndexOf should be an optional [\#8](https://github.com/pNre/ExSwift/issues/8) 214 | 215 | **Merged pull requests:** 216 | 217 | - Add .gitignore, add iOS Framework + tests target [\#7](https://github.com/pNre/ExSwift/pull/7) ([garnett](https://github.com/garnett)) 218 | 219 | - return Int? in indexOf, lastIndexOf [\#9](https://github.com/pNre/ExSwift/pull/9) ([garnett](https://github.com/garnett)) 220 | 221 | - Add partition, partitionAll, and partitionBy [\#5](https://github.com/pNre/ExSwift/pull/5) ([zolrath](https://github.com/zolrath)) 222 | 223 | - Add takeWhile and skipWhile to Array [\#4](https://github.com/pNre/ExSwift/pull/4) ([zolrath](https://github.com/zolrath)) 224 | 225 | ## [0.1.1](https://github.com/pNre/ExSwift/tree/0.1.1) (2014-06-11) 226 | 227 | [Full Changelog](https://github.com/pNre/ExSwift/compare/0.1.0...0.1.1) 228 | 229 | **Merged pull requests:** 230 | 231 | - Use if let syntax for Dictionary {group, count}by [\#3](https://github.com/pNre/ExSwift/pull/3) ([zolrath](https://github.com/zolrath)) 232 | 233 | - Use if let syntax for groupBy and countBy [\#2](https://github.com/pNre/ExSwift/pull/2) ([zolrath](https://github.com/zolrath)) 234 | 235 | ## [0.1.0](https://github.com/pNre/ExSwift/tree/0.1.0) (2014-06-10) 236 | 237 | 238 | 239 | \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* -------------------------------------------------------------------------------- /ExSwift.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "ExSwift" 3 | s.version = "0.1.9" 4 | s.summary = "Set of Swift extensions for standard types and classes." 5 | s.homepage = "https://github.com/pNre/ExSwift" 6 | s.license = { :type => 'BSD', :file => 'LICENSE' } 7 | s.author = { "pNre" => "mail@pnre.co" } 8 | s.source = { :git => "https://github.com/pNre/ExSwift.git", :tag => "0.1.9" } 9 | s.source_files = 'ExSwift/*.{h,swift}' 10 | s.frameworks = 'Foundation' 11 | s.requires_arc = true 12 | end 13 | -------------------------------------------------------------------------------- /ExSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ExSwift.xcodeproj/xcshareddata/xcschemes/ExSwift-Mac.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 94 | 100 | 101 | 102 | 103 | 105 | 106 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /ExSwift.xcodeproj/xcshareddata/xcschemes/ExSwift-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 94 | 100 | 101 | 102 | 103 | 105 | 106 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /ExSwift.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ExSwift/Bool.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Bool.swift 3 | // ExSwift 4 | // 5 | // Created by Hernandez Alvarez, David on 2/10/15. 6 | // Copyright (c) 2015 pNre. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension Bool { 12 | 13 | mutating func toggle() -> Bool { 14 | self = !self 15 | return self 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /ExSwift/Character.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Character.swift 3 | // ExSwift 4 | // 5 | // Created by Cenny Davidsson on 2014-12-08. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension Character { 12 | 13 | /** 14 | If the character represents an integer that fits into an Int, returns 15 | the corresponding integer. 16 | */ 17 | public func toInt () -> Int? { 18 | return String(self).toInt() 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /ExSwift/Dictionary.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Dictionary.swift 3 | // ExSwift 4 | // 5 | // Created by pNre on 04/06/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Swift 11 | 12 | internal extension Dictionary { 13 | 14 | /** 15 | Difference of self and the input dictionaries. 16 | Two dictionaries are considered equal if they contain the same [key: value] pairs. 17 | 18 | :param: dictionaries Dictionaries to subtract 19 | :returns: Difference of self and the input dictionaries 20 | */ 21 | func difference (dictionaries: [Key: V]...) -> [Key: V] { 22 | 23 | var result = [Key: V]() 24 | 25 | each { 26 | if let item = $1 as? V { 27 | result[$0] = item 28 | } 29 | } 30 | 31 | // Difference 32 | for dictionary in dictionaries { 33 | for (key, value) in dictionary { 34 | if result.has(key) && result[key] == value { 35 | result.removeValueForKey(key) 36 | } 37 | } 38 | } 39 | 40 | return result 41 | 42 | } 43 | 44 | /** 45 | Union of self and the input dictionaries. 46 | 47 | :param: dictionaries Dictionaries to join 48 | :returns: Union of self and the input dictionaries 49 | */ 50 | func union (dictionaries: Dictionary...) -> Dictionary { 51 | 52 | var result = self 53 | 54 | dictionaries.each { (dictionary) -> Void in 55 | dictionary.each { (key, value) -> Void in 56 | _ = result.updateValue(value, forKey: key) 57 | } 58 | } 59 | 60 | return result 61 | 62 | } 63 | 64 | /** 65 | Intersection of self and the input dictionaries. 66 | Two dictionaries are considered equal if they contain the same [key: value] copules. 67 | 68 | :param: values Dictionaries to intersect 69 | :returns: Dictionary of [key: value] couples contained in all the dictionaries and self 70 | */ 71 | func intersection (dictionaries: [K: V]...) -> [K: V] { 72 | 73 | // Casts self from [Key: Value] to [K: V] 74 | let filtered = mapFilter { (item, value) -> (K, V)? in 75 | if (item is K) && (value is V) { 76 | return (item as! K, value as! V) 77 | } 78 | 79 | return nil 80 | } 81 | 82 | // Intersection 83 | return filtered.filter({ (key: K, value: V) -> Bool in 84 | // check for [key: value] in all the dictionaries 85 | dictionaries.all { $0.has(key) && $0[key] == value } 86 | }) 87 | 88 | } 89 | 90 | /** 91 | Checks if a key exists in the dictionary. 92 | 93 | :param: key Key to check 94 | :returns: true if the key exists 95 | */ 96 | func has (key: Key) -> Bool { 97 | return indexForKey(key) != nil 98 | } 99 | 100 | /** 101 | Creates an Array with values generated by running 102 | each [key: value] of self through the mapFunction. 103 | 104 | :param: mapFunction 105 | :returns: Mapped array 106 | */ 107 | func toArray (map: (Key, Value) -> V) -> [V] { 108 | 109 | var mapped = [V]() 110 | 111 | each { 112 | mapped.append(map($0, $1)) 113 | } 114 | 115 | return mapped 116 | 117 | } 118 | 119 | /** 120 | Creates a Dictionary with the same keys as self and values generated by running 121 | each [key: value] of self through the mapFunction. 122 | 123 | :param: mapFunction 124 | :returns: Mapped dictionary 125 | */ 126 | func mapValues (map: (Key, Value) -> V) -> [Key: V] { 127 | 128 | var mapped = [Key: V]() 129 | 130 | each { 131 | mapped[$0] = map($0, $1) 132 | } 133 | 134 | return mapped 135 | 136 | } 137 | 138 | /** 139 | Creates a Dictionary with the same keys as self and values generated by running 140 | each [key: value] of self through the mapFunction discarding nil return values. 141 | 142 | :param: mapFunction 143 | :returns: Mapped dictionary 144 | */ 145 | func mapFilterValues (map: (Key, Value) -> V?) -> [Key: V] { 146 | 147 | var mapped = [Key: V]() 148 | 149 | each { 150 | if let value = map($0, $1) { 151 | mapped[$0] = value 152 | } 153 | } 154 | 155 | return mapped 156 | 157 | } 158 | 159 | /** 160 | Creates a Dictionary with keys and values generated by running 161 | each [key: value] of self through the mapFunction discarding nil return values. 162 | 163 | :param: mapFunction 164 | :returns: Mapped dictionary 165 | */ 166 | func mapFilter (map: (Key, Value) -> (K, V)?) -> [K: V] { 167 | 168 | var mapped = [K: V]() 169 | 170 | each { 171 | if let value = map($0, $1) { 172 | mapped[value.0] = value.1 173 | } 174 | } 175 | 176 | return mapped 177 | 178 | } 179 | 180 | /** 181 | Creates a Dictionary with keys and values generated by running 182 | each [key: value] of self through the mapFunction. 183 | 184 | :param: mapFunction 185 | :returns: Mapped dictionary 186 | */ 187 | func map (map: (Key, Value) -> (K, V)) -> [K: V] { 188 | 189 | var mapped = [K: V]() 190 | 191 | self.each({ 192 | let (_key, _value) = map($0, $1) 193 | mapped[_key] = _value 194 | }) 195 | 196 | return mapped 197 | 198 | } 199 | 200 | /** 201 | Loops trough each [key: value] pair in self. 202 | 203 | :param: eachFunction Function to inovke on each loop 204 | */ 205 | func each (each: (Key, Value) -> ()) { 206 | 207 | for (key, value) in self { 208 | each(key, value) 209 | } 210 | 211 | } 212 | 213 | /** 214 | Constructs a dictionary containing every [key: value] pair from self 215 | for which testFunction evaluates to true. 216 | 217 | :param: testFunction Function called to test each key, value 218 | :returns: Filtered dictionary 219 | */ 220 | func filter (test: (Key, Value) -> Bool) -> Dictionary { 221 | 222 | var result = Dictionary() 223 | 224 | for (key, value) in self { 225 | if test(key, value) { 226 | result[key] = value 227 | } 228 | } 229 | 230 | return result 231 | 232 | } 233 | 234 | /** 235 | Creates a dictionary composed of keys generated from the results of 236 | running each element of self through groupingFunction. The corresponding 237 | value of each key is an array of the elements responsible for generating the key. 238 | 239 | :param: groupingFunction 240 | :returns: Grouped dictionary 241 | */ 242 | func groupBy (group: (Key, Value) -> T) -> [T: [Value]] { 243 | 244 | var result = [T: [Value]]() 245 | 246 | for (key, value) in self { 247 | 248 | let groupKey = group(key, value) 249 | 250 | // If element has already been added to dictionary, append to it. If not, create one. 251 | if result.has(groupKey) { 252 | result[groupKey]! += [value] 253 | } else { 254 | result[groupKey] = [value] 255 | } 256 | 257 | } 258 | 259 | return result 260 | } 261 | 262 | /** 263 | Similar to groupBy. Doesn't return a list of values, but the number of values for each group. 264 | 265 | :param: groupingFunction Function called to define the grouping key 266 | :returns: Grouped dictionary 267 | */ 268 | func countBy (group: (Key, Value) -> (T)) -> [T: Int] { 269 | 270 | var result = [T: Int]() 271 | 272 | for (key, value) in self { 273 | 274 | let groupKey = group(key, value) 275 | 276 | // If element has already been added to dictionary, append to it. If not, create one. 277 | if result.has(groupKey) { 278 | result[groupKey]!++ 279 | } else { 280 | result[groupKey] = 1 281 | } 282 | } 283 | 284 | return result 285 | } 286 | 287 | /** 288 | Checks if test evaluates true for all the elements in self. 289 | 290 | :param: test Function to call for each element 291 | :returns: true if test returns true for all the elements in self 292 | */ 293 | func all (test: (Key, Value) -> (Bool)) -> Bool { 294 | 295 | for (key, value) in self { 296 | if !test(key, value) { 297 | return false 298 | } 299 | } 300 | 301 | return true 302 | 303 | } 304 | 305 | /** 306 | Checks if test evaluates true for any element of self. 307 | 308 | :param: test Function to call for each element 309 | :returns: true if test returns true for any element of self 310 | */ 311 | func any (test: (Key, Value) -> (Bool)) -> Bool { 312 | 313 | for (key, value) in self { 314 | if test(key, value) { 315 | return true 316 | } 317 | } 318 | 319 | return false 320 | 321 | } 322 | 323 | 324 | /** 325 | Returns the number of elements which meet the condition 326 | 327 | :param: test Function to call for each element 328 | :returns: the number of elements meeting the condition 329 | */ 330 | func countWhere (test: (Key, Value) -> (Bool)) -> Int { 331 | 332 | var result = 0 333 | 334 | for (key, value) in self { 335 | if test(key, value) { 336 | result++ 337 | } 338 | } 339 | 340 | return result 341 | } 342 | 343 | 344 | /** 345 | Recombines the [key: value] couples in self trough combine using initial as initial value. 346 | 347 | :param: initial Initial value 348 | :param: combine Function that reduces the dictionary 349 | :returns: Resulting value 350 | */ 351 | func reduce (initial: U, combine: (U, Element) -> U) -> U { 352 | return Swift.reduce(self, initial, combine) 353 | } 354 | 355 | /** 356 | Returns a copy of self, filtered to only have values for the whitelisted keys. 357 | 358 | :param: keys Whitelisted keys 359 | :returns: Filtered dictionary 360 | */ 361 | func pick (keys: [Key]) -> Dictionary { 362 | return filter { (key: Key, _) -> Bool in 363 | return keys.contains(key) 364 | } 365 | } 366 | 367 | /** 368 | Returns a copy of self, filtered to only have values for the whitelisted keys. 369 | 370 | :param: keys Whitelisted keys 371 | :returns: Filtered dictionary 372 | */ 373 | func pick (keys: Key...) -> Dictionary { 374 | return pick(unsafeBitCast(keys, [Key].self)) 375 | } 376 | 377 | /** 378 | Returns a copy of self, filtered to only have values for the whitelisted keys. 379 | 380 | :param: keys Keys to get 381 | :returns: Dictionary with the given keys 382 | */ 383 | func at (keys: Key...) -> Dictionary { 384 | return pick(keys) 385 | } 386 | 387 | /** 388 | Removes a (key, value) pair from self and returns it as tuple. 389 | If the dictionary is empty returns nil. 390 | 391 | :returns: (key, value) tuple 392 | */ 393 | mutating func shift () -> (Key, Value)? { 394 | if let key = keys.first { 395 | return (key, removeValueForKey(key)!) 396 | } 397 | 398 | return nil 399 | } 400 | } 401 | 402 | /** 403 | Difference operator 404 | */ 405 | public func - (first: [K: V], second: [K: V]) -> [K: V] { 406 | return first.difference(second) 407 | } 408 | 409 | /** 410 | Intersection operator 411 | */ 412 | public func & (first: [K: V], second: [K: V]) -> [K: V] { 413 | return first.intersection(second) 414 | } 415 | 416 | /** 417 | Union operator 418 | */ 419 | public func | (first: [K: V], second: [K: V]) -> [K: V] { 420 | return first.union(second) 421 | } 422 | -------------------------------------------------------------------------------- /ExSwift/Double.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Double.swift 3 | // ExSwift 4 | // 5 | // Created by pNre on 10/07/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension Double { 12 | 13 | /** 14 | Absolute value. 15 | 16 | :returns: fabs(self) 17 | */ 18 | func abs () -> Double { 19 | return Foundation.fabs(self) 20 | } 21 | 22 | /** 23 | Squared root. 24 | 25 | :returns: sqrt(self) 26 | */ 27 | func sqrt () -> Double { 28 | return Foundation.sqrt(self) 29 | } 30 | 31 | /** 32 | Rounds self to the largest integer <= self. 33 | 34 | :returns: floor(self) 35 | */ 36 | func floor () -> Double { 37 | return Foundation.floor(self) 38 | } 39 | 40 | /** 41 | Rounds self to the smallest integer >= self. 42 | 43 | :returns: ceil(self) 44 | */ 45 | func ceil () -> Double { 46 | return Foundation.ceil(self) 47 | } 48 | 49 | /** 50 | Rounds self to the nearest integer. 51 | 52 | :returns: round(self) 53 | */ 54 | func round () -> Double { 55 | return Foundation.round(self) 56 | } 57 | 58 | /** 59 | Clamps self to a specified range. 60 | 61 | :param: min Lower bound 62 | :param: max Upper bound 63 | :returns: Clamped value 64 | */ 65 | func clamp (min: Double, _ max: Double) -> Double { 66 | return Swift.max(min, Swift.min(max, self)) 67 | } 68 | 69 | /** 70 | Just like round(), except it supports rounding to an arbitrary number, not just 1 71 | Be careful about rounding errors 72 | 73 | :params: increment the increment to round to 74 | */ 75 | func roundToNearest(increment: Double) -> Double { 76 | let remainder = self % increment 77 | return remainder < increment / 2 ? self - remainder : self - remainder + increment 78 | } 79 | 80 | /** 81 | Random double between min and max (inclusive). 82 | 83 | :params: min 84 | :params: max 85 | :returns: Random number 86 | */ 87 | static func random(min: Double = 0, max: Double) -> Double { 88 | let diff = max - min; 89 | let rand = Double(arc4random() % (UInt32(RAND_MAX) + 1)) 90 | return ((rand / Double(RAND_MAX)) * diff) + min; 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /ExSwift/ExSwift.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExSwift.h 3 | // ExSwift 4 | // 5 | // Created by pNre on 07/06/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for ExSwift. 12 | FOUNDATION_EXPORT double ExSwiftVersionNumber; 13 | 14 | //! Project version string for ExSwift. 15 | FOUNDATION_EXPORT const unsigned char ExSwiftVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /ExSwift/ExSwift.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExSwift.swift 3 | // ExSwift 4 | // 5 | // Created by pNre on 07/06/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | infix operator =~ {} 12 | infix operator |~ {} 13 | infix operator .. {} 14 | infix operator <=> {} 15 | 16 | public typealias Ex = ExSwift 17 | 18 | public class ExSwift { 19 | 20 | /** 21 | Creates a wrapper that, executes function only after being called n times. 22 | 23 | :param: n No. of times the wrapper has to be called before function is invoked 24 | :param: function Function to wrap 25 | :returns: Wrapper function 26 | */ 27 | public class func after (n: Int, function: (P...) -> T) -> ((P...) -> T?) { 28 | 29 | typealias Function = [P] -> T 30 | 31 | var times = n 32 | 33 | return { 34 | (params: P...) -> T? in 35 | 36 | // Workaround for the now illegal (T...) type. 37 | let adaptedFunction = unsafeBitCast(function, Function.self) 38 | 39 | if times-- <= 0 { 40 | return adaptedFunction(params) 41 | } 42 | 43 | return nil 44 | } 45 | 46 | } 47 | 48 | /** 49 | Creates a wrapper that, executes function only after being called n times 50 | 51 | :param: n No. of times the wrapper has to be called before function is invoked 52 | :param: function Function to wrap 53 | :returns: Wrapper function 54 | */ 55 | public class func after (n: Int, function: Void -> T) -> (Void -> T?) { 56 | func callAfter (args: Any?...) -> T { 57 | return function() 58 | } 59 | 60 | let f = ExSwift.after(n, function: callAfter) 61 | 62 | return { f([nil]) } 63 | } 64 | 65 | /** 66 | Creates a wrapper function that invokes function once. 67 | Repeated calls to the wrapper function will return the value of the first call. 68 | 69 | :param: function Function to wrap 70 | :returns: Wrapper function 71 | */ 72 | public class func once (function: (P...) -> T) -> ((P...) -> T) { 73 | 74 | typealias Function = [P] -> T 75 | 76 | var returnValue: T? = nil 77 | 78 | return { (params: P...) -> T in 79 | 80 | if returnValue != nil { 81 | return returnValue! 82 | } 83 | 84 | let adaptedFunction = unsafeBitCast(function, Function.self) 85 | returnValue = adaptedFunction(params) 86 | 87 | return returnValue! 88 | 89 | } 90 | 91 | } 92 | 93 | /** 94 | Creates a wrapper function that invokes function once. 95 | Repeated calls to the wrapper function will return the value of the first call. 96 | 97 | :param: function Function to wrap 98 | :returns: Wrapper function 99 | */ 100 | public class func once (function: Void -> T) -> (Void -> T) { 101 | let f = ExSwift.once { 102 | (params: Any?...) -> T in 103 | return function() 104 | } 105 | 106 | return { f([nil]) } 107 | } 108 | 109 | /** 110 | Creates a wrapper that, when called, invokes function with any additional 111 | partial arguments prepended to those provided to the new function. 112 | 113 | :param: function Function to wrap 114 | :param: parameters Arguments to prepend 115 | :returns: Wrapper function 116 | */ 117 | public class func partial (function: (P...) -> T, _ parameters: P...) -> ((P...) -> T) { 118 | typealias Function = [P] -> T 119 | 120 | return { (params: P...) -> T in 121 | let adaptedFunction = unsafeBitCast(function, Function.self) 122 | return adaptedFunction(parameters + params) 123 | } 124 | } 125 | 126 | /** 127 | Creates a wrapper (without any parameter) that, when called, invokes function 128 | automatically passing parameters as arguments. 129 | 130 | :param: function Function to wrap 131 | :param: parameters Arguments to pass to function 132 | :returns: Wrapper function 133 | */ 134 | public class func bind (function: (P...) -> T, _ parameters: P...) -> (Void -> T) { 135 | typealias Function = [P] -> T 136 | 137 | return { Void -> T in 138 | let adaptedFunction = unsafeBitCast(function, Function.self) 139 | return adaptedFunction(parameters) 140 | } 141 | } 142 | 143 | /** 144 | Creates a wrapper for function that caches the result of function's invocations. 145 | 146 | :param: function Function with one parameter to cache 147 | :returns: Wrapper function 148 | */ 149 | public class func cached (function: P -> R) -> (P -> R) { 150 | var cache = [P:R]() 151 | 152 | return { (param: P) -> R in 153 | let key = param 154 | 155 | if let cachedValue = cache[key] { 156 | return cachedValue 157 | } else { 158 | let value = function(param) 159 | cache[key] = value 160 | return value 161 | } 162 | } 163 | } 164 | 165 | /** 166 | Creates a wrapper for function that caches the result of function's invocations. 167 | 168 | :param: function Function to cache 169 | :param: hash Parameters based hashing function that computes the key used to store each result in the cache 170 | :returns: Wrapper function 171 | */ 172 | public class func cached (function: (P...) -> R, hash: ((P...) -> P)) -> ((P...) -> R) { 173 | typealias Function = [P] -> R 174 | typealias Hash = [P] -> P 175 | 176 | var cache = [P:R]() 177 | 178 | return { (params: P...) -> R in 179 | let adaptedFunction = unsafeBitCast(function, Function.self) 180 | let adaptedHash = unsafeBitCast(hash, Hash.self) 181 | 182 | let key = adaptedHash(params) 183 | 184 | if let cachedValue = cache[key] { 185 | return cachedValue 186 | } else { 187 | let value = adaptedFunction(params) 188 | cache[key] = value 189 | return value 190 | } 191 | } 192 | } 193 | 194 | /** 195 | Creates a wrapper for function that caches the result of function's invocations. 196 | 197 | :param: function Function to cache 198 | :returns: Wrapper function 199 | */ 200 | public class func cached (function: (P...) -> R) -> ((P...) -> R) { 201 | return cached(function, hash: { (params: P...) -> P in return params[0] }) 202 | } 203 | 204 | /** 205 | Utility method to return an NSRegularExpression object given a pattern. 206 | 207 | :param: pattern Regex pattern 208 | :param: ignoreCase If true the NSRegularExpression is created with the NSRegularExpressionOptions.CaseInsensitive flag 209 | :returns: NSRegularExpression object 210 | */ 211 | internal class func regex (pattern: String, ignoreCase: Bool = false) -> NSRegularExpression? { 212 | 213 | var options = NSRegularExpressionOptions.DotMatchesLineSeparators.rawValue 214 | 215 | if ignoreCase { 216 | options = NSRegularExpressionOptions.CaseInsensitive.rawValue | options 217 | } 218 | 219 | var error: NSError? = nil 220 | let regex = NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions(rawValue: options), error: &error) 221 | 222 | return (error == nil) ? regex : nil 223 | 224 | } 225 | 226 | } 227 | 228 | func <=> (lhs: T, rhs: T) -> Int { 229 | if lhs < rhs { 230 | return -1 231 | } else if lhs > rhs { 232 | return 1 233 | } else { 234 | return 0 235 | } 236 | } 237 | 238 | /** 239 | * Internal methods 240 | */ 241 | extension ExSwift { 242 | 243 | /** 244 | * Converts, if possible, and flattens an object from its Objective-C 245 | * representation to the Swift one. 246 | * @param object Object to convert 247 | * @returns Flattenend array of converted values 248 | */ 249 | internal class func bridgeObjCObject (object: S) -> [T] { 250 | var result = [T]() 251 | let reflection = reflect(object) 252 | 253 | // object has an Objective-C type 254 | if let obj = object as? T { 255 | // object has type T 256 | result.append(obj) 257 | } else if reflection.disposition == .ObjCObject { 258 | 259 | var bridgedValue: T!? 260 | 261 | // If it is an NSArray, flattening will produce the expected result 262 | if let array = object as? NSArray { 263 | result += array.flatten() 264 | } else if let bridged = reflection.value as? T { 265 | result.append(bridged) 266 | } 267 | } else if reflection.disposition == .IndexContainer { 268 | // object is a native Swift array 269 | 270 | // recursively convert each item 271 | (0.. Float { 19 | return fabsf(self) 20 | } 21 | 22 | /** 23 | Squared root. 24 | 25 | :returns: sqrtf(self) 26 | */ 27 | func sqrt () -> Float { 28 | return sqrtf(self) 29 | } 30 | 31 | /** 32 | Rounds self to the largest integer <= self. 33 | 34 | :returns: floorf(self) 35 | */ 36 | func floor () -> Float { 37 | return floorf(self) 38 | } 39 | 40 | /** 41 | Rounds self to the smallest integer >= self. 42 | 43 | :returns: ceilf(self) 44 | */ 45 | func ceil () -> Float { 46 | return ceilf(self) 47 | } 48 | 49 | /** 50 | Rounds self to the nearest integer. 51 | 52 | :returns: roundf(self) 53 | */ 54 | func round () -> Float { 55 | return roundf(self) 56 | } 57 | 58 | /** 59 | Clamps self to a specified range. 60 | 61 | :param: min Lower bound 62 | :param: max Upper bound 63 | :returns: Clamped value 64 | */ 65 | func clamp (min: Float, _ max: Float) -> Float { 66 | return Swift.max(min, Swift.min(max, self)) 67 | } 68 | 69 | /** 70 | Random float between min and max (inclusive). 71 | 72 | :param: min 73 | :param: max 74 | :returns: Random number 75 | */ 76 | static func random(min: Float = 0, max: Float) -> Float { 77 | let diff = max - min; 78 | let rand = Float(arc4random() % (UInt32(RAND_MAX) + 1)) 79 | return ((rand / Float(RAND_MAX)) * diff) + min; 80 | } 81 | 82 | } 83 | 84 | -------------------------------------------------------------------------------- /ExSwift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | co.pNre.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.2.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSHumanReadableCopyright 24 | Copyright © 2014 pNre. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /ExSwift/Int.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Int.swift 3 | // ExSwift 4 | // 5 | // Created by pNre on 03/06/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension Int { 12 | 13 | /** 14 | Calls function self times. 15 | 16 | :param: function Function to call 17 | */ 18 | func times (function: Void -> T) { 19 | (0.. Void) { 28 | (0.. (function: (Int) -> T) { 37 | (0.. Bool { 46 | return (self % 2) == 0 47 | } 48 | 49 | /** 50 | Checks if a number is odd. 51 | 52 | :returns: true if self is odd 53 | */ 54 | func isOdd () -> Bool { 55 | return !isEven() 56 | } 57 | 58 | /** 59 | Iterates function, passing in integer values from self up to and including limit. 60 | 61 | :param: limit Last value to pass 62 | :param: function Function to invoke 63 | */ 64 | func upTo (limit: Int, function: (Int) -> ()) { 65 | if limit < self { 66 | return 67 | } 68 | 69 | (self...limit).each(function) 70 | } 71 | 72 | /** 73 | Iterates function, passing in integer values from self down to and including limit. 74 | 75 | :param: limit Last value to pass 76 | :param: function Function to invoke 77 | */ 78 | func downTo (limit: Int, function: (Int) -> ()) { 79 | if limit > self { 80 | return 81 | } 82 | 83 | Array(limit...self).reverse().each(function) 84 | } 85 | 86 | /** 87 | Clamps self to a specified range. 88 | 89 | :param: range Clamping range 90 | :returns: Clamped value 91 | */ 92 | func clamp (range: Range) -> Int { 93 | return clamp(range.startIndex, range.endIndex - 1) 94 | } 95 | 96 | /** 97 | Clamps self to a specified range. 98 | 99 | :param: min Lower bound 100 | :param: max Upper bound 101 | :returns: Clamped value 102 | */ 103 | func clamp (min: Int, _ max: Int) -> Int { 104 | return Swift.max(min, Swift.min(max, self)) 105 | } 106 | 107 | /** 108 | Checks if self is included a specified range. 109 | 110 | :param: range Range 111 | :param: strict If true, "<" is used for comparison 112 | :returns: true if in range 113 | */ 114 | func isIn (range: Range, strict: Bool = false) -> Bool { 115 | if strict { 116 | return range.startIndex < self && self < range.endIndex - 1 117 | } 118 | 119 | return range.startIndex <= self && self <= range.endIndex - 1 120 | } 121 | 122 | /** 123 | Checks if self is included in a closed interval. 124 | 125 | :param: interval Interval to check 126 | :returns: true if in the interval 127 | */ 128 | func isIn (interval: ClosedInterval) -> Bool { 129 | return interval.contains(self) 130 | } 131 | 132 | /** 133 | Checks if self is included in an half open interval. 134 | 135 | :param: interval Interval to check 136 | :returns: true if in the interval 137 | */ 138 | func isIn (interval: HalfOpenInterval) -> Bool { 139 | return interval.contains(self) 140 | } 141 | 142 | /** 143 | Returns an [Int] containing the digits in self. 144 | 145 | :return: Array of digits 146 | */ 147 | func digits () -> [Int] { 148 | var result = [Int]() 149 | 150 | for char in String(self) { 151 | let string = String(char) 152 | if let toInt = string.toInt() { 153 | result.append(toInt) 154 | } 155 | } 156 | 157 | return result 158 | } 159 | 160 | /** 161 | Absolute value. 162 | 163 | :returns: abs(self) 164 | */ 165 | func abs () -> Int { 166 | return Swift.abs(self) 167 | } 168 | 169 | /** 170 | Greatest common divisor of self and n. 171 | 172 | :param: n 173 | :returns: GCD 174 | */ 175 | func gcd (n: Int) -> Int { 176 | return n == 0 ? self : n.gcd(self % n) 177 | } 178 | 179 | /** 180 | Least common multiple of self and n 181 | 182 | :param: n 183 | :returns: LCM 184 | */ 185 | func lcm (n: Int) -> Int { 186 | return (self * n).abs() / gcd(n) 187 | } 188 | 189 | /** 190 | Computes the factorial of self 191 | 192 | :returns: Factorial 193 | */ 194 | func factorial () -> Int { 195 | return self == 0 ? 1 : self * (self - 1).factorial() 196 | } 197 | 198 | /** 199 | Random integer between min and max (inclusive). 200 | 201 | :param: min Minimum value to return 202 | :param: max Maximum value to return 203 | :returns: Random integer 204 | */ 205 | static func random(min: Int = 0, max: Int) -> Int { 206 | return Int(arc4random_uniform(UInt32((max - min) + 1))) + min 207 | } 208 | 209 | } 210 | 211 | /** 212 | NSTimeInterval conversion extensions 213 | */ 214 | public extension Int { 215 | 216 | var years: NSTimeInterval { 217 | return 365 * self.days 218 | } 219 | 220 | var year: NSTimeInterval { 221 | return self.years 222 | } 223 | 224 | var days: NSTimeInterval { 225 | return 24 * self.hours 226 | } 227 | 228 | var day: NSTimeInterval { 229 | return self.days 230 | } 231 | 232 | var hours: NSTimeInterval { 233 | return 60 * self.minutes 234 | } 235 | 236 | var hour: NSTimeInterval { 237 | return self.hours 238 | } 239 | 240 | var minutes: NSTimeInterval { 241 | return 60 * self.seconds 242 | } 243 | 244 | var minute: NSTimeInterval { 245 | return self.minutes 246 | } 247 | 248 | var seconds: NSTimeInterval { 249 | return NSTimeInterval(self) 250 | } 251 | 252 | var second: NSTimeInterval { 253 | return self.seconds 254 | } 255 | 256 | } 257 | -------------------------------------------------------------------------------- /ExSwift/NSArray.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray.swift 3 | // ExSwift 4 | // 5 | // Created by pNre on 10/06/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension NSArray { 12 | 13 | /** 14 | Converts an NSArray object to an OutType[] array containing the items in the NSArray of type OutType. 15 | 16 | :returns: Array of Swift objects 17 | */ 18 | func cast () -> [OutType] { 19 | var result = [OutType]() 20 | 21 | for item : AnyObject in self { 22 | result += Ex.bridgeObjCObject(item) as [OutType] 23 | } 24 | 25 | return result 26 | } 27 | 28 | /** 29 | Flattens a multidimensional NSArray to an OutType[] array 30 | containing the items in the NSArray that can be bridged from their ObjC type to OutType. 31 | 32 | :returns: Flattened array 33 | */ 34 | func flatten () -> [OutType] { 35 | var result = [OutType]() 36 | let reflection = reflect(self) 37 | 38 | for i in 0.. [AnyObject] { 51 | var result = [AnyObject]() 52 | 53 | for item in self { 54 | if let array = item as? NSArray { 55 | result += array.flattenAny() 56 | } else { 57 | result.append(item) 58 | } 59 | } 60 | 61 | return result 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /ExSwift/NSDate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // ExSwift 4 | // 5 | // Created by Piergiuseppe Longo on 23/11/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension NSDate { 12 | 13 | // MARK: NSDate Manipulation 14 | 15 | /** 16 | Returns a new NSDate object representing the date calculated by adding the amount specified to self date 17 | 18 | :param: seconds number of seconds to add 19 | :param: minutes number of minutes to add 20 | :param: hours number of hours to add 21 | :param: days number of days to add 22 | :param: weeks number of weeks to add 23 | :param: months number of months to add 24 | :param: years number of years to add 25 | :returns: the NSDate computed 26 | */ 27 | public func add(seconds: Int = 0, minutes: Int = 0, hours: Int = 0, days: Int = 0, weeks: Int = 0, months: Int = 0, years: Int = 0) -> NSDate { 28 | var calendar = NSCalendar.currentCalendar() 29 | 30 | let version = floor(NSFoundationVersionNumber) 31 | 32 | if version <= NSFoundationVersionNumber10_9_2 { 33 | var component = NSDateComponents() 34 | component.setValue(seconds, forComponent: .CalendarUnitSecond) 35 | 36 | var date : NSDate! = calendar.dateByAddingComponents(component, toDate: self, options: nil)! 37 | component = NSDateComponents() 38 | component.setValue(minutes, forComponent: .CalendarUnitMinute) 39 | date = calendar.dateByAddingComponents(component, toDate: date, options: nil)! 40 | 41 | component = NSDateComponents() 42 | component.setValue(hours, forComponent: .CalendarUnitHour) 43 | date = calendar.dateByAddingComponents(component, toDate: date, options: nil)! 44 | 45 | component = NSDateComponents() 46 | component.setValue(days, forComponent: .CalendarUnitDay) 47 | date = calendar.dateByAddingComponents(component, toDate: date, options: nil)! 48 | 49 | component = NSDateComponents() 50 | component.setValue(weeks, forComponent: .CalendarUnitWeekOfMonth) 51 | date = calendar.dateByAddingComponents(component, toDate: date, options: nil)! 52 | 53 | component = NSDateComponents() 54 | component.setValue(months, forComponent: .CalendarUnitMonth) 55 | date = calendar.dateByAddingComponents(component, toDate: date, options: nil)! 56 | 57 | component = NSDateComponents() 58 | component.setValue(years, forComponent: .CalendarUnitYear) 59 | date = calendar.dateByAddingComponents(component, toDate: date, options: nil)! 60 | return date 61 | } 62 | 63 | var date : NSDate! = calendar.dateByAddingUnit(.CalendarUnitSecond, value: seconds, toDate: self, options: nil) 64 | date = calendar.dateByAddingUnit(.CalendarUnitMinute, value: minutes, toDate: date, options: nil) 65 | date = calendar.dateByAddingUnit(.CalendarUnitDay, value: days, toDate: date, options: nil) 66 | date = calendar.dateByAddingUnit(.CalendarUnitHour, value: hours, toDate: date, options: nil) 67 | date = calendar.dateByAddingUnit(.CalendarUnitWeekOfMonth, value: weeks, toDate: date, options: nil) 68 | date = calendar.dateByAddingUnit(.CalendarUnitMonth, value: months, toDate: date, options: nil) 69 | date = calendar.dateByAddingUnit(.CalendarUnitYear, value: years, toDate: date, options: nil) 70 | return date 71 | } 72 | 73 | /** 74 | Returns a new NSDate object representing the date calculated by adding an amount of seconds to self date 75 | 76 | :param: seconds number of seconds to add 77 | :returns: the NSDate computed 78 | */ 79 | public func addSeconds (seconds: Int) -> NSDate { 80 | return add(seconds: seconds) 81 | } 82 | 83 | /** 84 | Returns a new NSDate object representing the date calculated by adding an amount of minutes to self date 85 | 86 | :param: minutes number of minutes to add 87 | :returns: the NSDate computed 88 | */ 89 | public func addMinutes (minutes: Int) -> NSDate { 90 | return add(minutes: minutes) 91 | } 92 | 93 | /** 94 | Returns a new NSDate object representing the date calculated by adding an amount of hours to self date 95 | 96 | :param: hours number of hours to add 97 | :returns: the NSDate computed 98 | */ 99 | public func addHours(hours: Int) -> NSDate { 100 | return add(hours: hours) 101 | } 102 | 103 | /** 104 | Returns a new NSDate object representing the date calculated by adding an amount of days to self date 105 | 106 | :param: days number of days to add 107 | :returns: the NSDate computed 108 | */ 109 | public func addDays(days: Int) -> NSDate { 110 | return add(days: days) 111 | } 112 | 113 | /** 114 | Returns a new NSDate object representing the date calculated by adding an amount of weeks to self date 115 | 116 | :param: weeks number of weeks to add 117 | :returns: the NSDate computed 118 | */ 119 | public func addWeeks(weeks: Int) -> NSDate { 120 | return add(weeks: weeks) 121 | } 122 | 123 | 124 | /** 125 | Returns a new NSDate object representing the date calculated by adding an amount of months to self date 126 | 127 | :param: months number of months to add 128 | :returns: the NSDate computed 129 | */ 130 | 131 | public func addMonths(months: Int) -> NSDate { 132 | return add(months: months) 133 | } 134 | 135 | /** 136 | Returns a new NSDate object representing the date calculated by adding an amount of years to self date 137 | 138 | :param: years number of year to add 139 | :returns: the NSDate computed 140 | */ 141 | public func addYears(years: Int) -> NSDate { 142 | return add(years: years) 143 | } 144 | 145 | // MARK: Date comparison 146 | 147 | /** 148 | Checks if self is after input NSDate 149 | 150 | :param: date NSDate to compare 151 | :returns: True if self is after the input NSDate, false otherwise 152 | */ 153 | public func isAfter(date: NSDate) -> Bool{ 154 | return (self.compare(date) == NSComparisonResult.OrderedDescending) 155 | } 156 | 157 | /** 158 | Checks if self is before input NSDate 159 | 160 | :param: date NSDate to compare 161 | :returns: True if self is before the input NSDate, false otherwise 162 | */ 163 | public func isBefore(date: NSDate) -> Bool{ 164 | return (self.compare(date) == NSComparisonResult.OrderedAscending) 165 | } 166 | 167 | 168 | // MARK: Getter 169 | 170 | /** 171 | Date year 172 | */ 173 | public var year : Int { 174 | get { 175 | return getComponent(.CalendarUnitYear) 176 | } 177 | } 178 | 179 | /** 180 | Date month 181 | */ 182 | public var month : Int { 183 | get { 184 | return getComponent(.CalendarUnitMonth) 185 | } 186 | } 187 | 188 | /** 189 | Date weekday 190 | */ 191 | public var weekday : Int { 192 | get { 193 | return getComponent(.CalendarUnitWeekday) 194 | } 195 | } 196 | 197 | /** 198 | Date weekMonth 199 | */ 200 | public var weekMonth : Int { 201 | get { 202 | return getComponent(.CalendarUnitWeekOfMonth) 203 | } 204 | } 205 | 206 | 207 | /** 208 | Date days 209 | */ 210 | public var days : Int { 211 | get { 212 | return getComponent(.CalendarUnitDay) 213 | } 214 | } 215 | 216 | /** 217 | Date hours 218 | */ 219 | public var hours : Int { 220 | 221 | get { 222 | return getComponent(.CalendarUnitHour) 223 | } 224 | } 225 | 226 | /** 227 | Date minuts 228 | */ 229 | public var minutes : Int { 230 | get { 231 | return getComponent(.CalendarUnitMinute) 232 | } 233 | } 234 | 235 | /** 236 | Date seconds 237 | */ 238 | public var seconds : Int { 239 | get { 240 | return getComponent(.CalendarUnitSecond) 241 | } 242 | } 243 | 244 | /** 245 | Returns the value of the NSDate component 246 | 247 | :param: component NSCalendarUnit 248 | :returns: the value of the component 249 | */ 250 | 251 | public func getComponent (component : NSCalendarUnit) -> Int { 252 | let calendar = NSCalendar.currentCalendar() 253 | let components = calendar.components(component, fromDate: self) 254 | 255 | return components.valueForComponent(component) 256 | } 257 | } 258 | 259 | extension NSDate: Strideable { 260 | public func distanceTo(other: NSDate) -> NSTimeInterval { 261 | return other - self 262 | } 263 | 264 | public func advancedBy(n: NSTimeInterval) -> Self { 265 | return self.dynamicType(timeIntervalSinceReferenceDate: self.timeIntervalSinceReferenceDate + n) 266 | } 267 | } 268 | // MARK: Arithmetic 269 | 270 | func +(date: NSDate, timeInterval: Int) -> NSDate { 271 | return date + NSTimeInterval(timeInterval) 272 | } 273 | 274 | func -(date: NSDate, timeInterval: Int) -> NSDate { 275 | return date - NSTimeInterval(timeInterval) 276 | } 277 | 278 | func +=(inout date: NSDate, timeInterval: Int) { 279 | date = date + timeInterval 280 | } 281 | 282 | func -=(inout date: NSDate, timeInterval: Int) { 283 | date = date - timeInterval 284 | } 285 | 286 | func +(date: NSDate, timeInterval: Double) -> NSDate { 287 | return date.dateByAddingTimeInterval(NSTimeInterval(timeInterval)) 288 | } 289 | 290 | func -(date: NSDate, timeInterval: Double) -> NSDate { 291 | return date.dateByAddingTimeInterval(NSTimeInterval(-timeInterval)) 292 | } 293 | 294 | func +=(inout date: NSDate, timeInterval: Double) { 295 | date = date + timeInterval 296 | } 297 | 298 | func -=(inout date: NSDate, timeInterval: Double) { 299 | date = date - timeInterval 300 | } 301 | 302 | func -(date: NSDate, otherDate: NSDate) -> NSTimeInterval { 303 | return date.timeIntervalSinceDate(otherDate) 304 | } 305 | 306 | extension NSDate: Equatable { 307 | } 308 | 309 | public func ==(lhs: NSDate, rhs: NSDate) -> Bool { 310 | return lhs.compare(rhs) == NSComparisonResult.OrderedSame 311 | } 312 | 313 | extension NSDate: Comparable { 314 | } 315 | 316 | public func <(lhs: NSDate, rhs: NSDate) -> Bool { 317 | return lhs.compare(rhs) == NSComparisonResult.OrderedAscending 318 | } 319 | -------------------------------------------------------------------------------- /ExSwift/Range.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Range.swift 3 | // ExSwift 4 | // 5 | // Created by pNre on 04/06/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | internal extension Range { 12 | 13 | /** 14 | For each element in the range invokes function. 15 | 16 | :param: function Function to call 17 | */ 18 | func times (function: () -> ()) { 19 | each { (current: T) -> () in 20 | function() 21 | } 22 | } 23 | 24 | /** 25 | For each element in the range invokes function passing the element as argument. 26 | 27 | :param: function Function to invoke 28 | */ 29 | func times (function: (T) -> ()) { 30 | each (function) 31 | } 32 | 33 | /** 34 | For each element in the range invokes function passing the element as argument. 35 | 36 | :param: function Function to invoke 37 | */ 38 | func each (function: (T) -> ()) { 39 | for i in self { 40 | function(i) 41 | } 42 | } 43 | 44 | /** 45 | Returns each element of the range in an array 46 | 47 | :returns: Each element of the range in an array 48 | */ 49 | func toArray () -> [T] { 50 | var result: [T] = [] 51 | for i in self { 52 | result.append(i) 53 | } 54 | return result 55 | } 56 | 57 | /** 58 | Range of Int with random bounds between from and to (inclusive). 59 | 60 | :param: from Lower bound 61 | :param: to Upper bound 62 | :returns: Random range 63 | */ 64 | static func random (from: Int, to: Int) -> Range { 65 | let lowerBound = Int.random(min: from, max: to) 66 | let upperBound = Int.random(min: lowerBound, max: to) 67 | 68 | return lowerBound...upperBound 69 | } 70 | 71 | } 72 | 73 | /** 74 | * Operator == to compare 2 ranges first, second by start & end indexes. If first.startIndex is equal to 75 | * second.startIndex and first.endIndex is equal to second.endIndex the ranges are considered equal. 76 | */ 77 | public func == (first: Range, second: Range) -> Bool { 78 | return first.startIndex == second.startIndex && 79 | first.endIndex == second.endIndex 80 | } 81 | -------------------------------------------------------------------------------- /ExSwift/Sequence.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Sequence.swift 3 | // ExSwift 4 | // 5 | // Created by Colin Eberhardt on 24/06/2014. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | internal extension SequenceOf { 12 | 13 | /** 14 | First element of the sequence. 15 | 16 | :returns: First element of the sequence if present 17 | */ 18 | var first: T? { 19 | var generator = self.generate() 20 | return generator.next() 21 | } 22 | 23 | /** 24 | Checks if call returns true for any element of self. 25 | 26 | :param: call Function to call for each element 27 | :returns: True if call returns true for any element of self 28 | */ 29 | func any (call: (T) -> Bool) -> Bool { 30 | var generator = self.generate() 31 | while let nextItem = generator.next() { 32 | if call(nextItem) { 33 | return true 34 | } 35 | } 36 | return false 37 | } 38 | 39 | /** 40 | Object at the specified index if exists. 41 | 42 | :param: index 43 | :returns: Object at index in sequence, nil if index is out of bounds 44 | */ 45 | func get (index: Int) -> T? { 46 | var generator = self.generate() 47 | for _ in 0..<(index - 1) { 48 | generator.next() 49 | } 50 | return generator.next() 51 | } 52 | 53 | /** 54 | Objects in the specified range. 55 | 56 | :param: range 57 | :returns: Subsequence in range 58 | */ 59 | func get (range: Range) -> SequenceOf { 60 | return self.skip(range.startIndex).take(range.endIndex - range.startIndex) 61 | } 62 | 63 | /** 64 | Index of the first occurrence of item, if found. 65 | 66 | :param: item The item to search for 67 | :returns: Index of the matched item or nil 68 | */ 69 | func indexOf (item: U) -> Int? { 70 | var index = 0 71 | for current in self { 72 | if let equatable = current as? U { 73 | if equatable == item { 74 | return index 75 | } 76 | } 77 | index++ 78 | } 79 | return nil 80 | } 81 | 82 | /** 83 | Subsequence from n to the end of the sequence. 84 | 85 | :param: n Number of elements to skip 86 | :returns: Sequence from n to the end 87 | */ 88 | func skip (n: Int) -> SequenceOf { 89 | var generator = self.generate() 90 | for _ in 0.. Bool) -> SequenceOf { 103 | return SequenceOf(lazy(self).filter(include)) 104 | } 105 | 106 | /** 107 | Opposite of filter. 108 | 109 | :param: exclude Function invoked to test elements for exlcusion from the sequence 110 | :returns: Filtered sequence 111 | */ 112 | func reject (exclude: (T -> Bool)) -> SequenceOf { 113 | return self.filter { 114 | return !exclude($0) 115 | } 116 | } 117 | 118 | /** 119 | Skips the elements in the sequence up until the condition returns false. 120 | 121 | :param: condition A function which returns a boolean if an element satisfies a given condition or not 122 | :returns: Elements of the sequence starting with the element which does not meet the condition 123 | */ 124 | func skipWhile(condition:(T) -> Bool) -> SequenceOf { 125 | var generator = self.generate() 126 | var checkingGenerator = self.generate() 127 | 128 | var keepSkipping = true 129 | 130 | while keepSkipping { 131 | var nextItem = checkingGenerator.next() 132 | keepSkipping = nextItem != nil ? condition(nextItem!) : false 133 | 134 | if keepSkipping { 135 | generator.next() 136 | } 137 | } 138 | return SequenceOf(generator) 139 | } 140 | 141 | /** 142 | Checks if self contains the item object. 143 | 144 | :param: item The item to search for 145 | :returns: true if self contains item 146 | */ 147 | func contains (item: T) -> Bool { 148 | var generator = self.generate() 149 | while let nextItem = generator.next() { 150 | if nextItem as! T == item { 151 | return true 152 | } 153 | } 154 | return false 155 | } 156 | 157 | /** 158 | Returns the first n elements from self. 159 | 160 | :param: n Number of elements to take 161 | :returns: First n elements 162 | */ 163 | func take (n: Int) -> SequenceOf { 164 | return SequenceOf(TakeSequence(self, n)) 165 | } 166 | 167 | /** 168 | Returns the elements of the sequence up until an element does not meet the condition. 169 | 170 | :param: condition A function which returns a boolean if an element satisfies a given condition or not. 171 | :returns: Elements of the sequence up until an element does not meet the condition 172 | */ 173 | func takeWhile (condition:(T?) -> Bool) -> SequenceOf { 174 | return SequenceOf(TakeWhileSequence(self, condition)) 175 | } 176 | 177 | /** 178 | Returns each element of the sequence in an array 179 | 180 | :returns: Each element of the sequence in an array 181 | */ 182 | func toArray () -> [T] { 183 | var result: [T] = [] 184 | for item in self { 185 | result.append(item) 186 | } 187 | return result 188 | } 189 | } 190 | 191 | /** 192 | A sequence adapter that implements the 'take' functionality 193 | */ 194 | public struct TakeSequence: SequenceType { 195 | private let sequence: S 196 | private let n: Int 197 | 198 | public init(_ sequence: S, _ n: Int) { 199 | self.sequence = sequence 200 | self.n = n 201 | } 202 | 203 | public func generate() -> GeneratorOf { 204 | var count = 0 205 | var generator = self.sequence.generate() 206 | return GeneratorOf { 207 | count++ 208 | if count > self.n { 209 | return nil 210 | } else { 211 | return generator.next() 212 | } 213 | } 214 | } 215 | } 216 | 217 | /** 218 | a sequence adapter that implements the 'takeWhile' functionality 219 | */ 220 | public struct TakeWhileSequence: SequenceType { 221 | private let sequence: S 222 | private let condition: (S.Generator.Element?) -> Bool 223 | 224 | public init(_ sequence:S, _ condition:(S.Generator.Element?) -> Bool) { 225 | self.sequence = sequence 226 | self.condition = condition 227 | } 228 | 229 | public func generate() -> GeneratorOf { 230 | var generator = self.sequence.generate() 231 | var endConditionMet = false 232 | return GeneratorOf { 233 | let next: S.Generator.Element? = generator.next() 234 | if !endConditionMet { 235 | endConditionMet = !self.condition(next) 236 | } 237 | if endConditionMet { 238 | return nil 239 | } else { 240 | return next 241 | } 242 | } 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /ExSwift/String.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String.swift 3 | // ExSwift 4 | // 5 | // Created by pNre on 03/06/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension String { 12 | 13 | /** 14 | String length 15 | */ 16 | var length: Int { return count(self) } 17 | 18 | /** 19 | self.capitalizedString shorthand 20 | */ 21 | var capitalized: String { return capitalizedString } 22 | 23 | /** 24 | Returns the substring in the given range 25 | 26 | :param: range 27 | :returns: Substring in range 28 | */ 29 | subscript (range: Range) -> String? { 30 | if range.startIndex < 0 || range.endIndex > self.length { 31 | return nil 32 | } 33 | 34 | let range = Range(start: advance(startIndex, range.startIndex), end: advance(startIndex, range.endIndex)) 35 | 36 | return self[range] 37 | } 38 | 39 | /** 40 | Equivalent to at. Takes a list of indexes and returns an Array 41 | containing the elements at the given indexes in self. 42 | 43 | :param: firstIndex 44 | :param: secondIndex 45 | :param: restOfIndexes 46 | :returns: Charaters at the specified indexes (converted to String) 47 | */ 48 | subscript (firstIndex: Int, secondIndex: Int, restOfIndexes: Int...) -> [String] { 49 | return at([firstIndex, secondIndex] + restOfIndexes) 50 | } 51 | 52 | /** 53 | Gets the character at the specified index as String. 54 | If index is negative it is assumed to be relative to the end of the String. 55 | 56 | :param: index Position of the character to get 57 | :returns: Character as String or nil if the index is out of bounds 58 | */ 59 | subscript (index: Int) -> String? { 60 | if let char = Array(self).get(index) { 61 | return String(char) 62 | } 63 | 64 | return nil 65 | } 66 | 67 | /** 68 | Takes a list of indexes and returns an Array containing the elements at the given indexes in self. 69 | 70 | :param: indexes Positions of the elements to get 71 | :returns: Array of characters (as String) 72 | */ 73 | func at (indexes: Int...) -> [String] { 74 | return indexes.map { self[$0]! } 75 | } 76 | 77 | /** 78 | Takes a list of indexes and returns an Array containing the elements at the given indexes in self. 79 | 80 | :param: indexes Positions of the elements to get 81 | :returns: Array of characters (as String) 82 | */ 83 | func at (indexes: [Int]) -> [String] { 84 | return indexes.map { self[$0]! } 85 | } 86 | 87 | /** 88 | Returns an array of strings, each of which is a substring of self formed by splitting it on separator. 89 | 90 | :param: separator Character used to split the string 91 | :returns: Array of substrings 92 | */ 93 | func explode (separator: Character) -> [String] { 94 | return split(self, isSeparator: { (element: Character) -> Bool in 95 | return element == separator 96 | }) 97 | } 98 | 99 | /** 100 | Finds any match in self for pattern. 101 | 102 | :param: pattern Pattern to match 103 | :param: ignoreCase true for case insensitive matching 104 | :returns: Matches found (as [NSTextCheckingResult]) 105 | */ 106 | func matches (pattern: String, ignoreCase: Bool = false) -> [NSTextCheckingResult]? { 107 | 108 | if let regex = ExSwift.regex(pattern, ignoreCase: ignoreCase) { 109 | // Using map to prevent a possible bug in the compiler 110 | return regex.matchesInString(self, options: nil, range: NSMakeRange(0, length)).map { $0 as! NSTextCheckingResult } 111 | } 112 | 113 | return nil 114 | } 115 | 116 | /** 117 | Check is string with this pattern included in string 118 | 119 | :param: pattern Pattern to match 120 | :param: ignoreCase true for case insensitive matching 121 | :returns: true if contains match, otherwise false 122 | */ 123 | func containsMatch (pattern: String, ignoreCase: Bool = false) -> Bool? { 124 | if let regex = ExSwift.regex(pattern, ignoreCase: ignoreCase) { 125 | let range = NSMakeRange(0, count(self)) 126 | return regex.firstMatchInString(self, options: .allZeros, range: range) != nil 127 | } 128 | 129 | return nil 130 | } 131 | 132 | /** 133 | Replace all pattern matches with another string 134 | 135 | :param: pattern Pattern to match 136 | :param: replacementString string to replace matches 137 | :param: ignoreCase true for case insensitive matching 138 | :returns: true if contains match, otherwise false 139 | */ 140 | func replaceMatches (pattern: String, withString replacementString: String, ignoreCase: Bool = false) -> String? { 141 | if let regex = ExSwift.regex(pattern, ignoreCase: ignoreCase) { 142 | let range = NSMakeRange(0, count(self)) 143 | return regex.stringByReplacingMatchesInString(self, options: .allZeros, range: range, withTemplate: replacementString) 144 | } 145 | 146 | return nil 147 | } 148 | 149 | /** 150 | Inserts a substring at the given index in self. 151 | 152 | :param: index Where the new string is inserted 153 | :param: string String to insert 154 | :returns: String formed from self inserting string at index 155 | */ 156 | func insert (var index: Int, _ string: String) -> String { 157 | // Edge cases, prepend and append 158 | if index > length { 159 | return self + string 160 | } else if index < 0 { 161 | return string + self 162 | } 163 | 164 | return self[0.. String { 173 | if let range = rangeOfCharacterFromSet(set.invertedSet) { 174 | return self[range.startIndex.. String { 181 | return trimmedLeft(characterSet: set) 182 | } 183 | 184 | /** 185 | Strips the specified characters from the end of self. 186 | 187 | :returns: Stripped string 188 | */ 189 | func trimmedRight (characterSet set: NSCharacterSet = NSCharacterSet.whitespaceAndNewlineCharacterSet()) -> String { 190 | if let range = rangeOfCharacterFromSet(set.invertedSet, options: NSStringCompareOptions.BackwardsSearch) { 191 | return self[startIndex.. String { 198 | return trimmedRight(characterSet: set) 199 | } 200 | 201 | /** 202 | Strips whitespaces from both the beginning and the end of self. 203 | 204 | :returns: Stripped string 205 | */ 206 | func trimmed () -> String { 207 | return trimmedLeft().trimmedRight() 208 | } 209 | 210 | /** 211 | Costructs a string using random chars from a given set. 212 | 213 | :param: length String length. If < 1, it's randomly selected in the range 0..16 214 | :param: charset Chars to use in the random string 215 | :returns: Random string 216 | */ 217 | static func random (var length len: Int = 0, charset: String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") -> String { 218 | 219 | if len < 1 { 220 | len = Int.random(max: 16) 221 | } 222 | 223 | var result = String() 224 | let max = charset.length - 1 225 | 226 | len.times { 227 | result += charset[Int.random(min: 0, max: max)]! 228 | } 229 | 230 | return result 231 | 232 | } 233 | 234 | 235 | /** 236 | Parses a string containing a double numerical value into an optional double if the string is a well formed number. 237 | 238 | :returns: A double parsed from the string or nil if it cannot be parsed. 239 | */ 240 | func toDouble() -> Double? { 241 | 242 | let scanner = NSScanner(string: self) 243 | var double: Double = 0 244 | 245 | if scanner.scanDouble(&double) { 246 | return double 247 | } 248 | 249 | return nil 250 | 251 | } 252 | 253 | /** 254 | Parses a string containing a float numerical value into an optional float if the string is a well formed number. 255 | 256 | :returns: A float parsed from the string or nil if it cannot be parsed. 257 | */ 258 | func toFloat() -> Float? { 259 | 260 | let scanner = NSScanner(string: self) 261 | var float: Float = 0 262 | 263 | if scanner.scanFloat(&float) { 264 | return float 265 | } 266 | 267 | return nil 268 | 269 | } 270 | 271 | /** 272 | Parses a string containing a non-negative integer value into an optional UInt if the string is a well formed number. 273 | 274 | :returns: A UInt parsed from the string or nil if it cannot be parsed. 275 | */ 276 | func toUInt() -> UInt? { 277 | if let val = self.trimmed().toInt() { 278 | if val < 0 { 279 | return nil 280 | } 281 | return UInt(val) 282 | } 283 | 284 | return nil 285 | } 286 | 287 | 288 | /** 289 | Parses a string containing a boolean value (true or false) into an optional Bool if the string is a well formed. 290 | 291 | :returns: A Bool parsed from the string or nil if it cannot be parsed as a boolean. 292 | */ 293 | func toBool() -> Bool? { 294 | let text = self.trimmed().lowercaseString 295 | if text == "true" || text == "false" || text == "yes" || text == "no" { 296 | return (text as NSString).boolValue 297 | } 298 | 299 | return nil 300 | } 301 | 302 | /** 303 | Parses a string containing a date into an optional NSDate if the string is a well formed. 304 | The default format is yyyy-MM-dd, but can be overriden. 305 | 306 | :returns: A NSDate parsed from the string or nil if it cannot be parsed as a date. 307 | */ 308 | func toDate(format : String? = "yyyy-MM-dd") -> NSDate? { 309 | let text = self.trimmed().lowercaseString 310 | var dateFmt = NSDateFormatter() 311 | dateFmt.timeZone = NSTimeZone.defaultTimeZone() 312 | if let fmt = format { 313 | dateFmt.dateFormat = fmt 314 | } 315 | return dateFmt.dateFromString(text) 316 | } 317 | 318 | /** 319 | Parses a string containing a date and time into an optional NSDate if the string is a well formed. 320 | The default format is yyyy-MM-dd hh-mm-ss, but can be overriden. 321 | 322 | :returns: A NSDate parsed from the string or nil if it cannot be parsed as a date. 323 | */ 324 | func toDateTime(format : String? = "yyyy-MM-dd hh-mm-ss") -> NSDate? { 325 | return toDate(format: format) 326 | } 327 | 328 | } 329 | 330 | /** 331 | Repeats the string first n times 332 | */ 333 | public func * (first: String, n: Int) -> String { 334 | 335 | var result = String() 336 | 337 | n.times { 338 | result += first 339 | } 340 | 341 | return result 342 | 343 | } 344 | 345 | // Pattern matching using a regular expression 346 | public func =~ (string: String, pattern: String) -> Bool { 347 | 348 | let regex = ExSwift.regex(pattern, ignoreCase: false)! 349 | let matches = regex.numberOfMatchesInString(string, options: nil, range: NSMakeRange(0, string.length)) 350 | 351 | return matches > 0 352 | 353 | } 354 | 355 | // Pattern matching using a regular expression 356 | public func =~ (string: String, regex: NSRegularExpression) -> Bool { 357 | 358 | let matches = regex.numberOfMatchesInString(string, options: nil, range: NSMakeRange(0, string.length)) 359 | 360 | return matches > 0 361 | 362 | } 363 | 364 | // This version also allowes to specify case sentitivity 365 | public func =~ (string: String, options: (pattern: String, ignoreCase: Bool)) -> Bool { 366 | 367 | if let matches = ExSwift.regex(options.pattern, ignoreCase: options.ignoreCase)?.numberOfMatchesInString(string, options: nil, range: NSMakeRange(0, string.length)) { 368 | return matches > 0 369 | } 370 | 371 | return false 372 | 373 | } 374 | 375 | // Match against all the alements in an array of String 376 | public func =~ (strings: [String], pattern: String) -> Bool { 377 | 378 | let regex = ExSwift.regex(pattern, ignoreCase: false)! 379 | 380 | return strings.all { $0 =~ regex } 381 | 382 | } 383 | 384 | public func =~ (strings: [String], options: (pattern: String, ignoreCase: Bool)) -> Bool { 385 | 386 | return strings.all { $0 =~ options } 387 | 388 | } 389 | 390 | // Match against any element in an array of String 391 | public func |~ (strings: [String], pattern: String) -> Bool { 392 | 393 | let regex = ExSwift.regex(pattern, ignoreCase: false)! 394 | 395 | return strings.any { $0 =~ regex } 396 | 397 | } 398 | 399 | public func |~ (strings: [String], options: (pattern: String, ignoreCase: Bool)) -> Bool { 400 | 401 | return strings.any { $0 =~ options } 402 | 403 | } 404 | -------------------------------------------------------------------------------- /ExSwiftTests/ArrayExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArrayExtensionsTests.swift 3 | // ExtensionsTests 4 | // 5 | // Created by pNre on 03/06/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | class ArrayExtensionsSpec: QuickSpec { 13 | 14 | var intArray: [Int] = [] 15 | var stringArray: [String] = [] 16 | 17 | override func spec() { 18 | 19 | beforeEach { () -> () in 20 | 21 | self.intArray = [Int](1...5) 22 | self.stringArray = ["A", "B", "C", "D", "E", "F"] 23 | 24 | } 25 | 26 | /** 27 | * Array.get 28 | */ 29 | describe("get") { 30 | 31 | it("in bounds") { 32 | 33 | for i in enumerate(self.intArray) { 34 | expect(self.intArray.get(i.index)) == (i.element) 35 | } 36 | 37 | } 38 | 39 | it("out of bounds") { 40 | 41 | expect(self.intArray.get(-1)).to(beNil()) 42 | 43 | expect(self.intArray.get(self.intArray.count)).to(beNil()) 44 | 45 | } 46 | 47 | } 48 | 49 | /** 50 | * Array.sortUsing 51 | */ 52 | describe("sortUsing") { 53 | 54 | it("default item comparison") { 55 | 56 | expect(self.intArray.sortUsing { $0 }) == [1, 2, 3, 4, 5] 57 | 58 | } 59 | 60 | it("mapped item") { 61 | 62 | expect(self.intArray.sortUsing { $0 % 2 }) == [2, 4, 1, 3, 5] 63 | expect(self.intArray.sortUsing { -$0 }) == self.intArray.reverse() 64 | 65 | } 66 | 67 | } 68 | 69 | /** 70 | * Array.reject 71 | */ 72 | describe("reject") { 73 | 74 | it("all/none") { 75 | 76 | expect(self.intArray.reject { _ in true }) == [] 77 | 78 | expect(self.intArray.reject { _ in false }) == self.intArray 79 | 80 | } 81 | 82 | it("misc") { 83 | 84 | expect(self.intArray.reject { obj in obj > 3 }) == [1, 2, 3] 85 | 86 | expect(self.intArray.reject { obj in obj % 2 == 0 }) == [1, 3, 5] 87 | 88 | } 89 | 90 | } 91 | 92 | /** 93 | * Array.each 94 | */ 95 | describe("each") { 96 | 97 | it("object param") { 98 | 99 | var data = [Int]() 100 | 101 | self.intArray.each { data.append($0) } 102 | 103 | expect(data) == self.intArray 104 | 105 | } 106 | 107 | it("index param") { 108 | 109 | var data = [Int]() 110 | 111 | self.intArray.each { index, obj in data.append(index) } 112 | 113 | expect(data) == [Int](0...4) 114 | 115 | } 116 | 117 | } 118 | 119 | /** 120 | * Array.contains 121 | */ 122 | describe("contains") { 123 | 124 | it("one item") { 125 | 126 | expect(self.intArray.contains(10)).to(beFalse()) 127 | 128 | expect(self.intArray.contains(4)).to(beTrue()) 129 | 130 | } 131 | 132 | it("more than one item") { 133 | 134 | // Contains 1, doesn't contain 10 135 | expect(self.intArray.contains(1, 10)).to(beFalse()) 136 | 137 | // Contains both 1, 2 138 | expect(self.intArray.contains(1, 2)).to(beTrue()) 139 | 140 | // Doesn't contain 6, 7, 8 141 | expect(self.intArray.contains(6, 7, 8)).to(beFalse()) 142 | 143 | } 144 | 145 | it("item of an invalid type") { 146 | 147 | expect(self.intArray.contains("A")).to(beFalse()) 148 | 149 | } 150 | 151 | } 152 | 153 | /** 154 | * Array.indexOf 155 | */ 156 | describe("indexOf") { 157 | 158 | it("with an object") { 159 | 160 | expect(self.intArray.indexOf(1)) == 0 161 | expect(self.intArray.indexOf(5)) == 4 162 | 163 | expect(self.intArray.indexOf(self.intArray[2])) == 2 164 | 165 | expect(self.intArray.indexOf(50)).to(beNil()) 166 | 167 | } 168 | 169 | it("with matching block") { 170 | 171 | expect(self.intArray.indexOf { $0 % 2 == 0 }) == 1 172 | 173 | expect(self.intArray.indexOf { $0 > 10 }).to(beNil()) 174 | 175 | } 176 | 177 | } 178 | 179 | /** 180 | * Array.lastIndexOf 181 | */ 182 | describe("lastIndexOf") { 183 | 184 | var arrayWithDuplicates: [Int] = [] 185 | 186 | beforeEach { 187 | 188 | arrayWithDuplicates = [1, 1, 2, 2, 3, 4, 1] 189 | 190 | } 191 | 192 | it("with an object") { 193 | 194 | expect(arrayWithDuplicates.lastIndexOf(1)) == 6 195 | expect(arrayWithDuplicates.lastIndexOf(4)) == 5 196 | 197 | expect(arrayWithDuplicates.lastIndexOf(arrayWithDuplicates[2])) == 3 198 | 199 | expect(arrayWithDuplicates.lastIndexOf(50)).to(beNil()) 200 | 201 | } 202 | 203 | } 204 | 205 | /** 206 | * Array.max 207 | */ 208 | describe("max") { 209 | 210 | it("comparable array") { 211 | 212 | expect(self.intArray.max() as Int) == 5 213 | 214 | } 215 | 216 | } 217 | 218 | /** 219 | * Array.min 220 | */ 221 | describe("min") { 222 | 223 | it("comparable array") { 224 | 225 | expect(self.intArray.min() as Int) == 1 226 | 227 | } 228 | 229 | } 230 | 231 | /** 232 | * Array.at 233 | */ 234 | describe("at") { 235 | 236 | it("at") { 237 | 238 | expect(self.intArray.at(0, 2)) == [1, 3] 239 | 240 | } 241 | 242 | it("subscript") { 243 | 244 | expect(self.intArray[0, 2, 1]) == [1, 3, 2] 245 | 246 | } 247 | 248 | } 249 | 250 | /** 251 | * Array.unique/uniqueBy 252 | */ 253 | describe("unique/uniqueBy") { 254 | 255 | var arrayWithDuplicates: [Int] = [] 256 | 257 | beforeEach { 258 | 259 | arrayWithDuplicates = [1, 1, 2, 2, 3, 4] 260 | 261 | } 262 | 263 | it("unique") { 264 | 265 | expect(arrayWithDuplicates.unique() as [Int]) == [1, 2, 3, 4] 266 | 267 | } 268 | 269 | it("uniqueBy") { 270 | 271 | expect(arrayWithDuplicates.uniqueBy { $0 }) == arrayWithDuplicates.unique() 272 | 273 | expect(arrayWithDuplicates.uniqueBy { $0 % 2 }) == [1, 2] 274 | 275 | expect(arrayWithDuplicates.uniqueBy { $0 % 3 }) == [1, 2, 3] 276 | 277 | expect(arrayWithDuplicates.uniqueBy { $0 < 3 }) == [1, 3] 278 | 279 | } 280 | 281 | } 282 | 283 | /** 284 | * Array.take/takeWhile 285 | */ 286 | describe("take/takeWhile") { 287 | 288 | it("take") { 289 | 290 | expect(self.intArray.take(2)) == self.intArray[0..<2] 291 | expect(self.intArray.take(0)) == [] 292 | 293 | } 294 | 295 | it("take out of bounds") { 296 | 297 | expect(self.intArray.take(6)) == self.intArray 298 | expect(self.intArray.take(-1)) == [] 299 | 300 | } 301 | 302 | it("takeWhile") { 303 | 304 | expect(self.intArray.takeWhile { $0 < 3 }) == [1, 2] 305 | 306 | expect(self.intArray.takeWhile { $0 % 2 == 0 }) == [] 307 | 308 | } 309 | 310 | } 311 | 312 | /** 313 | * Array.skip/skipWhile 314 | */ 315 | describe("skip/skipWhile") { 316 | 317 | it("skip") { 318 | 319 | expect(self.intArray.skip(2)) == self.intArray[2.. 0 }) == [] 338 | 339 | } 340 | 341 | } 342 | 343 | /** 344 | * Array.countBy 345 | */ 346 | describe("countBy") { 347 | 348 | it("countBy") { 349 | 350 | let count_1 = self.intArray.countBy { 351 | return $0 % 2 == 0 ? "even" : "odd" 352 | } 353 | 354 | expect(count_1) == ["even": 2, "odd": 3] 355 | 356 | let count_2 = self.intArray.countBy { param -> Int in 357 | return 0 358 | } 359 | 360 | expect(count_2) == [0: self.intArray.count] 361 | 362 | } 363 | 364 | } 365 | 366 | /** 367 | * Array.difference 368 | */ 369 | describe("difference") { 370 | 371 | it("method") { 372 | 373 | expect(self.intArray.difference([3, 4])) == [1, 2, 5] 374 | 375 | expect(self.intArray.difference([3], [4])) == [1, 2, 5] 376 | 377 | expect(self.intArray.difference([])) == self.intArray 378 | 379 | } 380 | 381 | it("operator") { 382 | 383 | expect(self.intArray - [3, 4]) == [1, 2, 5] 384 | 385 | expect(self.intArray - [3] - [4]) == [1, 2, 5] 386 | 387 | expect(self.intArray - []) == self.intArray 388 | 389 | } 390 | 391 | } 392 | 393 | /** 394 | * Array.intersection 395 | */ 396 | describe("intersection") { 397 | 398 | it("method") { 399 | 400 | expect(self.intArray.intersection([])) == [] 401 | 402 | expect(self.intArray.intersection([1])) == [1] 403 | 404 | expect(self.intArray.intersection([1, 2], [1, 2], [1, 2, 3])) == [1, 2] 405 | 406 | } 407 | 408 | it("operator") { 409 | 410 | expect(self.intArray & []) == [] 411 | 412 | expect(self.intArray & [1]) == [1] 413 | 414 | expect(self.intArray & [1, 2] & [1, 2] & [1, 2, 3]) == [1, 2] 415 | 416 | } 417 | 418 | } 419 | 420 | /** 421 | * Array.union 422 | */ 423 | describe("union") { 424 | 425 | it("method") { 426 | 427 | expect(self.intArray.union([])) == self.intArray 428 | 429 | expect(self.intArray.union([1])) == self.intArray 430 | 431 | expect(self.intArray.union([1, 5], [6], [7, 4])) == [1, 2, 3, 4, 5, 6, 7] 432 | 433 | } 434 | 435 | it("operator") { 436 | 437 | expect(self.intArray | []) == self.intArray 438 | 439 | expect(self.intArray | [1]) == self.intArray 440 | 441 | expect(self.intArray | [1, 5] | [6] | [7, 4]) == [1, 2, 3, 4, 5, 6, 7] 442 | 443 | } 444 | 445 | } 446 | 447 | /** 448 | * Array duplication 449 | */ 450 | describe("duplication") { 451 | 452 | it("operator") { 453 | 454 | expect([1] * 3) == [1, 1, 1] 455 | 456 | expect(self.intArray * 0) == [] 457 | expect(self.intArray * 1) == self.intArray 458 | 459 | } 460 | 461 | } 462 | 463 | /** 464 | * Array.tail 465 | */ 466 | describe("tail") { 467 | 468 | it("in bounds") { 469 | 470 | expect(self.intArray.tail(0)) == [] 471 | 472 | expect(self.intArray.tail(3)) == [3, 4, 5] 473 | 474 | } 475 | 476 | it("out of bounds") { 477 | 478 | expect(self.intArray.tail(10)) == self.intArray 479 | 480 | } 481 | 482 | } 483 | 484 | /** 485 | * Array.pop 486 | */ 487 | describe("pop") { 488 | 489 | it("non empty array") { 490 | 491 | expect(self.intArray.pop()) == 5 492 | expect(self.intArray) == [1, 2, 3, 4] 493 | 494 | } 495 | 496 | it("empty array") { 497 | 498 | var emptyArray = [Int]() 499 | 500 | expect(emptyArray.pop()).to(beNil()) 501 | 502 | } 503 | 504 | } 505 | 506 | /** 507 | * Array.push 508 | */ 509 | describe("push") { 510 | 511 | it("push") { 512 | 513 | self.intArray.push(10) 514 | 515 | expect(self.intArray.last) == 10 516 | 517 | } 518 | 519 | } 520 | 521 | /** 522 | * Array.shift 523 | */ 524 | describe("shift") { 525 | 526 | it("non empty array") { 527 | 528 | expect(self.intArray.shift()) == 1 529 | expect(self.intArray) == [2, 3, 4, 5] 530 | 531 | } 532 | 533 | it("empty array") { 534 | 535 | var emptyArray = [Int]() 536 | 537 | expect(emptyArray.shift()).to(beNil()) 538 | 539 | } 540 | 541 | } 542 | 543 | /** 544 | * Array.unshift 545 | */ 546 | describe("unshift") { 547 | 548 | it("unshift") { 549 | 550 | self.intArray.unshift(10) 551 | 552 | expect(self.intArray) == [10, 1, 2, 3, 4, 5] 553 | 554 | } 555 | 556 | } 557 | 558 | /** 559 | * Array.remove 560 | */ 561 | describe("remove") { 562 | 563 | it("method") { 564 | 565 | self.intArray.remove(1) 566 | 567 | expect(self.intArray) == [2, 3, 4, 5] 568 | 569 | self.intArray.remove(6) 570 | 571 | expect(self.intArray) == [2, 3, 4, 5] 572 | 573 | } 574 | 575 | it("operator") { 576 | 577 | expect(self.intArray - 1) == [2, 3, 4, 5] 578 | 579 | expect(self.intArray - 6) == [1, 2, 3, 4, 5] 580 | 581 | } 582 | } 583 | 584 | /** 585 | * Array.toDictionary 586 | */ 587 | describe("toDictionary") { 588 | 589 | it("map values to keys") { 590 | 591 | let dictionary = self.intArray.toDictionary { 592 | 593 | return "Number \($0)" 594 | 595 | } 596 | 597 | for i in enumerate(self.intArray) { 598 | 599 | expect(dictionary["Number \(i.element)"]) == i.element 600 | 601 | } 602 | 603 | } 604 | 605 | it("map keys and values") { 606 | 607 | let dictionary = self.intArray.toDictionary { (element) -> (Int, String)? in 608 | 609 | if (element > 2) { 610 | return nil 611 | } 612 | 613 | return (element, "Number \(element)") 614 | 615 | } 616 | 617 | expect(dictionary[1]) == "Number 1" 618 | expect(dictionary[2]) == "Number 2" 619 | 620 | expect(dictionary.keys.array - [1, 2]) == [] 621 | 622 | } 623 | 624 | } 625 | 626 | /** 627 | * Array.implode 628 | */ 629 | describe("implode") { 630 | 631 | it("method") { 632 | 633 | expect(self.stringArray.implode("")) == "ABCDEF" 634 | expect(self.stringArray.implode("*")) == "A*B*C*D*E*F" 635 | 636 | } 637 | 638 | it("operator") { 639 | 640 | expect(self.stringArray * "") == "ABCDEF" 641 | expect(self.stringArray * "*") == "A*B*C*D*E*F" 642 | 643 | } 644 | 645 | } 646 | 647 | /** 648 | * Array.flatten 649 | */ 650 | describe("flatten") { 651 | 652 | var multidimensionalArray: NSArray = [] 653 | 654 | beforeEach { () -> () in 655 | 656 | multidimensionalArray = [5, [6, [7]], 8] 657 | 658 | } 659 | 660 | it("flatten") { 661 | 662 | expect(multidimensionalArray.flatten() as [Int]) == [5, 6, 7, 8] 663 | expect((multidimensionalArray.flattenAny() as! [Int])) == [5, 6, 7, 8] 664 | 665 | } 666 | 667 | } 668 | 669 | /** 670 | * Array.minBy 671 | */ 672 | it("minBy") { 673 | 674 | expect(self.intArray.minBy { $0 }) == 1 675 | 676 | expect(self.intArray.minBy { -$0 }) == 5 677 | 678 | expect(self.intArray.minBy { $0 % 4 }) == 4 679 | 680 | expect(self.intArray.minBy { $0 % 2 }) == 2 681 | 682 | } 683 | 684 | /** 685 | * Array.maxBy 686 | */ 687 | it("maxBy") { 688 | 689 | expect(self.intArray.maxBy { $0 }) == 5 690 | 691 | expect(self.intArray.maxBy { -$0 }) == 1 692 | 693 | expect(self.intArray.maxBy { $0 % 4 }) == 3 694 | 695 | expect(self.intArray.maxBy { $0 % 3 }) == 2 696 | 697 | } 698 | 699 | /** 700 | * Array.zip 701 | */ 702 | it("zip") { 703 | 704 | let zipped = self.stringArray.zip(self.intArray) 705 | 706 | expect(zipped[0].first as? String) == "A" 707 | expect(zipped[0].last as? Int) == 1 708 | 709 | expect(zipped[1].first as? String) == "B" 710 | expect(zipped[1].last as? Int) == 2 711 | 712 | expect(zipped.last!.first as? String) == "E" 713 | expect(zipped.last!.last as? Int) == 5 714 | 715 | } 716 | 717 | /** 718 | * Array.sample 719 | */ 720 | it("sample") { 721 | 722 | // 0 objects 723 | let zero = self.intArray.sample(size: 0) 724 | 725 | expect(zero).to(beEmpty()) 726 | 727 | // 1 object 728 | let one = self.intArray.sample()[0] 729 | 730 | expect(self.intArray).to(contain(one)) 731 | 732 | // n > 1 objects 733 | let sampled = self.intArray.sample(size: 3) 734 | 735 | for item in sampled { 736 | expect(self.intArray).to(contain(item)) 737 | } 738 | 739 | } 740 | 741 | /** 742 | * Array.groupBy 743 | */ 744 | it("groupBy") { 745 | 746 | let group = self.intArray.groupBy(groupingFunction: { 747 | (value: Int) -> Bool in 748 | return value > 3 749 | }) 750 | 751 | expect(group.keys.array) == [false, true] 752 | 753 | expect(group[true]) == [4, 5] 754 | expect(group[false]) == [1, 2, 3] 755 | 756 | } 757 | 758 | /** 759 | * Array.countWhere 760 | */ 761 | it("countWhere") { 762 | 763 | expect(self.intArray.countWhere { value in true }) == self.intArray.count 764 | expect(self.intArray.countWhere { value in false }) == 0 765 | 766 | expect(self.intArray.countWhere { value in value % 2 == 0 }) == 2 767 | 768 | } 769 | 770 | /** 771 | * Array.takeFirst 772 | */ 773 | it("takeFirst") { 774 | 775 | expect(self.intArray.takeFirst { value in true }) == 1 776 | expect(self.intArray.takeFirst { value in false }).to(beNil()) 777 | 778 | expect(self.intArray.takeFirst { $0 % 2 == 0 }) == 2 779 | expect(self.intArray.takeFirst { $0 > 10 }).to(beNil()) 780 | 781 | } 782 | 783 | /** 784 | * Array.fill 785 | */ 786 | it("fill") { 787 | 788 | self.intArray.fill(0) 789 | 790 | for object in self.intArray { 791 | expect(object) == 0 792 | } 793 | 794 | var emptyArray: [String] = [] 795 | emptyArray.fill("x") 796 | 797 | expect(emptyArray) == [] 798 | 799 | } 800 | 801 | /** 802 | * Array.insert 803 | */ 804 | it("insert") { 805 | 806 | self.intArray.insert([6, 7, 8], atIndex: 1) 807 | 808 | expect(self.intArray) == [1, 6, 7, 8, 2, 3, 4, 5] 809 | 810 | self.intArray.insert([9], atIndex: 10) 811 | 812 | expect(self.intArray) == [1, 6, 7, 8, 2, 3, 4, 5, 9] 813 | 814 | self.intArray.insert([0], atIndex: -2) 815 | 816 | expect(self.intArray) == [0, 1, 6, 7, 8, 2, 3, 4, 5, 9] 817 | 818 | } 819 | 820 | /** 821 | * Array[] 822 | */ 823 | describe("subscript") { 824 | 825 | it("half open interval") { 826 | 827 | expect(self.intArray[0..<0]) == [] 828 | expect(self.intArray[0..<1]) == [1] 829 | expect(self.intArray[0..<2]) == [1, 2] 830 | 831 | } 832 | 833 | it("interval") { 834 | 835 | expect(self.intArray[0...0]) == [1] 836 | expect(self.intArray[0...1]) == [1, 2] 837 | expect(self.intArray[0...2]) == [1, 2, 3] 838 | 839 | } 840 | 841 | it("list of indices") { 842 | 843 | expect(self.intArray[0, 1]) == [1, 2] 844 | expect(self.intArray[2, 4]) == [3, 5] 845 | 846 | } 847 | 848 | } 849 | 850 | /** 851 | * Array.shuffled 852 | */ 853 | it("shuffled") { 854 | 855 | expect(self.intArray - self.intArray.shuffled()) == [] 856 | 857 | } 858 | 859 | /** 860 | * Array.shuffle 861 | */ 862 | it("shuffled") { 863 | 864 | var array = self.intArray 865 | 866 | self.intArray.shuffle() 867 | 868 | expect(self.intArray - array) == [] 869 | 870 | } 871 | 872 | /** 873 | * Array.mapFilter 874 | */ 875 | it("mapFilter") { 876 | 877 | let mapped = self.intArray.mapFilter { value in 878 | return value > 3 ? nil : value + 1 879 | } 880 | 881 | expect(mapped) == [2, 3, 4] 882 | 883 | } 884 | 885 | /** 886 | * Array.mapAccum 887 | */ 888 | it("mapAccum") { 889 | 890 | let (accumulated, mapped) = self.intArray.mapAccum(0) { accumulator, value in 891 | return (accumulator + value, value - 1) 892 | } 893 | 894 | expect(accumulated) == self.intArray.reduce(+) 895 | expect(mapped) == self.intArray.map { $0 - 1 } 896 | 897 | } 898 | 899 | /** 900 | * Array.cycle 901 | */ 902 | it("cycle") { 903 | 904 | var sum = 0 905 | 906 | self.intArray.cycle(n: 2) { 907 | sum += $0 908 | } 909 | 910 | expect(sum) == self.intArray.reduce(0, combine: +) * 2 911 | 912 | sum = 0 913 | 914 | self.intArray.cycle(n: 0) { 915 | sum += $0 916 | } 917 | 918 | expect(sum) == 0 919 | 920 | self.intArray.cycle(n: -1) { 921 | sum += $0 922 | } 923 | 924 | expect(sum) == 0 925 | 926 | } 927 | 928 | /** 929 | * Array.partition 930 | */ 931 | it("partition") { 932 | 933 | expect(self.intArray.partition(2)) == [[1, 2], [3, 4]] 934 | 935 | expect(self.intArray.partition(2, step: 1)) == [[1, 2], [2, 3], [3, 4], [4, 5]] 936 | 937 | expect(self.intArray.partition(2, step: 1, pad: nil)) == [[1, 2], [2, 3], [3, 4], [4, 5], [5]] 938 | expect(self.intArray.partition(4, step: 1, pad: nil)) == [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5]] 939 | 940 | expect(self.intArray.partition(2, step: 1, pad: [6, 7, 8])) == [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6]] 941 | expect(self.intArray.partition(4, step: 3, pad: [6])) == [[1, 2, 3, 4], [4, 5, 6]] 942 | 943 | expect(self.intArray.partition(2, pad: [6])) == [[1, 2], [3, 4], [5, 6]] 944 | 945 | expect([1, 2, 3, 4, 5, 6].partition(2, step: 4)) == [[1, 2], [5, 6]] 946 | 947 | expect(self.intArray.partition(10)) == [[]] 948 | 949 | } 950 | 951 | /** 952 | * Array.partitionAll 953 | */ 954 | it("partitionAll") { 955 | 956 | expect(self.intArray.partitionAll(2, step: 1)) == [[1, 2], [2, 3], [3, 4], [4, 5], [5]] 957 | 958 | expect(self.intArray.partitionAll(2)) == [[1, 2], [3, 4], [5]] 959 | 960 | expect(self.intArray.partitionAll(4, step: 1)) == [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5], [4, 5], [5]] 961 | 962 | } 963 | 964 | /** 965 | * Array.partitionBy 966 | */ 967 | it("partitionBy") { 968 | 969 | expect(self.intArray.partitionBy { value in false }) == [self.intArray] 970 | expect(self.intArray.partitionBy { value in true }) == [self.intArray] 971 | 972 | expect([1, 2, 4, 3, 5, 6].partitionBy { $0 % 2 == 0 }) == [[1], [2, 4], [3, 5], [6]] 973 | 974 | expect([1, 7, 3, 6, 10, 12].partitionBy { $0 % 3 }) == [[1, 7], [3, 6], [10], [12]] 975 | 976 | } 977 | 978 | /** 979 | * Array.repeatedCombination 980 | */ 981 | it("repeatedCombination") { 982 | 983 | var array = [1, 2, 3] 984 | 985 | expect(array.repeatedCombination(-1)) == [] 986 | 987 | expect(array.repeatedCombination(0)) == [[]] 988 | 989 | expect(array.repeatedCombination(1)) == [[1], [2], [3]] 990 | expect(array.repeatedCombination(2)) == [[1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 3]] 991 | expect(array.repeatedCombination(3)) == [[1, 1, 1],[1, 1, 2], [1, 1, 3], [1, 2, 2], [1, 2, 3], [1, 3, 3], [2, 2, 2], [2, 2, 3], [2, 3, 3], [3, 3, 3]] 992 | expect(array.repeatedCombination(4)) == [[1, 1, 1, 1], [1, 1, 1, 2], [1, 1, 1, 3], [1, 1, 2, 2], [1, 1, 2, 3], [1, 1, 3, 3], [1, 2, 2, 2], [1, 2, 2, 3], [1, 2, 3, 3], [1, 3, 3, 3], [2, 2, 2, 2], [2, 2, 2, 3], [2, 2, 3, 3], [2, 3, 3, 3], [3, 3, 3, 3]] 993 | 994 | } 995 | 996 | /** 997 | * Array.combination 998 | */ 999 | it("combination") { 1000 | 1001 | expect(self.intArray.combination(-1)) == [] 1002 | 1003 | expect(self.intArray.combination(0)) == [[]] 1004 | 1005 | expect(self.intArray.combination(1)) == [[1], [2], [3], [4], [5]] 1006 | expect(self.intArray.combination(2)) == [[1, 2], [1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5], [3, 4], [3, 5], [4, 5]] 1007 | expect(self.intArray.combination(3)) == [[1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 3, 4], [1, 3, 5], [1, 4, 5], [2, 3, 4], [2, 3, 5], [2, 4, 5], [3, 4, 5]] 1008 | expect(self.intArray.combination(4)) == [[1, 2, 3, 4], [1, 2, 3, 5], [1, 2, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5]] 1009 | expect(self.intArray.combination(5)) == [[1, 2, 3, 4, 5]] 1010 | expect(self.intArray.combination(6)) == [] 1011 | 1012 | } 1013 | 1014 | /** 1015 | * Array.transposition 1016 | */ 1017 | it("transposition") { 1018 | 1019 | var arrays: [[Int]] = [self.intArray] * self.intArray.count 1020 | 1021 | var arraysTransposition: [[Int]] = [].transposition(arrays) 1022 | arrays.eachIndex { i in 1023 | arrays[0].eachIndex { j in 1024 | expect(arrays[i][j]) == arraysTransposition[j][i] 1025 | } 1026 | } 1027 | 1028 | var jagged: [[String]] = [["a", "b", "c"], ["d", "e"], ["f", "g", "h"]] 1029 | var jaggedTransposition = [].transposition(jagged) 1030 | 1031 | expect(jaggedTransposition) == [["a", "d", "f"], ["b", "e", "g"], ["c", "h"]] 1032 | 1033 | } 1034 | 1035 | /** 1036 | * Array.permutation 1037 | */ 1038 | it("permutation") { 1039 | 1040 | 1.upTo(self.intArray.count) { i in 1041 | var permutations: [[Int]] = self.intArray.permutation(i) 1042 | var factorial = 1 1043 | 1044 | for j in 1...i { 1045 | factorial *= j 1046 | } 1047 | 1048 | expect(permutations.count) == self.intArray.combination(i).count * factorial 1049 | 1050 | var mappedPermutations: [Int] = permutations.map({ (i: [Int]) -> [Int] in i.unique()}).flatten() 1051 | var flattenedPermutations: [Int] = permutations.flatten() 1052 | 1053 | expect(mappedPermutations) == flattenedPermutations 1054 | expect(permutations.flatten().all({$0 >= 1 && $0 <= 5})).to(beTrue()) 1055 | expect(permutations.unique()) == permutations 1056 | } 1057 | 1058 | expect(self.intArray.permutation(-1)) == [] 1059 | expect(self.intArray.permutation(0)) == [[]] 1060 | expect(self.intArray.permutation(self.intArray.count + 1)) == [] 1061 | 1062 | } 1063 | 1064 | /** 1065 | * Array.repeatedPermutation 1066 | */ 1067 | it("repeatedPermutation") { 1068 | 1069 | var shortArray = [1, 2] 1070 | 1071 | expect(shortArray.repeatedPermutation(0)) == [] 1072 | expect(shortArray.repeatedPermutation(1)) == [[1], [2]] 1073 | expect(shortArray.repeatedPermutation(2)) == [[1, 1], [1, 2], [2, 1], [2, 2]] 1074 | expect(shortArray.repeatedPermutation(3)) == [[1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 2, 2], [2, 1, 1], [2, 1, 2], [2, 2, 1], [2, 2, 2]] 1075 | 1076 | } 1077 | 1078 | /** 1079 | * Array.bSearch 1080 | */ 1081 | describe("bSearch") { 1082 | 1083 | it("findMin") { 1084 | 1085 | 1.upTo(10) { arraySize in 1086 | 1087 | var testArray: [Int] = [] 1088 | 1089 | 1.upTo(arraySize) { i in 1090 | testArray += [i] 1091 | } 1092 | 1093 | for i in testArray { 1094 | expect(testArray.bSearch({ $0 >= i })) == i 1095 | } 1096 | 1097 | } 1098 | 1099 | expect(self.intArray.bSearch({ $0 >= 101 })).to(beNil()) 1100 | 1101 | expect(self.intArray.bSearch({ $0 >= 0 })) == 1 1102 | 1103 | expect([].bSearch({ true })).to(beNil()) 1104 | 1105 | } 1106 | 1107 | it("findAny") { 1108 | 1109 | 1.upTo(10) { arraySize in 1110 | 1111 | var testArray: [Int] = [] 1112 | 1113 | 1.upTo(arraySize) { i in 1114 | testArray += [i] 1115 | } 1116 | 1117 | for i in testArray { 1118 | expect(testArray.bSearch({ $0 - i })) == i 1119 | } 1120 | 1121 | } 1122 | 1123 | expect(self.intArray.bSearch({ $0 - (self.intArray.max() + 1) })).to(beNil()) 1124 | expect(self.intArray.bSearch({ $0 - (self.intArray.min() - 1) })).to(beNil()) 1125 | 1126 | expect([Int]().bSearch({ $0 })).to(beNil()) 1127 | 1128 | } 1129 | 1130 | } 1131 | 1132 | } 1133 | 1134 | } 1135 | -------------------------------------------------------------------------------- /ExSwiftTests/CharacterExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CharacterExtensions.swift 3 | // ExSwift 4 | // 5 | // Created by Cenny Davidsson on 2014-12-09. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | class CharacterExtensionsSpec: QuickSpec { 13 | 14 | override func spec() { 15 | 16 | it("toInt") { 17 | 18 | expect(Character("7").toInt()) == 7 19 | 20 | expect(Character("a").toInt()).to(beNil()) 21 | 22 | } 23 | 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /ExSwiftTests/DictionaryExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DictionaryExtensionsTests.swift 3 | // ExSwift 4 | // 5 | // Created by pNre on 04/06/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | class DictionaryExtensionsSpec: QuickSpec { 13 | 14 | var dictionary: [String: Int] = [String: Int]() 15 | 16 | override func spec() { 17 | 18 | beforeEach { () -> () in 19 | 20 | self.dictionary = [ 21 | "A": 1, 22 | "B": 2, 23 | "C": 3 24 | ] 25 | 26 | } 27 | 28 | /** 29 | * Dictionary.has 30 | */ 31 | it("has") { 32 | 33 | expect(self.dictionary.has("A")).to(beTrue()) 34 | expect(self.dictionary.has("Z")).to(beFalse()) 35 | 36 | } 37 | 38 | /** 39 | * Dictionary.mapValues 40 | */ 41 | it("mapValues") { 42 | 43 | let mapped = self.dictionary.mapValues({ key, value -> Int in 44 | return value + 1 45 | }) 46 | 47 | expect(mapped) == ["A": 2, "B": 3, "C": 4] 48 | 49 | } 50 | 51 | /** 52 | * Dictionary.map 53 | */ 54 | it("map") { 55 | 56 | let mapped = self.dictionary.map({ key, value -> (String, Int) in return (key + "A", value + 1) }) 57 | 58 | expect(mapped) == ["AA": 2, "BA": 3, "CA": 4] 59 | 60 | } 61 | 62 | /** 63 | * Dictionary.mapFilterValues 64 | */ 65 | it("mapFilterValues") { 66 | 67 | let result = self.dictionary.mapFilterValues { (key, value) -> Int? in 68 | if key == "B" { 69 | return nil 70 | } 71 | 72 | return value + 1 73 | } 74 | 75 | expect(result) == ["A": 2, "C": 4] 76 | 77 | expect(self.dictionary.mapFilterValues { (key, value) -> Int? in nil }) == [String: Int]() 78 | expect(self.dictionary.mapFilterValues { (key, value) -> Int? in value }) == self.dictionary 79 | 80 | } 81 | 82 | /** 83 | * Dictionary.mapFilter 84 | */ 85 | it("mapFilter") { 86 | 87 | let mapped = self.dictionary.mapFilter({ key, value -> (String, String)? in 88 | if key == "C" { 89 | return ("D", key) 90 | } 91 | 92 | return nil 93 | }) 94 | 95 | expect(mapped) == ["D": "C"] 96 | 97 | expect(self.dictionary.mapFilter { (key, value) -> (String, String)? in nil }) == [String: String]() 98 | expect(self.dictionary.mapFilter { (key, value) -> (String, Int)? in (key, value) }) == self.dictionary 99 | 100 | } 101 | 102 | /** 103 | * Dictionary.filter 104 | */ 105 | it("filter") { 106 | 107 | expect(self.dictionary.filter { key, _ in return key != "A" }) == ["B": 2, "C": 3] 108 | 109 | expect(self.dictionary.filter { key, _ in return false }) == [String: Int]() 110 | expect(self.dictionary.filter { key, _ in return true }) == self.dictionary 111 | 112 | } 113 | 114 | /** 115 | * Dictionary.countWhere 116 | */ 117 | it("countWhere") { 118 | 119 | expect(self.dictionary.countWhere { key, _ in return key != "A" }) == 2 120 | 121 | expect(self.dictionary.countWhere { key, _ in return false }) == 0 122 | expect(self.dictionary.countWhere { key, _ in return true }) == 3 123 | 124 | } 125 | 126 | /** 127 | * Dictionary.any 128 | */ 129 | it("any") { 130 | 131 | expect(self.dictionary.any { _, value -> Bool in return value % 2 == 0 }).to(beTrue()) 132 | 133 | expect(self.dictionary.any { _, value -> Bool in return value >= 0 }).to(beTrue()) 134 | 135 | expect(self.dictionary.any { _, value -> Bool in return value < 0 }).to(beFalse()) 136 | 137 | } 138 | 139 | /** 140 | * Dictionary.all 141 | */ 142 | it("all") { 143 | 144 | expect(self.dictionary.all { _, value -> Bool in return value % 2 == 0 }).to(beFalse()) 145 | 146 | expect(self.dictionary.all { _, value -> Bool in return value >= 0 }).to(beTrue()) 147 | 148 | expect(self.dictionary.all { _, value -> Bool in return value < 0 }).to(beFalse()) 149 | 150 | } 151 | 152 | /** 153 | * Dictionary.shift 154 | */ 155 | it("shift") { 156 | 157 | let unshifted = self.dictionary 158 | let (key, value) = self.dictionary.shift()! 159 | 160 | expect(unshifted.keys.array).to(contain(key)) 161 | expect(self.dictionary.keys.array).toNot(contain(key)) 162 | 163 | expect(unshifted[key]) == value 164 | expect(self.dictionary[key]).to(beNil()) 165 | 166 | expect(unshifted.values.array).to(contain(value)) 167 | expect(self.dictionary.values.array).toNot(contain(value)) 168 | 169 | } 170 | 171 | /** 172 | * Dictionary.pick 173 | */ 174 | it("pick") { 175 | 176 | let pick1 = self.dictionary.pick(["A", "C"]) 177 | 178 | expect(pick1) == ["A": 1, "C": 3] 179 | 180 | let pick2 = self.dictionary.pick("A", "C") 181 | 182 | expect(pick2) == pick1 183 | 184 | expect(self.dictionary.pick(["K"])) == [:] 185 | expect(self.dictionary.pick([])) == [:] 186 | expect(self.dictionary.pick()) == [:] 187 | 188 | } 189 | 190 | /** 191 | * Dictionary.groupBy 192 | */ 193 | it("groupBy") { 194 | 195 | let grouped = self.dictionary.groupBy { _, value -> Bool in 196 | return (value % 2 == 0) 197 | } 198 | 199 | expect(grouped.keys.array - [false, true]).to(beEmpty()) 200 | expect(grouped[true]) == [2] 201 | 202 | expect(grouped[false]!.count) == 2 203 | expect(grouped[false]! - [1, 3]).to(beEmpty()) 204 | 205 | } 206 | 207 | /** 208 | * Dictionary.countBy 209 | */ 210 | it("countBy") { 211 | 212 | let grouped = self.dictionary.countBy { _, value -> Bool in 213 | return (value % 2 == 0) 214 | } 215 | 216 | expect(grouped.keys.array - [false, true]).to(beEmpty()) 217 | expect(grouped[true]) == 1 218 | expect(grouped[false]) == 2 219 | 220 | } 221 | 222 | /** 223 | * Dictionary.reduce 224 | */ 225 | it("reduce") { 226 | 227 | let reduced1 = self.dictionary.reduce([Int: String](), combine: { 228 | (var initial: [Int: String], couple: (String, Int)) in 229 | initial.updateValue(couple.0, forKey: couple.1) 230 | return initial 231 | }) 232 | 233 | expect(reduced1) == [2: "B", 3: "C", 1: "A"] 234 | 235 | let reduced2 = self.dictionary.reduce(0, combine: { (initial: Int, couple: (String, Int)) in 236 | return initial + couple.1 237 | }) 238 | 239 | expect(reduced2) == self.dictionary.values.array.reduce(+) 240 | 241 | } 242 | 243 | /** 244 | * Dictionary.difference 245 | */ 246 | describe("difference") { 247 | 248 | let dictionary1 = [ "A": 1, "B": 2, "C": 3 ] 249 | let dictionary2 = [ "A": 1 ] 250 | let dictionary3 = [ "B": 2, "C": 3 ] 251 | 252 | it("operator") { 253 | 254 | expect(self.dictionary - dictionary1) == [:] 255 | expect(self.dictionary - dictionary2) == [ "B": 2, "C": 3 ] 256 | expect(self.dictionary - dictionary3) == [ "A": 1 ] 257 | 258 | expect(dictionary2 - dictionary3) != (dictionary3 - dictionary2) 259 | 260 | expect(dictionary2 - dictionary3) == dictionary2 261 | expect(dictionary2 - [:]) == dictionary2 262 | 263 | } 264 | 265 | it("method") { 266 | 267 | expect(self.dictionary.difference(dictionary1)) == [:] 268 | expect(self.dictionary.difference(dictionary2)) == [ "B": 2, "C": 3 ] 269 | expect(self.dictionary.difference(dictionary3)) == [ "A": 1 ] 270 | 271 | expect(dictionary2.difference(dictionary3)) != dictionary3.difference(dictionary2) 272 | 273 | expect(dictionary2.difference(dictionary3)) == dictionary2 274 | expect(dictionary2.difference([:])) == dictionary2 275 | 276 | } 277 | 278 | } 279 | 280 | /** 281 | * Dictionary.union 282 | */ 283 | describe("union") { 284 | 285 | let dictionary1 = [ "A": 1, "B": 2, "C": 3 ] 286 | let dictionary2 = [ "A": 1 ] 287 | let dictionary3 = [ "B": 2, "C": 3 ] 288 | 289 | it("operator") { 290 | 291 | expect(self.dictionary | dictionary1) == self.dictionary 292 | expect(self.dictionary | dictionary2) == self.dictionary 293 | expect(self.dictionary | dictionary3) == self.dictionary 294 | 295 | expect(dictionary2 | dictionary3) == (dictionary3 | dictionary2) 296 | expect(dictionary2 | dictionary3) == self.dictionary 297 | 298 | expect(dictionary1 | [:]) == dictionary1 299 | 300 | } 301 | 302 | it("method") { 303 | 304 | expect(self.dictionary.union(dictionary1)) == self.dictionary 305 | expect(self.dictionary.union(dictionary2)) == self.dictionary 306 | expect(self.dictionary.union(dictionary3)) == self.dictionary 307 | 308 | expect(dictionary2.union(dictionary3)) == dictionary3.union(dictionary2) 309 | expect(dictionary2.union(dictionary3)) == self.dictionary 310 | 311 | expect(dictionary1.union([:])) == dictionary1 312 | 313 | } 314 | 315 | } 316 | 317 | /** 318 | * Dictionary.intersection 319 | */ 320 | describe("intersection") { 321 | 322 | let dictionary1 = [ "A": 1, "B": 2, "C": 3 ] 323 | let dictionary2 = [ "A": 1 ] 324 | let dictionary3 = [ "B": 2, "C": 3 ] 325 | 326 | it("operator") { 327 | 328 | expect(self.dictionary & dictionary1) == self.dictionary 329 | expect(self.dictionary & dictionary2) == dictionary2 330 | expect(self.dictionary & dictionary3) == dictionary3 331 | 332 | expect(dictionary2 & dictionary3) == (dictionary3 & dictionary2) 333 | expect(dictionary2 & dictionary3) == [String: Int]() 334 | 335 | expect(dictionary1 & [:]) == [:] 336 | 337 | } 338 | 339 | it("method") { 340 | 341 | expect(self.dictionary.intersection(dictionary1)) == self.dictionary 342 | expect(self.dictionary.intersection(dictionary2)) == dictionary2 343 | expect(self.dictionary.intersection(dictionary3)) == dictionary3 344 | 345 | expect(dictionary2.intersection(dictionary3)) == dictionary3.intersection(dictionary2) 346 | expect(dictionary2.intersection(dictionary3)) == [String: Int]() 347 | 348 | expect(dictionary1.intersection([:])) == [String: Int]() 349 | 350 | } 351 | 352 | } 353 | 354 | /** 355 | * Dictionary.toArray 356 | */ 357 | it("toArray") { 358 | 359 | expect(self.dictionary.toArray({ (key, value) -> String in key })) == self.dictionary.keys.array 360 | expect(self.dictionary.toArray({ (key, value) -> Int in value })) == self.dictionary.values.array 361 | 362 | expect(self.dictionary.toArray({ (key, value) -> Bool in false })) == [false, false, false] 363 | 364 | } 365 | 366 | } 367 | 368 | } 369 | -------------------------------------------------------------------------------- /ExSwiftTests/DoubleExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DoubleExtensionsTests.swift 3 | // ExSwift 4 | // 5 | // Created by pNre on 10/07/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | class DoubleExtensionsSpec: QuickSpec { 13 | 14 | override func spec() { 15 | 16 | /** 17 | * Double.abs 18 | */ 19 | it("abs") { 20 | 21 | expect(Double(0).abs()) == Double(0) 22 | 23 | expect(Double(-1).abs()).to(beCloseTo(1, within: 0.001)) 24 | expect(Double(1).abs()).to(beCloseTo(1, within: 0.001)) 25 | 26 | expect(Double(-111.2).abs()).to(beCloseTo(111.2, within: 0.001)) 27 | expect(Double(111.2).abs()).to(beCloseTo(111.2, within: 0.001)) 28 | 29 | } 30 | 31 | /** 32 | * Double.sqrt 33 | */ 34 | it("sqrt") { 35 | 36 | expect(Double(0).sqrt()) == Double(0) 37 | 38 | expect(Double(4).sqrt()).to(beCloseTo(2, within: 0.001)) 39 | expect(Double(111.2).sqrt()).to(beCloseTo(sqrt(111.2), within: 0.001)) 40 | 41 | expect(isnan(Double(-10).sqrt())).to(beTrue()) 42 | 43 | } 44 | 45 | /** 46 | * Double.floor 47 | */ 48 | it("floor") { 49 | 50 | expect(Double(0).floor()) == Double(0) 51 | 52 | expect(Double(4.99999999).floor()).to(beCloseTo(4, within: 0.001)) 53 | expect(Double(4.001).floor()).to(beCloseTo(4, within: 0.001)) 54 | expect(Double(4.5).floor()).to(beCloseTo(4, within: 0.001)) 55 | 56 | expect(Double(-4.99999999).floor()).to(beCloseTo(-5, within: 0.001)) 57 | expect(Double(-4.001).floor()).to(beCloseTo(-5, within: 0.001)) 58 | expect(Double(-4.5).floor()).to(beCloseTo(-5, within: 0.001)) 59 | 60 | } 61 | 62 | /** 63 | * Double.ceil 64 | */ 65 | it("ceil") { 66 | 67 | expect(Double(0).ceil()) == Double(0) 68 | 69 | expect(Double(4.99999999).ceil()).to(beCloseTo(5, within: 0.001)) 70 | expect(Double(4.001).ceil()).to(beCloseTo(5, within: 0.001)) 71 | expect(Double(4.5).ceil()).to(beCloseTo(5, within: 0.001)) 72 | 73 | expect(Double(-4.99999999).ceil()).to(beCloseTo(-4, within: 0.001)) 74 | expect(Double(-4.001).ceil()).to(beCloseTo(-4, within: 0.001)) 75 | expect(Double(-4.5).ceil()).to(beCloseTo(-4, within: 0.001)) 76 | 77 | } 78 | 79 | /** 80 | * Double.round 81 | */ 82 | it("round") { 83 | 84 | expect(Double(0).round()) == Double(0) 85 | 86 | expect(Double(4.99999999).round()).to(beCloseTo(5, within: 0.001)) 87 | expect(Double(4.001).round()).to(beCloseTo(4, within: 0.001)) 88 | expect(Double(4.5).round()).to(beCloseTo(5, within: 0.001)) 89 | 90 | expect(Double(4.3).round()).to(beCloseTo(4, within: 0.001)) 91 | expect(Double(4.7).round()).to(beCloseTo(5, within: 0.001)) 92 | 93 | expect(Double(-4.99999999).round()).to(beCloseTo(-5, within: 0.001)) 94 | expect(Double(-4.001).round()).to(beCloseTo(-4, within: 0.001)) 95 | expect(Double(-4.5).round()).to(beCloseTo(-5, within: 0.001)) 96 | 97 | } 98 | 99 | /** 100 | * Double.roundToNearest 101 | */ 102 | it("roundToNearest") { 103 | 104 | expect(2.5.roundToNearest(0.3)).to(beCloseTo(2.4, within: 0.01)) 105 | expect(0.roundToNearest(0.3)).to(beCloseTo(0.0, within: 0.01)) 106 | expect(4.0.roundToNearest(2)).to(beCloseTo(4.0, within: 0.01)) 107 | expect(10.0.roundToNearest(3)).to(beCloseTo(9.0, within: 0.01)) 108 | expect(-2.0.roundToNearest(3)).to(beCloseTo(-3.0, within: 0.01)) 109 | 110 | } 111 | 112 | /** 113 | * Double.clamp 114 | */ 115 | it("clamp") { 116 | 117 | expect(Double(0.25).clamp(0, 0.5)).to(beCloseTo(0.25, within: 0.01)) 118 | expect(Double(2).clamp(0, 0.5)).to(beCloseTo(0.5, within: 0.01)) 119 | expect(Double(-2).clamp(0, 0.5)).to(beCloseTo(0, within: 0.01)) 120 | 121 | } 122 | 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /ExSwiftTests/ExSwiftBoolTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExSwiftBoolTests.swift 3 | // ExSwift 4 | // 5 | // Created by Hernandez Alvarez, David on 2/10/15. 6 | // Copyright (c) 2015 pNre. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class ExSwiftBoolTests: XCTestCase { 12 | 13 | func testToogleTrue() { 14 | var bool: Bool = false 15 | XCTAssertTrue(bool.toggle(), "Bool did not toogle to true") 16 | } 17 | 18 | func testToogleFalse() { 19 | var bool: Bool = true 20 | XCTAssertFalse(bool.toggle(), "Bool did not toogle to false") 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /ExSwiftTests/ExSwiftTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExSwiftTests.swift 3 | // ExSwift 4 | // 5 | // Created by pNre on 07/06/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | class ExSwiftSpec: QuickSpec { 13 | 14 | override func spec() { 15 | 16 | it("after") { 17 | 18 | let f = ExSwift.after(2, function: { () -> Bool in return true }) 19 | 20 | expect(f()).to(beNil()) 21 | expect(f()).to(beNil()) 22 | 23 | expect(f()).to(beTrue()) 24 | 25 | var called = false 26 | let g = ExSwift.after(2, function: { called = true }) 27 | 28 | g() 29 | 30 | expect(called).to(beFalse()) 31 | 32 | g() 33 | 34 | expect(called).to(beFalse()) 35 | 36 | g() 37 | 38 | expect(called).to(beTrue()) 39 | 40 | } 41 | 42 | it("once") { 43 | 44 | var seq = [1, 2, 3, 4].generate() 45 | 46 | let g = Ex.once { Void -> Int in 47 | return seq.next()! 48 | } 49 | 50 | expect(g()) == 1 51 | expect(g()) == 1 52 | 53 | } 54 | 55 | it("partial") { 56 | 57 | let add = { (params: Int...) -> Int in 58 | return params.reduce(0, combine: +) 59 | } 60 | 61 | let add5 = ExSwift.partial(add, 5) 62 | 63 | expect(add5(10)) == 15 64 | expect(add5(1, 2)) == 8 65 | 66 | } 67 | 68 | it("bind") { 69 | 70 | let concat = { (params: String...) -> String in 71 | return params.implode(" ")! 72 | } 73 | 74 | let helloWorld = ExSwift.bind(concat, "Hello", "World") 75 | 76 | expect(helloWorld()) == "Hello World" 77 | 78 | } 79 | 80 | it("cached") { 81 | 82 | var calls = 0 83 | 84 | // Slow Fibonacci 85 | var fib: ((Int...) -> Int)! 86 | fib = { (params: Int...) -> Int in 87 | let n = params[0] 88 | 89 | calls++ 90 | 91 | if n <= 1 { 92 | return n 93 | } 94 | return fib(n - 1) + fib(n - 2) 95 | } 96 | 97 | let fibonacci = Ex.cached(fib) 98 | 99 | // This one is computed (fib is called 465 times) 100 | fibonacci(12) 101 | expect(calls) == 465 102 | 103 | // The results is taken from the cache (fib is not called again) 104 | fibonacci(12) 105 | expect(calls) == 465 106 | 107 | } 108 | 109 | describe("operators") { 110 | 111 | it("spaceship") { 112 | 113 | expect(4 <=> 5) == -1 114 | expect(5 <=> 4) == 1 115 | expect(4 <=> 4) == 0 116 | 117 | } 118 | 119 | } 120 | 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /ExSwiftTests/FloatExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FloatExtensionsTests.swift 3 | // ExSwift 4 | // 5 | // Created by pNre on 04/06/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | class FloatExtensionsSpec: QuickSpec { 13 | 14 | override func spec() { 15 | 16 | /** 17 | * Float.abs 18 | */ 19 | it("abs") { 20 | 21 | expect(Float(0).abs()) == Float(0) 22 | 23 | expect(Float(-1).abs()).to(beCloseTo(1, within: 0.001)) 24 | expect(Float(1).abs()).to(beCloseTo(1, within: 0.001)) 25 | 26 | expect(Float(-111.2).abs()).to(beCloseTo(111.2, within: 0.001)) 27 | expect(Float(111.2).abs()).to(beCloseTo(111.2, within: 0.001)) 28 | 29 | } 30 | 31 | /** 32 | * Float.sqrt 33 | */ 34 | it("sqrt") { 35 | 36 | expect(Float(0).sqrt()) == Float(0) 37 | 38 | expect(Float(4).sqrt()).to(beCloseTo(2, within: 0.001)) 39 | expect(Float(111.2).sqrt()).to(beCloseTo(sqrt(111.2), within: 0.001)) 40 | 41 | expect(isnan(Float(-10).sqrt())).to(beTrue()) 42 | 43 | } 44 | 45 | /** 46 | * Float.floor 47 | */ 48 | it("floor") { 49 | 50 | expect(Float(0).floor()) == Float(0) 51 | 52 | expect(Float(4.99999).floor()).to(beCloseTo(4, within: 0.001)) 53 | expect(Float(4.001).floor()).to(beCloseTo(4, within: 0.001)) 54 | expect(Float(4.5).floor()).to(beCloseTo(4, within: 0.001)) 55 | 56 | expect(Float(-4.99999).floor()).to(beCloseTo(-5, within: 0.001)) 57 | expect(Float(-4.001).floor()).to(beCloseTo(-5, within: 0.001)) 58 | expect(Float(-4.5).floor()).to(beCloseTo(-5, within: 0.001)) 59 | 60 | } 61 | 62 | /** 63 | * Float.ceil 64 | */ 65 | it("ceil") { 66 | 67 | expect(Float(0).ceil()) == Float(0) 68 | 69 | expect(Float(4.99999).ceil()).to(beCloseTo(5, within: 0.001)) 70 | expect(Float(4.001).ceil()).to(beCloseTo(5, within: 0.001)) 71 | expect(Float(4.5).ceil()).to(beCloseTo(5, within: 0.001)) 72 | 73 | expect(Float(-4.99999).ceil()).to(beCloseTo(-4, within: 0.001)) 74 | expect(Float(-4.001).ceil()).to(beCloseTo(-4, within: 0.001)) 75 | expect(Float(-4.5).ceil()).to(beCloseTo(-4, within: 0.001)) 76 | 77 | } 78 | 79 | /** 80 | * Float.round 81 | */ 82 | it("round") { 83 | 84 | expect(Float(0).round()) == Float(0) 85 | 86 | expect(Float(4.99999999).round()).to(beCloseTo(5, within: 0.001)) 87 | expect(Float(4.001).round()).to(beCloseTo(4, within: 0.001)) 88 | expect(Float(4.5).round()).to(beCloseTo(5, within: 0.001)) 89 | 90 | expect(Float(4.3).round()).to(beCloseTo(4, within: 0.001)) 91 | expect(Float(4.7).round()).to(beCloseTo(5, within: 0.001)) 92 | 93 | expect(Float(-4.99999999).round()).to(beCloseTo(-5, within: 0.001)) 94 | expect(Float(-4.001).round()).to(beCloseTo(-4, within: 0.001)) 95 | expect(Float(-4.5).round()).to(beCloseTo(-5, within: 0.001)) 96 | 97 | } 98 | 99 | /** 100 | * Float.roundToNearest 101 | */ 102 | it("roundToNearest") { 103 | 104 | expect(2.5.roundToNearest(0.3)).to(beCloseTo(2.4, within: 0.01)) 105 | expect(0.roundToNearest(0.3)).to(beCloseTo(0.0, within: 0.01)) 106 | expect(4.0.roundToNearest(2)).to(beCloseTo(4.0, within: 0.01)) 107 | expect(10.0.roundToNearest(3)).to(beCloseTo(9.0, within: 0.01)) 108 | expect(-2.0.roundToNearest(3)).to(beCloseTo(-3.0, within: 0.01)) 109 | 110 | } 111 | 112 | /** 113 | * Float.clamp 114 | */ 115 | it("clamp") { 116 | 117 | expect(Float(0.25).clamp(0, 0.5)).to(beCloseTo(0.25, within: 0.01)) 118 | expect(Float(2).clamp(0, 0.5)).to(beCloseTo(0.5, within: 0.01)) 119 | expect(Float(-2).clamp(0, 0.5)).to(beCloseTo(0, within: 0.01)) 120 | 121 | } 122 | 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /ExSwiftTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | co.pNre.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ExSwiftTests/IntExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IntExtensionsTests.swift 3 | // ExSwift 4 | // 5 | // Created by pNre on 03/06/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | class IntExtensionsSpec: QuickSpec { 13 | 14 | override func spec() { 15 | 16 | /** 17 | * Int.times 18 | */ 19 | describe("times") { 20 | 21 | it("iteration") { 22 | 23 | var count = 0 24 | 25 | 5.times { count++ } 26 | expect(count).to(equal(5)) 27 | 28 | 0.times { count++ } 29 | expect(count).to(equal(5)) 30 | 31 | } 32 | 33 | it("index") { 34 | 35 | var indexes = [Int]() 36 | 5.times(indexes.append) 37 | 38 | expect(indexes) == [0, 1, 2, 3, 4] 39 | 40 | } 41 | 42 | } 43 | 44 | /** 45 | * Int.even 46 | */ 47 | it("even") { 48 | 49 | expect((-1).isEven()).to(beFalse()) 50 | expect(3.isEven()).to(beFalse()) 51 | 52 | expect((-2).isEven()).to(beTrue()) 53 | expect(4.isEven()).to(beTrue()) 54 | 55 | } 56 | 57 | /** 58 | * Int.odd 59 | */ 60 | it("odd") { 61 | 62 | expect((-1).isOdd()).to(beTrue()) 63 | expect(3.isOdd()).to(beTrue()) 64 | 65 | expect((-2).isOdd()).to(beFalse()) 66 | expect(4.isOdd()).to(beFalse()) 67 | 68 | } 69 | 70 | /** 71 | * Int.random 72 | */ 73 | it("random") { 74 | 75 | var indexes = [Int]() 76 | 10.times { indexes.append(Int.random(min: 5, max: 25)) } 77 | 78 | expect(indexes).to(allPass { $0 >= 5 && $0 <= 25 }) 79 | 80 | } 81 | 82 | /** 83 | * Int.upTo 84 | */ 85 | it("upTo") { 86 | 87 | var result = [Int]() 88 | 5.upTo(10, function: result.append) 89 | 90 | expect(result) == [Int](5...10) 91 | 92 | } 93 | 94 | /** 95 | * Int.downTo 96 | */ 97 | it("downTo") { 98 | 99 | var result = [Int]() 100 | 5.downTo(0, function: result.append) 101 | 102 | expect(result) == [5, 4, 3, 2, 1, 0] 103 | 104 | } 105 | 106 | /** 107 | * Int.clamp 108 | */ 109 | it("clamp") { 110 | 111 | expect(5.clamp(0...4)) == 4 112 | expect(3.clamp(0...4)) == 3 113 | expect(1.clamp(2...4)) == 2 114 | 115 | } 116 | 117 | /** 118 | * Int.isIn 119 | */ 120 | it("isIn") { 121 | 122 | expect(2.isIn(0..<3)).to(beTrue()) 123 | expect(2.isIn(0..<3, strict: true)).to(beFalse()) 124 | 125 | expect(0.isIn(0..<3)).to(beTrue()) 126 | expect(0.isIn(0..<3, strict: true)).to(beFalse()) 127 | 128 | expect(2.isIn(0...2)).to(beTrue()) 129 | expect(2.isIn(0...2, strict: true)).to(beFalse()) 130 | 131 | } 132 | 133 | /** 134 | * Int.explode 135 | */ 136 | it("explode") { 137 | 138 | expect(0.digits()) == [0] 139 | 140 | expect(1234.digits()) == [1, 2, 3, 4] 141 | 142 | } 143 | 144 | /** 145 | * Int.gcd 146 | */ 147 | it("gcd") { 148 | 149 | expect(3.gcd(6)) == 3 150 | 151 | expect(6.gcd(3)) == 3 152 | 153 | expect(6124.gcd(342)) == 2 154 | 155 | expect(342.gcd(6124)) == 2 156 | 157 | } 158 | 159 | /** 160 | * Int.lcm 161 | */ 162 | it("lcm") { 163 | 164 | expect(3.lcm(4)) == 12 165 | 166 | expect(4.lcm(3)) == 12 167 | 168 | } 169 | 170 | /** 171 | * Int.abs 172 | */ 173 | it("abs") { 174 | 175 | expect((-1).abs()) == 1 176 | expect((-10).abs()) == 10 177 | 178 | expect(1.abs()) == 1 179 | 180 | expect(0.abs()) == 0 181 | 182 | } 183 | 184 | describe("time") { 185 | 186 | it("years") { 187 | 188 | expect(0.years) == 0 189 | expect(1.year) == 31536000 190 | expect(111.years) == 31536000 * 111 191 | 192 | expect(-1.year) == -31536000 193 | expect(-111.years) == -31536000 * 111 194 | 195 | expect(0.year) == 0.years 196 | expect(1.year) == 1.years 197 | expect(1010.year) == 1010.years 198 | 199 | } 200 | 201 | it("days") { 202 | 203 | expect(0.days) == 0 204 | expect(1.day) == 86400 205 | expect(111.days) == 86400 * 111 206 | 207 | expect(-1.day) == -86400 208 | expect(-111.days) == -86400 * 111 209 | 210 | expect(0.day) == 0.days 211 | expect(1.day) == 1.days 212 | expect(1010.day) == 1010.days 213 | 214 | } 215 | 216 | it("hours") { 217 | 218 | expect(0.hours) == 0 219 | expect(1.hour) == 3600 220 | expect(111.hours) == 3600 * 111 221 | 222 | expect(-1.hour) == -3600 223 | expect(-111.hours) == -3600 * 111 224 | 225 | expect(0.hour) == 0.hours 226 | expect(1.hour) == 1.hours 227 | expect(1010.hour) == 1010.hours 228 | 229 | } 230 | 231 | it("minutes") { 232 | 233 | expect(0.minutes) == 0 234 | expect(1.minute) == 60 235 | expect(111.minutes) == 60 * 111 236 | 237 | expect(-1.minute) == -60 238 | expect(-111.minutes) == -60 * 111 239 | 240 | expect(0.minute) == 0.minutes 241 | expect(1.minute) == 1.minutes 242 | expect(1010.minute) == 1010.minutes 243 | 244 | } 245 | 246 | it("seconds") { 247 | 248 | expect(0.seconds) == 0 249 | expect(1.second) == 1 250 | expect(111.seconds) == 111 251 | 252 | expect(-1.second) == -1 253 | expect(-111.seconds) == -111 254 | 255 | expect(0.second) == 0.seconds 256 | expect(1.second) == 1.seconds 257 | expect(1010.second) == 1010.seconds 258 | 259 | } 260 | 261 | } 262 | 263 | } 264 | 265 | } 266 | -------------------------------------------------------------------------------- /ExSwiftTests/NSArrayExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSArrayExtensionsTests.swift 3 | // ExSwift 4 | // 5 | // Created by pNre on 10/06/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | class NSArrayExtensionsSpec: QuickSpec { 13 | 14 | override func spec() { 15 | 16 | it("cast") { 17 | 18 | let array: NSArray = ["A", 10, "B", "C", false] 19 | 20 | expect(array.cast() as [NSNumber]) == [10, 0] 21 | expect(array.cast() as [NSString]) == ["A", "B", "C"] 22 | 23 | expect(array.cast() as [Int]) == [10, 0] 24 | 25 | } 26 | 27 | it("flatten") { 28 | 29 | let array = [5, [6, ["A", 7]], 8] 30 | 31 | expect(array.flatten() as [NSNumber]) == [5, 6, 7, 8] 32 | expect(array.flatten() as [Int]) == [5, 6, 7, 8] 33 | expect(array.flatten() as [String]) == ["A"] 34 | 35 | expect(array.flattenAny() as? [NSObject]) == [5, 6, "A", 7, 8] 36 | 37 | } 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /ExSwiftTests/NSDateExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSDateExtensionsTests.swift 3 | // ExSwift 4 | // 5 | // Created by Piergiuseppe Longo on 23/11/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | class NSDateExtensionsSpec: QuickSpec { 13 | 14 | let dateFormatter = NSDateFormatter() 15 | 16 | var startDate: NSDate? 17 | 18 | override func spec() { 19 | 20 | beforeSuite { 21 | 22 | self.dateFormatter.dateFormat = "dd/MM/yyyy HH:mm:ss" 23 | 24 | } 25 | 26 | beforeEach { 27 | 28 | self.startDate = self.dateFormatter.dateFromString("30/11/1988 00:00:00") 29 | 30 | } 31 | 32 | describe("manipulation") { 33 | 34 | it("addSeconds") { 35 | 36 | var expectedDate = self.dateFormatter.dateFromString("30/11/1988 00:00:42") 37 | 38 | expect(self.startDate?.addSeconds(42)) == expectedDate 39 | expect(self.startDate?.add(seconds: 42)) == expectedDate 40 | 41 | expectedDate = self.dateFormatter.dateFromString("29/11/1988 23:59:18") 42 | 43 | expect(self.startDate?.addSeconds(-42)) == expectedDate 44 | expect(self.startDate?.add(seconds: -42)) == expectedDate 45 | 46 | } 47 | 48 | it("addMinutes") { 49 | 50 | var expectedDate = self.dateFormatter.dateFromString("30/11/1988 00:42:00") 51 | 52 | expect(self.startDate?.addMinutes(42)) == expectedDate 53 | expect(self.startDate?.add(minutes: 42)) == expectedDate 54 | 55 | expectedDate = self.dateFormatter.dateFromString("29/11/1988 23:18:00") 56 | 57 | expect(self.startDate?.addMinutes(-42)) == expectedDate 58 | expect(self.startDate?.add(minutes: -42)) == expectedDate 59 | 60 | } 61 | 62 | it("addHours") { 63 | 64 | var expectedDate = self.dateFormatter.dateFromString("01/12/1988 18:00:00") 65 | 66 | expect(self.startDate?.addHours(42)) == expectedDate 67 | expect(self.startDate?.add(hours: 42)) == expectedDate 68 | 69 | expectedDate = self.dateFormatter.dateFromString("28/11/1988 06:00:00") 70 | 71 | expect(self.startDate?.addHours(-42)) == expectedDate 72 | expect(self.startDate?.add(hours: -42)) == expectedDate 73 | 74 | } 75 | 76 | it("addDays") { 77 | 78 | var expectedDate = self.dateFormatter.dateFromString("02/12/1988 00:00:00") 79 | 80 | expect(self.startDate?.addDays(2)) == expectedDate 81 | expect(self.startDate?.add(days: 2)) == expectedDate 82 | 83 | expectedDate = self.dateFormatter.dateFromString("19/10/1988 00:00:00") 84 | 85 | expect(self.startDate?.addDays(-42)) == expectedDate 86 | expect(self.startDate?.add(days: -42)) == expectedDate 87 | 88 | } 89 | 90 | it("addWeeks") { 91 | 92 | var expectedDate = self.dateFormatter.dateFromString("7/12/1988 00:00:00") 93 | 94 | expect(self.startDate?.addWeeks(1)) == expectedDate 95 | expect(self.startDate?.add(weeks: 1)) == expectedDate 96 | 97 | expectedDate = self.dateFormatter.dateFromString("23/11/1988 00:00:00") 98 | 99 | expect(self.startDate?.addWeeks(-1)) == expectedDate 100 | expect(self.startDate?.add(weeks: -1)) == expectedDate 101 | 102 | } 103 | 104 | it("addMonths") { 105 | 106 | var expectedDate = self.dateFormatter.dateFromString("30/12/1988 00:00:00") 107 | 108 | expect(self.startDate?.addMonths(1)) == expectedDate 109 | expect(self.startDate?.add(months: 1)) == expectedDate 110 | 111 | expectedDate = self.dateFormatter.dateFromString("30/10/1988 00:00:00") 112 | 113 | expect(self.startDate?.addMonths(-1)) == expectedDate 114 | expect(self.startDate?.add(months: -1)) == expectedDate 115 | 116 | } 117 | 118 | it("addYears") { 119 | 120 | var expectedDate = self.dateFormatter.dateFromString("30/11/1989 00:00:00") 121 | 122 | expect(self.startDate?.addYears(1)) == expectedDate 123 | expect(self.startDate?.add(years: 1)) == expectedDate 124 | 125 | expectedDate = self.dateFormatter.dateFromString("30/11/1987 00:00:00") 126 | 127 | expect(self.startDate?.addYears(-1)) == expectedDate 128 | expect(self.startDate?.add(years: -1)) == expectedDate 129 | 130 | } 131 | 132 | it("add") { 133 | 134 | var expectedDate = self.dateFormatter.dateFromString("10/01/1990 18:42:42") 135 | 136 | expect(self.startDate?.add(seconds: 42, minutes: 42, hours: 42, days: 2, weeks: 1 , months: 1, years: 1)) == expectedDate 137 | 138 | expectedDate = self.dateFormatter.dateFromString("20/10/1987 22:17:18") 139 | 140 | expect(self.startDate?.add(seconds: -42, minutes: -42, hours: -1, days: -2, weeks: -1 , months: -1, years: -1)) == expectedDate 141 | 142 | } 143 | 144 | } 145 | 146 | describe("comparison") { 147 | 148 | it("isAfter") { 149 | 150 | let date = NSDate() 151 | 152 | var futureDate = date.addSeconds(42) 153 | var pastDate = date.addSeconds(-42) 154 | 155 | expect(futureDate.isAfter(date)).to(beTrue()) 156 | expect(date.isAfter(date)).to(beFalse()) 157 | expect(pastDate.isAfter(date)).to(beFalse()) 158 | 159 | } 160 | 161 | it("isBefore") { 162 | 163 | let date = NSDate() 164 | 165 | var futureDate = date.addSeconds(42) 166 | var pastDate = date.addSeconds(-42) 167 | 168 | expect(futureDate.isBefore(date)).to(beFalse()) 169 | expect(date.isBefore(date)).to(beFalse()) 170 | expect(pastDate.isBefore(date)).to(beTrue()) 171 | 172 | } 173 | 174 | } 175 | 176 | it("components properties") { 177 | 178 | expect(self.startDate!.year) == 1988 179 | expect(self.startDate!.month) == 11 180 | expect(self.startDate!.days) == 30 181 | expect(self.startDate!.hours) == 0 182 | expect(self.startDate!.minutes) == 0 183 | expect(self.startDate!.seconds) == 0 184 | expect(self.startDate!.weekday) == 4 185 | expect(self.startDate!.weekMonth) == 5 186 | 187 | } 188 | 189 | describe("comparable") { 190 | 191 | it("sorting") { 192 | 193 | let firstDate = self.startDate!.addSeconds(0) 194 | let secondDate = self.startDate!.addSeconds(42) 195 | let thirdDate = self.startDate!.addSeconds(-42) 196 | let fourthDate = self.startDate!.addSeconds(-84) 197 | let fifthDate = self.startDate!.addSeconds(84) 198 | 199 | var dates = [thirdDate, secondDate, firstDate, fourthDate, fifthDate] 200 | 201 | let expected = [fifthDate, secondDate, firstDate, thirdDate, fourthDate] 202 | let expectedReverded = expected.reverse() 203 | 204 | for i in 0 ... 42 { 205 | dates.shuffle() 206 | 207 | dates.sort( { $0 > $1 } ) 208 | expect(dates) == expected 209 | 210 | dates.sort( { $0 < $1 } ) 211 | expect(dates) == expectedReverded 212 | } 213 | 214 | } 215 | 216 | it("comparable") { 217 | 218 | let date = self.startDate!.addSeconds(-42) 219 | let anotherDate = self.startDate!.addSeconds(42) 220 | let shouldBeTheSameDate = NSDate(timeInterval: 0, sinceDate: self.startDate!) 221 | 222 | expect(self.startDate) == shouldBeTheSameDate 223 | 224 | expect(self.startDate) > date 225 | expect(self.startDate) >= date 226 | 227 | expect(self.startDate) <= anotherDate 228 | expect(self.startDate) < anotherDate 229 | 230 | expect(date) != self.startDate 231 | expect(anotherDate) != self.startDate 232 | 233 | } 234 | 235 | } 236 | 237 | it("arithmetic") { 238 | 239 | let date = NSDate() as NSDate 240 | 241 | expect(date.timeIntervalSinceDate(date - 1.hour)) == 1.hour 242 | expect(date.timeIntervalSinceDate(date + 1.hour)) == -1.hour 243 | 244 | var otherDate = date 245 | 246 | otherDate -= 1.minute 247 | expect(otherDate) !== date 248 | expect(date.timeIntervalSinceDate(otherDate)) == 1.minute 249 | 250 | otherDate += 1.hour 251 | expect(date.timeIntervalSinceDate(otherDate)) == 1.minute - 1.hour 252 | 253 | } 254 | 255 | } 256 | 257 | } 258 | 259 | -------------------------------------------------------------------------------- /ExSwiftTests/RangeExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RangeExtensionsTests.swift 3 | // ExSwift 4 | // 5 | // Created by pNre on 04/06/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | class RangeExtensionsSpec: QuickSpec { 13 | 14 | override func spec() { 15 | 16 | /** 17 | * Range.times 18 | */ 19 | it("times") { 20 | 21 | var count: Int = 0 22 | (2..<4).times { count++ } 23 | 24 | expect(count) == 2 25 | 26 | count = 0 27 | (2...4).times { count++ } 28 | 29 | expect(count) == 3 30 | 31 | } 32 | 33 | /** 34 | * Range.each 35 | */ 36 | it("each") { 37 | 38 | var items = [Int]() 39 | (0..<2).each(items.append) 40 | 41 | expect(items) == [0, 1] 42 | 43 | (0..<0).each { (current: Int) in 44 | fail() 45 | } 46 | 47 | } 48 | 49 | } 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /ExSwiftTests/SequenceExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SequenceExtensionsTests.swift 3 | // ExSwift 4 | // 5 | // Created by Colin Eberhardt on 24/06/2014. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | 10 | import Quick 11 | import Nimble 12 | 13 | class SequenceExtensionsSpec: QuickSpec { 14 | 15 | var sequence = 1...5 16 | var emptySequence = 1..<1 17 | 18 | override func spec() { 19 | 20 | it("first") { 21 | 22 | expect(SequenceOf(self.sequence).first) == 1 23 | 24 | expect(SequenceOf(self.emptySequence).first).to(beNil()) 25 | 26 | } 27 | 28 | it("contains") { 29 | 30 | expect(SequenceOf(self.sequence).contains(1)).to(beTrue()) 31 | expect(SequenceOf(self.sequence).contains(56)).to(beFalse()) 32 | 33 | } 34 | 35 | it("indexOf") { 36 | 37 | expect(SequenceOf(self.sequence).indexOf(2)) == 1 38 | expect(SequenceOf(self.sequence).indexOf(56)).to(beNil()) 39 | 40 | } 41 | 42 | it("skip") { 43 | 44 | expect(Array(SequenceOf(self.sequence).skip(0))) == Array(SequenceOf(self.sequence)) 45 | 46 | expect(Array(SequenceOf(self.sequence).skip(2))) == [3, 4, 5] 47 | 48 | expect(Array(SequenceOf(self.sequence).skip(8))) == [] 49 | 50 | } 51 | 52 | it("skipWhile") { 53 | 54 | expect(Array(SequenceOf(self.sequence).skipWhile { $0 < 3 })) == [3, 4, 5] 55 | 56 | expect(Array(SequenceOf(self.sequence).skipWhile { $0 < 20 })) == [] 57 | 58 | } 59 | 60 | it("take") { 61 | 62 | expect(Array(SequenceOf(self.sequence).take(0))) == [] 63 | 64 | expect(Array(SequenceOf(self.sequence).take(2))) == [1, 2] 65 | 66 | expect(Array(SequenceOf(self.sequence).take(20))) == Array(SequenceOf(self.sequence)) 67 | 68 | } 69 | 70 | it("takeWhile") { 71 | 72 | expect(Array(SequenceOf(self.sequence).takeWhile { $0 != 3 })) == [1, 2] 73 | 74 | expect(Array(SequenceOf(self.sequence).takeWhile { $0 == 7 })) == [] 75 | 76 | expect(Array(SequenceOf(self.sequence).takeWhile { $0 != 7 })) == [1, 2, 3, 4, 5] 77 | 78 | } 79 | 80 | describe("get") { 81 | 82 | it("index") { 83 | 84 | expect(SequenceOf(self.sequence).get(3)) == 3 85 | expect(SequenceOf(self.sequence).get(22)).to(beNil()) 86 | 87 | } 88 | 89 | it("range") { 90 | 91 | expect(Array(SequenceOf(self.sequence).get(1..<3))) == [2, 3] 92 | 93 | expect(Array(SequenceOf(self.sequence).get(0..<0))) == [] 94 | 95 | expect(Array(SequenceOf(self.sequence).get(10..<15))) == [] 96 | 97 | } 98 | 99 | } 100 | 101 | it("any") { 102 | 103 | expect(SequenceOf(self.sequence).any { $0 == 1 }).to(beTrue()) 104 | 105 | expect(SequenceOf(self.sequence).any { $0 == 77 }).to(beFalse()) 106 | 107 | } 108 | 109 | it("filter") { 110 | 111 | var evens = SequenceOf(self.sequence).filter { $0 % 2 == 0 } 112 | expect(Array(evens)) == [2, 4] 113 | 114 | var odds = SequenceOf(self.sequence).filter { $0 % 2 == 1 } 115 | expect(Array(odds)) == [1, 3, 5] 116 | 117 | var all = SequenceOf(self.sequence).filter { $0 < 10 } 118 | expect(Array(all)) == [1, 2, 3, 4, 5] 119 | 120 | var none = SequenceOf(self.sequence).filter { $0 > 10 } 121 | expect(Array(none)) == [] 122 | 123 | } 124 | 125 | it("reject") { 126 | 127 | var rejected = SequenceOf(self.sequence).reject { $0 == 3 } 128 | expect(Array(rejected)) == [1, 2, 4, 5] 129 | 130 | rejected = SequenceOf(self.sequence).reject { $0 == 1 } 131 | expect(Array(rejected)) == [2, 3, 4, 5] 132 | 133 | rejected = SequenceOf(self.sequence).reject { $0 == 10 } 134 | expect(Array(rejected)) == [1, 2, 3, 4, 5] 135 | 136 | } 137 | 138 | } 139 | 140 | } 141 | -------------------------------------------------------------------------------- /ExSwiftTests/StringExtensionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StringExtensionsTests.swift 3 | // ExSwift 4 | // 5 | // Created by ExSwift on 04/06/14. 6 | // Copyright (c) 2014 pNre. All rights reserved. 7 | // 8 | 9 | import Quick 10 | import Nimble 11 | 12 | class StringExtensionsSpec: QuickSpec { 13 | 14 | override func spec() { 15 | 16 | /** 17 | * String.length 18 | */ 19 | it("length") { 20 | 21 | expect("".length) == 0 22 | expect("A".length) == 1 23 | expect("😱".length) == 1 24 | expect("∞".length) == 1 25 | expect("∞aA".length) == 3 26 | 27 | } 28 | 29 | /** 30 | * String[x] 31 | */ 32 | it("subscript") { 33 | 34 | let string = "∆Test😗" 35 | 36 | expect(string[0]) == "∆" 37 | expect(string[1]) == "T" 38 | 39 | expect(string[string.length - 1]) == "😗" 40 | expect(string[1..<6]) == "Test😗" 41 | 42 | if let s = "hello"[0] { 43 | expect(s) == "h" 44 | } else { 45 | fail("string[0]") 46 | } 47 | 48 | expect("ABCD"[0, 2]) == ["A", "C"] 49 | 50 | } 51 | 52 | /** 53 | * String.at 54 | */ 55 | it("at") { 56 | 57 | expect("ABCD".at(0)) == ["A"] 58 | expect("ABCD".at(0)) == ["ABCD"[0]!] 59 | 60 | expect("ABCD".at(0, 2)) == ["A", "C"] 61 | expect("ABCD".at(0, 2)) == "ABCD"[0, 2] 62 | 63 | } 64 | 65 | /** 66 | * String.explode 67 | */ 68 | it("explode") { 69 | 70 | expect("A B C".explode(" ")) == ["A", "B", "C"] 71 | 72 | expect("A B C".explode(">")) == ["A B C"] 73 | expect("A>B C".explode(">")) == ["A", "B C"] 74 | 75 | } 76 | 77 | /** 78 | * String.capitalized 79 | */ 80 | it("capitalized") { 81 | 82 | expect("".capitalized) == "" 83 | expect("abcdef".capitalized) == "Abcdef" 84 | expect("Abcdef".capitalized) == "Abcdef" 85 | 86 | } 87 | 88 | /** 89 | * String.insert 90 | */ 91 | it("insert") { 92 | 93 | expect("abcdef".insert(0, "X")) == "Xabcdef" 94 | 95 | expect("abcdef".insert(10, "X")) == "abcdefX" 96 | expect("abcdef".insert(3, "X")) == "abcXdef" 97 | 98 | } 99 | 100 | /** 101 | * String.repeat 102 | */ 103 | it("repeat operator") { 104 | 105 | expect("A" * 3) == "AAA" 106 | expect("A" * 0) == "" 107 | 108 | } 109 | 110 | /** 111 | * String pattern matching 112 | */ 113 | describe("matching") { 114 | 115 | it("=~") { 116 | 117 | let string = "ABcd" 118 | 119 | expect(string =~ "^A").to(beTrue()) 120 | 121 | expect(string =~ (pattern: "D$", ignoreCase: true)).to(beTrue()) 122 | expect(string =~ "D$").to(beFalse()) 123 | 124 | // String[] all 125 | let strings = [string, string, string] 126 | 127 | expect(strings =~ "^A").to(beTrue()) 128 | 129 | expect(strings =~ (pattern: "D$", ignoreCase: true)).to(beTrue()) 130 | expect(strings =~ "D$").to(beFalse()) 131 | 132 | } 133 | 134 | it("|~") { 135 | 136 | // String[] any 137 | let strings = ["ABcd", "ABcd", "ABcd"] 138 | 139 | XCTAssertTrue(strings |~ "^A") 140 | 141 | XCTAssertTrue(strings |~ (pattern: "D$", ignoreCase: true)) 142 | XCTAssertFalse(strings |~ "D$") 143 | 144 | } 145 | 146 | it("matches") { 147 | 148 | let string = "AB[31]" 149 | 150 | let matches = string.matches("\\d+")! 151 | let range = matches[0].rangeAtIndex(0) 152 | 153 | let substringRange = range.location..<(range.location + range.length) 154 | 155 | expect(string[substringRange]) == "31" 156 | expect(string.matches("N")!.isEmpty).to(beTrue()) 157 | 158 | } 159 | 160 | } 161 | 162 | 163 | /** 164 | * String contains matches 165 | */ 166 | describe("containsMatch checks"){ 167 | it("match") { 168 | expect("Test string for match".containsMatch("for")).to(beTrue()) 169 | } 170 | it("not match") { 171 | expect("Test string for match".containsMatch("not for")).to(beFalse()) 172 | } 173 | } 174 | 175 | /** 176 | * ReplaceMatches in string 177 | */ 178 | describe("ReplaceMatches checks"){ 179 | it("find match to replace") { 180 | expect("Test_string".replaceMatches("_.*", withString: "_replace")) == "Test_replace" 181 | } 182 | 183 | it("find match to replacei with empty string") { 184 | expect("Test 111string 222for333 match".replaceMatches("\\d+", withString: "")) == "Test string for match" 185 | } 186 | 187 | it("not find match to replace") { 188 | expect("Test string for match".replaceMatches("\\d+", withString: "some string")) == "Test string for match" 189 | } 190 | } 191 | 192 | /** 193 | * String trimming methods 194 | */ 195 | describe("trimming") { 196 | 197 | it("trimmed") { 198 | 199 | expect("t e".trimmed()) == "t e" 200 | expect(" AB".trimmed()) == "AB" 201 | expect("\n ABC ".trimmed()) == "ABC" 202 | expect("".trimmed()) == "" 203 | expect(" \t\n\r".trimmed()) == "" 204 | 205 | } 206 | 207 | describe("trimmedLeft") { 208 | 209 | it("default character set") { 210 | 211 | expect("ab ".trimmedLeft()) == "ab " 212 | expect("ab".trimmedLeft()) == "ab" 213 | expect(" AB".trimmedLeft()) == "AB" 214 | expect("\n ABC ".trimmedLeft()) == "ABC " 215 | expect("".trimmedLeft()) == "" 216 | expect(" \t\n\r".trimmedLeft()) == "" 217 | 218 | } 219 | 220 | it("with character set") { 221 | 222 | expect("ab ".trimmedLeft(characterSet: NSCharacterSet.alphanumericCharacterSet())) == " " 223 | expect(" ab".trimmedLeft(characterSet: NSCharacterSet.alphanumericCharacterSet())) == " ab" 224 | expect("ab".trimmedLeft(characterSet: NSCharacterSet.alphanumericCharacterSet())) == "" 225 | 226 | } 227 | 228 | } 229 | 230 | describe("trimmedRight") { 231 | 232 | it("default character set") { 233 | 234 | expect("t e".trimmedRight()) == "t e" 235 | expect(" AB".trimmedRight()) == " AB" 236 | expect("AB ".trimmedRight()) == "AB" 237 | expect("\n ABC ".trimmedRight()) == "\n ABC" 238 | expect("".trimmedRight()) == "" 239 | expect(" \t\n\r".trimmedRight()) == "" 240 | 241 | } 242 | 243 | it("with character set") { 244 | 245 | expect("ab ".trimmedRight(characterSet: NSCharacterSet.alphanumericCharacterSet())) == "ab " 246 | expect(" ab".trimmedRight(characterSet: NSCharacterSet.alphanumericCharacterSet())) == " " 247 | expect("ab".trimmedRight(characterSet: NSCharacterSet.alphanumericCharacterSet())) == "" 248 | 249 | } 250 | 251 | } 252 | 253 | describe("type conversion") { 254 | 255 | it("toDouble") { 256 | 257 | expect(" 7.2 ".toDouble()).to(beCloseTo(7.2, within: 0.0001)) 258 | expect("-70.211111 ".toDouble()).to(beCloseTo(-70.211111, within: 0.0001)) 259 | expect("42".toDouble()).to(beCloseTo(42, within: 0.0001)) 260 | 261 | expect("a772.2".toDouble()).to(beNil()) 262 | 263 | } 264 | 265 | it("toFloat") { 266 | 267 | expect(" 7.2 ".toFloat()).to(beCloseTo(7.2, within: 0.0001)) 268 | expect("-70.211111 ".toFloat()).to(beCloseTo(-70.211111, within: 0.0001)) 269 | expect("42".toFloat()).to(beCloseTo(42, within: 0.0001)) 270 | 271 | expect("a772.2".toFloat()).to(beNil()) 272 | 273 | } 274 | 275 | it("toUInt") { 276 | 277 | expect(" 7 ".toUInt()) == 7 278 | 279 | expect("a772.2".toUInt()).to(beNil()) 280 | expect("-772".toUInt()).to(beNil()) 281 | expect("7.5".toUInt()).to(beNil()) 282 | 283 | } 284 | 285 | it("toBool") { 286 | 287 | expect(" TrUe ".toBool()).to(beTrue()) 288 | expect(" yEs ".toBool()).to(beTrue()) 289 | 290 | expect(" FALSE ".toBool()).to(beFalse()) 291 | expect(" nO ".toBool()).to(beFalse()) 292 | 293 | expect("".toBool()).to(beNil()) 294 | expect("jeff".toBool()).to(beNil()) 295 | expect("0".toBool()).to(beNil()) 296 | 297 | } 298 | 299 | it("toDate") { 300 | 301 | var d : NSDate = " 2015-08-19 \t ".toDate()! 302 | 303 | var c = NSDateComponents() 304 | c.year = 2015 305 | c.month = 8 306 | c.day = 19 307 | 308 | var gregorian = NSCalendar(identifier: NSCalendarIdentifierGregorian)! 309 | expect(gregorian.dateFromComponents(c)) == d 310 | 311 | expect("a772.2".toDate()).to(beNil()) 312 | expect("Tuesday".toDate()).to(beNil()) 313 | expect("1973-08-19 03:04:55".toDate()).to(beNil()) 314 | 315 | } 316 | 317 | it("toDateTime") { 318 | 319 | var d : NSDate = " 2015-08-19 03:04:34\t ".toDateTime()! 320 | 321 | var c = NSDateComponents() 322 | c.year = 2015 323 | c.month = 8 324 | c.day = 19 325 | c.hour = 3 326 | c.minute = 4 327 | c.second = 34 328 | 329 | var gregorian = NSCalendar(identifier: NSCalendarIdentifierGregorian)! 330 | expect(gregorian.dateFromComponents(c)) == d 331 | 332 | expect("a772.2".toDateTime()).to(beNil()) 333 | expect("Tuesday".toDateTime()).to(beNil()) 334 | expect("1973-08-19".toDateTime()).to(beNil()) 335 | 336 | } 337 | 338 | } 339 | 340 | /** 341 | * String.random 342 | */ 343 | it("random") { 344 | 345 | expect(String.random().length).to(beLessThanOrEqualTo(16)) 346 | expect(String.random(length: 12).length) == 12 347 | 348 | } 349 | 350 | } 351 | 352 | } 353 | 354 | } 355 | 356 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, pNre 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those 25 | of the authors and should not be interpreted as representing official policies, 26 | either expressed or implied, of the FreeBSD Project. 27 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | inhibit_all_warnings! 2 | use_frameworks! 3 | 4 | def import_test_pods 5 | 6 | pod 'Quick', '~> 0.3.1' 7 | pod 'Nimble', '~> 0.4.2' 8 | 9 | end 10 | 11 | target "ExSwiftTests-iOS" do 12 | 13 | platform :ios, '8.0' 14 | 15 | import_test_pods 16 | 17 | end 18 | 19 | target "ExSwiftTests-Mac" do 20 | 21 | platform :osx, '10.10' 22 | 23 | import_test_pods 24 | 25 | end 26 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Nimble (0.4.2) 3 | - Quick (0.3.1) 4 | 5 | DEPENDENCIES: 6 | - Nimble (~> 0.4.2) 7 | - Quick (~> 0.3.1) 8 | 9 | SPEC CHECKSUMS: 10 | Nimble: 49b7a7da8919f42823d37c6d68cc6d15a7009f32 11 | Quick: 824572d3d198d51e52cf4aa722cebf7e59952a35 12 | 13 | COCOAPODS: 0.37.1 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ExSwift 2 | ![CocoaPods](https://img.shields.io/cocoapods/v/ExSwift.svg) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![Build Status](https://travis-ci.org/pNre/ExSwift.svg)](https://travis-ci.org/pNre/ExSwift) 3 | 4 | Set of Swift extensions for standard types and classes. 5 | 6 | # Installation 7 | 8 | Because of Xcode errors it's not possible to integrate this project with Cocoapods or as Embedded Framework. 9 | [Read more at Dev Forum](https://devforums.apple.com/message/983747#983747) 10 | 11 | ## Use submodule and copy source code 12 | 1. Add ExSwift as a submodule 13 | 2. Open the `ExSwift` project folder, and drag `ExSwift` sub folder with source code into the file navigator of your Xcode project. Make sure you select add to target 14 | 3. Use it 15 | 16 | ``` swift 17 | components.takeFirst() { $0.completed } 18 | ``` 19 | 20 | ## Contents ## 21 | 22 | - [ExSwift extensions](#extensions) 23 | - [Array](#array) 24 | - [Instance Methods](#instance-methods) 25 | - [Class Methods](#class-methods) 26 | - [Operators](#operators) 27 | - [Int](#int) 28 | - [Properties](#properties) 29 | - [Instance Methods](#instance-methods-1) 30 | - [Class Methods](#class-methods-1) 31 | - [Float](#float) 32 | - [Instance Methods](#instance-methods-2) 33 | - [Class Methods](#class-methods-2) 34 | - [String](#string) 35 | - [Properties](#properties-1) 36 | - [Instance Methods](#instance-methods-3) 37 | - [Class Methods](#class-methods-3) 38 | - [Operators](#operators-1) 39 | - [Range](#range) 40 | - [Instance Methods](#instance-methods-4) 41 | - [Class Methods](#class-methods-4) 42 | - [Operators](#operators-2) 43 | - [Dictionary](#dictionary) 44 | - [Instance Methods](#instance-methods-5) 45 | - [Operators](#operators-3) 46 | - [NSArray](#nsarray) 47 | - [Instance Methods](#instance-methods-6) 48 | - [SequenceOf](#sequenceof) 49 | - [Instance Methods](#instance-methods-7) 50 | - [Double](#double) 51 | - [Instance Methods](#instance-methods-8) 52 | - [Class Methods](#class-methods-5) 53 | - [NSDate](#nsdate) 54 | - [Instance Methods](#instance-methods-9) 55 | - [Operators](#operators-4) 56 | 57 | - [Utilities](#utilities) 58 | - [Class Methods](#class-methods-6) 59 | - [Operators](#operators-5) 60 | 61 | # Extensions # 62 | 63 | ## Array ## 64 | 65 | Examples in the [Wiki](https://github.com/pNre/ExSwift/wiki/Array) 66 | 67 | #### Instance Methods #### 68 | 69 | Name | Signature 70 | ---- | --------- 71 | **`first`**|`first () -> Element?` 72 | **`last`**|`last () -> Element?` 73 | **`get`**|`get (index: Int) -> Element?` 74 | **`remove`**|`remove (element: U)` 75 | **`at`**|`at (indexes: Int...) -> Array` 76 | **`take`**|`take (n: Int) -> Array` 77 | **`takeWhile`**|`takeWhile (condition: (Element) -> Bool) -> Array` 78 | **`takeFirst`**|`takeFirst (condition: (Element) -> Bool) -> Element?` 79 | **`tail`**|`tail (n: Int) -> Array` 80 | **`skip`**|`skip (n: Int) -> Array` 81 | **`skipWhile`**|`skipWhile (condition: (Element) -> Bool) -> Array` 82 | **`contains`**|`contains (item: T...) -> Bool` 83 | **`difference`**|`difference (values: [T]...) -> [T]` 84 | **`intersection`**|`intersection (values: [U]...) -> Array` 85 | **`union`**|`union (values: [U]...) -> Array` 86 | **`unique`**|`unique () -> [T]` 87 | **`indexOf`**|`indexOf (item: T) -> Int?` 88 | **`indexOf`**|`indexOf (condition: Element -> Bool) -> Int?` 89 | **`lastIndexOf`**|`lastIndexOf (item: T) -> Int?` 90 | **`zip`**|`zip (arrays: Array...) -> [[Any?]]` 91 | **`partition`**|`partition (var n: Int, var step: Int? = nil) -> [Array]`
`partition (var n: Int, var step: Int? = nil, pad: Element[]?) -> [Array]` 92 | **`partitionAll`**|`partitionAll (var n: Int, var step: Int? = nil) -> [Array]` 93 | **`partitionBy`**|`partitionBy (cond: (Element) -> T) -> [Array]` 94 | **`shuffle`**|`shuffle ()` 95 | **`shuffled`**|`shuffled () -> Array` 96 | **`sample`** *(random)*|`sample (size n: Int = 1) -> [T]` 97 | **`max`**|`max () -> T` 98 | **`min`**|`min () -> T` 99 | **`each`**|`each (call: (Element) -> ())`
`each (call: (Int, Element) -> ())` 100 | **`eachRight`**|`eachRight (call: (Element) -> ())`
`eachRight (call: (Int, Element) -> ())` 101 | **`any`**|`any (call: (Element) -> Bool) -> Bool` 102 | **`all`**|`all (call: (Element) -> Bool) -> Bool` 103 | **`reject`**|`reject (exclude: (Element -> Bool)) -> Array` 104 | **`pop`**|`pop() -> Element` 105 | **`push`**|`push(newElement: Element)` 106 | **`shift`**|`shift() -> Element` 107 | **`unshift`**|`unshift(newElement: Element)` 108 | **`insert`**|`insert (newArray: Array, atIndex: Int)` 109 | **`groupBy`**|`groupBy (groupingFunction group: (Element) -> (U)) -> [U: Array]` 110 | **`countBy`**|`countBy (groupingFunction group: (Element) -> (U)) -> [U: Int]` 111 | **`countWhere`**|`countWhere (test: (Element) -> Bool) -> Int` 112 | **`reduce`**|`reduce (combine: (Element, Element) -> Element) -> Element?` 113 | **`reduceRight`**|`reduceRight (initial: U, combine: (U, Element) -> U) -> U` 114 | **`mapFilter`**|`mapFilter (mapFunction map: (Element) -> (V)?) -> [V]` 115 | **`implode`**|`implode (separator: C) -> C?` 116 | **`flatten`**|`flatten () -> [OutType]` 117 | **`flattenAny`**|`flattenAny () -> [AnyObject]` 118 | **`toDictionary`**|`toDictionary (keySelector:(Element) -> U) -> [U: Element]` 119 | **`toDictionary`**|`toDictionary (transform: (Element) -> (key: K, value: V)?) -> [K: V]` 120 | **`cycle`**|`cycle (n: Int? = nil, block: (T) -> ())` 121 | **`bSearch`**|`bSearch (block: (T) -> (Bool)) -> T?` 122 | **`bSearch`**|`bSearch (block: (T) -> (Int)) -> T?` 123 | **`sortUsing`**|`sortUsing(block: ((T) -> U)) -> [T]` 124 | **`transposition`**|`transposition (array: [[T]]) -> [[T]]` 125 | **`permutation`**|`permutation (length: Int) -> [[T]]` 126 | **`repeatedPermutation`**|`repeatedPermutation(length: Int) -> [[T]]` 127 | **`combination`**|`combination (length: Int) -> [[Element]]` 128 | **`repeatedCombination `**|`repeatedCombination (length: Int) -> [[Element]]` 129 | 130 | #### Class Methods #### 131 | 132 | Name | Signatures 133 | ---- | ---------- 134 | **`range`**|`range (range: Range) -> Array` 135 | 136 | #### Operators #### 137 | Name | Signature | Function 138 | ---- | --------- | -------- 139 | `-`|`- (first: Array, second: Array) -> Array`|Difference 140 | `-`|`- (first: Array, second: T) -> Array`|Element removal 141 | `&`|`& (first: Array, second: Array) -> Array`|Intersection 142 | ||| (first: Array, second: Array) -> Array|Union 143 | `* Int`|`* (array: ItemType[], n: Int) -> [ItemType]`|Returns a new array built by concatenating int copies of self 144 | `* String`|`* (array: String[], separator: String) -> String`|Equivalent to `array.implode(String)` 145 | `[rangeAsArray: x..y]`
`[rangeAsArray: x...y]`|`subscript(#rangeAsArray: Range) -> Array`|Returns the sub-array from index *x* to index *y* 146 | `[x, y, ...]`|`subscript(first: Int, second: Int, rest: Int...) -> Array`|Returns the items at *x*, *y* 147 | 148 | ## Int ## 149 | 150 | Examples in the [Wiki](https://github.com/pNre/ExSwift/wiki/Int) 151 | 152 | #### Properties #### 153 | Name | 154 | ---- | 155 | `NSTimeInterval`**`years`**| 156 | `NSTimeInterval`**`year`**| 157 | `NSTimeInterval`**`days`**| 158 | `NSTimeInterval`**`day`**| 159 | `NSTimeInterval`**`hours`**| 160 | `NSTimeInterval`**`hour`**| 161 | `NSTimeInterval`**`minutes`**| 162 | `NSTimeInterval`**`minute`**| 163 | `NSTimeInterval`**`seconds`**| 164 | `NSTimeInterval`**`second`**| 165 | 166 | #### Instance Methods #### 167 | 168 | Name | Signatures 169 | ---- | ---------- 170 | **`times`**|`times (call: (Int) -> T)`
`times (call: () -> T)`
`times (call: () -> ())` 171 | **`isEven`**|`isEven () -> Bool` 172 | **`isOdd`**|`idOdd () -> Bool` 173 | **`upTo`**|`upTo (limit: Int, call: (Int) -> ())` 174 | **`downTo`**|`downTo (limit: Int, call: (Int) -> ())` 175 | **`clamp`**|`clamp (range: Range) -> Int`
`clamp (min: Int, max: Int) -> Int` 176 | **`isIn`**|`isIn (range: Range, strict: Bool = false) -> Bool` 177 | **`digits`**|`digits () -> Array` 178 | **`abs`**|`abs () -> Int` 179 | **`gcd`**|`gcd (n: Int) -> Int` 180 | **`lcm`**|`lcm (n: Int) -> Int` 181 | 182 | #### Class Methods #### 183 | 184 | Name | Signatures 185 | ---- | ---------- 186 | **`random`**|`random(min: Int = 0, max: Int) -> Int` 187 | 188 | 189 | ## Float ## 190 | 191 | Examples in the [Wiki](https://github.com/pNre/ExSwift/wiki/Float) 192 | 193 | #### Instance Methods #### 194 | 195 | Name | Signature 196 | ---- | --------- 197 | **`abs`**|`abs () -> Float` 198 | **`sqrt`**|`sqrt () -> Float` 199 | **`round`**|`round () -> Float` 200 | **`ceil`**|`ceil () -> Float` 201 | **`floor`**|`floor () -> Float` 202 | **`clamp`**|`clamp (min: Float, _ max: Float) -> Float` 203 | 204 | #### Class Methods #### 205 | 206 | Name | Signatures 207 | ---- | ---------- 208 | **`random`**|`random(min: Float = 0, max: Float) -> Float` 209 | 210 | ## String ## 211 | 212 | Examples in the [Wiki](https://github.com/pNre/ExSwift/wiki/String) 213 | 214 | #### Properties #### 215 | Name | 216 | ---- | 217 | **`length`**| 218 | **`capitalized`**| 219 | 220 | #### Instance Methods #### 221 | 222 | Name | Signature 223 | ---- | --------- 224 | **`explode`**|`explode (separator: Character) -> [String]` 225 | **`at`**|`at (indexes: Int...) -> [String]` 226 | **`matches`**|`matches (pattern: String, ignoreCase: Bool = false) -> [NSTextCheckingResult]?` 227 | **`insert`**|`insert (index: Int, _ string: String) -> String` 228 | **`ltrimmed`**|`ltrimmed () -> String` 229 | **`ltrimmed`**|`ltrimmed (set: NSCharacterSet) -> String` 230 | **`rtrimmed`**|`rtrimmed () -> String` 231 | **`rtrimmed`**|`rtrimmed (set: NSCharacterSet) -> String` 232 | **`trimmed`**|`trimmed () -> String` 233 | **`rtrimmed`**|`rtrimmed (set: NSCharacterSet) -> String` 234 | **`toDouble`**|`toDouble() -> Double?` 235 | **`toFloat`**|`toFloat() -> Float?` 236 | **`toUInt`**|`toUInt() -> UInt?` 237 | **`toBool`**|`toBool() -> Bool?` 238 | **`toDate`**|`toDate(format : String? = "yyyy-MM-dd") -> NSDate?` 239 | **`toDateTime`**|`toDateTime(format : String? = "yyyy-MM-dd hh-mm-ss") -> NSDate?` 240 | 241 | 242 | #### Class Methods #### 243 | 244 | Name | Signature 245 | ---- | --------- 246 | **`random`**|`func random (var length len: Int = 0, charset: String = "...") -> String` 247 | 248 | #### Operators #### 249 | Name | Signature 250 | ---- | --------- 251 | `[x]`|`subscript(index: Int) -> String?` 252 | `[x..y]`
`[x...y]`|`subscript(range: Range) -> String` 253 | `[x, y, z]`|`subscript (indexes: Int...) -> [String]` 254 | `S * n`|`* (first: String, second: Int) -> String` 255 | `=~`|`=~ (string: String, pattern: String) -> Bool`
`=~ (string: String, options: (pattern: String, ignoreCase: Bool)) -> Bool`
`=~ (strings: [String], pattern: String) -> Bool`
`=~ (strings: [String], options: (pattern: String, ignoreCase: Bool)) -> Bool` 256 | |~||~ (string: String, pattern: String) -> Bool
|~ (string: String, options: (pattern: String, ignoreCase: Bool)) -> Bool 257 | 258 | ## Range ## 259 | 260 | Examples in the [Wiki](https://github.com/pNre/ExSwift/wiki/Range) 261 | 262 | #### Instance Methods #### 263 | 264 | Name | Signatures 265 | ---- | ---------- 266 | **`times`**|`times (call: (T) -> ())`
`times (call: () -> ())` 267 | **`each`**|`each (call: (T) -> ())` 268 | **`toArray`**|`toArray () -> [T]` 269 | 270 | #### Class Methods #### 271 | 272 | Name | Signature 273 | ---- | --------- 274 | **`random`**|`random (from: Int, to: Int) -> Range` 275 | 276 | #### Operators #### 277 | Name | Signature|Function 278 | ---- | ---------|-------- 279 | `=`|`== (first: Range, second: Range) -> Bool`|Compares 2 ranges 280 | 281 | ## Dictionary ## 282 | 283 | Examples in the [Wiki](https://github.com/pNre/ExSwift/wiki/Dictionary) 284 | 285 | #### Instance Methods #### 286 | 287 | Name | Signatures 288 | ---- | ---------- 289 | **`difference`**|`difference (dictionaries: [Key: V]...) -> [Key: V]` 290 | **`union`**|`union (dictionaries: [Key: Value]...) -> [Key: Value]` 291 | **`intersection`**|`intersection (dictionaries: [K: V]...) -> [K: V]` 292 | **`has`**|`has (key: Key) -> Bool` 293 | **`map`**|`map (mapFunction map: (Key, Value) -> (K, V)) -> [K: V]` 294 | **`mapFilter`**|`mapFilter (mapFunction map: (Key, Value) -> (K, V)?) -> [K: V]` 295 | **`mapValues`**|`mapValues (mapFunction map: (Key, Value) -> (V)) -> [Key: V]` 296 | **`mapFilterValues`**|`mapFilterValues (mapFunction map: (Key, Value) -> V?) -> [Key: V]` 297 | **`each`**|`each(eachFunction each: (Key, Value) -> ())` 298 | **`filter`**|`filter(testFunction test: (Key, Value) -> Bool) -> [Key: Value]` 299 | **`merge`**|`merge (dictionaries: [Key: Value]...) -> [Key: Value]` 300 | **`shift`**|`shift () -> (Key, Value)` 301 | **`groupBy`**|`groupBy (groupingFunction group: (Key, Value) -> (T)) -> [T: Array]` 302 | **`countBy`**|`countBy (groupingFunction group: (Key, Value) -> (T)) -> [T: Int]` 303 | **`countWhere`**|`countWhere (test: (Key, Value) -> (Bool)) -> Int` 304 | **`any`**|`any (test: (Key, Value) -> (Bool)) -> Bool` 305 | **`all`**|`all (test: (Key, Value) -> (Bool)) -> Bool` 306 | **`reduce`**|`reduce (initial: U, combine: (U, Element) -> U) -> U` 307 | **`pick`, `at`**|`pick (keys: [Key]) -> Dictionary`
`pick (keys: Key...) -> Dictionary`
`at (keys: Key...) -> Dictionary` 308 | **`toArray`**|`toArray (mapFunction map: (Key, Value) -> V) -> [V]` 309 | 310 | #### Operators #### 311 | Name | Signature | Function 312 | ---- | --------- | -------- 313 | `-`|`- (first: Dictionary, second: Dictionary) -> Dictionary`|Difference 314 | `&`|`& (first: Dictionary, second: Dictionary) -> Dictionary`|Intersection 315 | ||| (first: Dictionary, second: Dictionary) -> Dictionary|Union 316 | 317 | ## NSArray ## 318 | 319 | Examples in the [Wiki](https://github.com/pNre/ExSwift/wiki/NSArray) 320 | 321 | #### Instance Methods #### 322 | 323 | Name | Signatures 324 | ---- | ---------- 325 | **`cast`**|`cast () -> [OutType]` 326 | **`flatten`**|`flatten () -> [OutType]` 327 | **`flattenAny`**|`flattenAny () -> [AnyObject]` 328 | 329 | ## SequenceOf ## 330 | 331 | The following operations can be performed on sequences and are evaluated lazily. Each operation only takes the data it requires from the source sequence in order to return its result. 332 | 333 | The `Sequence` protocol cannot be extended, hence the following are extensions to `SequenceOf`. They can be used as follows: 334 | 335 | ``` 336 | var source: Sequence = ... 337 | var filteredSequence = SequenceOf(source).filter { ... } 338 | ``` 339 | 340 | #### Instance Methods #### 341 | 342 | Name | Signatures 343 | ---- | ---------- 344 | **`first`**|`first () -> T?` 345 | **`any`**|`any (call: (T) -> Bool) -> Bool` 346 | **`get`**|`get (index: Int) -> T?` 347 | **`get`**|`get (range: Range) -> SequenceOf` 348 | **`indexOf`**|`indexOf (item: U) -> Int?` 349 | **`filter`**|`filter(include: (T) -> Bool) -> SequenceOf` 350 | **`reject`**|`reject (exclude: (T -> Bool)) -> SequenceOf` 351 | **`skipWhile`**|`skipWhile(condition:(T) -> Bool) -> SequenceOf` 352 | **`skip`**|`skip (n:Int) -> SequenceOf` 353 | **`contains`**|`contains (item: T) -> Bool` 354 | **`take`**|`take (n:Int) -> SequenceOf` 355 | **`takeWhile`**|`takeWhile (condition:(T?) -> Bool) -> SequenceOf` 356 | 357 | ## Double ## 358 | 359 | Examples in the [Wiki](https://github.com/pNre/ExSwift/wiki/Double) 360 | 361 | #### Instance Methods #### 362 | 363 | Name | Signature 364 | ---- | --------- 365 | **`abs`**|`abs () -> Double` 366 | **`sqrt`**|`sqrt () -> Double` 367 | **`round`**|`round () -> Double` 368 | **`ceil`**|`ceil () -> Double` 369 | **`floor`**|`floor () -> Double` 370 | **`clamp`**|`clamp (min: Double, _ max: Double) -> Double` 371 | **`roundToNearest`**|`roundToNearest(increment: Double) -> Double` 372 | 373 | #### Class Methods #### 374 | 375 | Name | Signatures 376 | ---- | ---------- 377 | **`random`**|`random(min: Double = 0, max: Double) -> Double` 378 | 379 | # NSDate # 380 | 381 | #### Properties #### 382 | Name | Signatures 383 | ---- | ---- 384 | **`year`** |`Int` 385 | **`month`**|`Int` 386 | **`weekday`** |`Int` 387 | **`weekMonth`**|`Int` 388 | **`days`** |`Int` 389 | **`hours`**|`Int` 390 | **`minutes`** |`Int` 391 | **`seconds`**| `Int` 392 | 393 | #### Instance Methods #### 394 | Name | Signatures 395 | ---- | ---------- 396 | **`add`**|`add(seconds:Int=0, minutes:Int = 0, hours:Int = 0, days:Int = 0, weeks:Int = 0, months:Int = 0, years:Int = 0) -> NSDate` 397 | **`addSeconds`**|`addSeconds (seconds:Int) -> NSDate ` 398 | **`addMinutes`**|`addMinutes (minute:Int) -> NSDate ` 399 | **`addHours`**|`addHours(hours:Int) -> NSDate ` 400 | **`addDays`**|`addDays(days:Int) -> NSDate ` 401 | **`addWeeks`**|`addWeeks(weeks:Int) -> NSDate` 402 | **`addMonths`**|`addMonths(months:Int) -> NSDate` 403 | **`addYears`**|`addYears(years:Int) -> NSDate ` 404 | **`isAfter`**|`isAfter(date: NSDate) -> Bool` 405 | **`isBefore`**|`isBefore(date: NSDate) -> Bool` 406 | **`getComponent`**|`getComponent (component : NSCalendarUnit) -> Int` 407 | 408 | #### Operators #### 409 | 410 | Name | Signatures 411 | ---- | ---------- 412 | **`==`**|`==(lhs: NSDate, rhs: NSDate) -> Bool` 413 | **`<`**|`<(lhs: NSDate, rhs: NSDate) -> Bool` 414 | **`>`**|`>(lhs: NSDate, rhs: NSDate) -> Bool` 415 | **`<=`**|`<=(lhs: NSDate, rhs: NSDate) -> Bool` 416 | **`>=`**|`>=(lhs: NSDate, rhs: NSDate) -> Bool` 417 | **`==`**|`==(lhs: NSDate, rhs: NSDate) -> Bool` 418 | 419 | # Utilities # 420 | 421 | Examples in the [Wiki](https://github.com/pNre/ExSwift/wiki/ExSwift) 422 | 423 | #### Class Methods #### 424 | 425 | Name | Signatures 426 | ---- | ---------- 427 | **`after`**|`after (n: Int, function: P -> T) -> (P -> T?)`
`func after (n: Int, function: () -> T) -> (() -> T?)` 428 | **`once`**|`once (function: P -> T) -> (P -> T?)`
`once (call: Void -> T) -> (Void -> T?)` 429 | **`partial`**|`partial (function: (P...) -> T, _ parameters: P...) -> ((P...) -> T?)` 430 | **`bind`**|`bind (function: (P...) -> T, _ parameters: P...) -> (() -> T)` 431 | **`cached`**|`cached (function: P -> R) -> (P -> R)`
`cached (function: (P...) -> R) -> ((P...) -> R)`
`cached (function: (P...) -> R, hash: ((P...) -> P)) -> ((P...) -> R)` 432 | 433 | #### Operators #### 434 | Name | Signatures 435 | ---- | ---------- 436 | **`<=>`**|`<=> (lhs: T, rhs: T) -> Int` 437 | 438 | # To Do # 439 | * [X] Wiki 440 | * [X] Xcode project for both iOS & OS X 441 | * [X] Review code comments 442 | * [ ] Example project 443 | * [ ] Installation instructions 444 | * [ ] Benchmark 445 | --------------------------------------------------------------------------------