Permalink
Browse files

Some basic extensions and tests

  • Loading branch information...
tptee committed Aug 6, 2015
1 parent 4939737 commit f9c3c06c42ca51fd383fd4629825b7e4a372de3c
@@ -1,8 +1,12 @@
# OS X
.DS_Store
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
DerivedData
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
@@ -12,22 +16,29 @@ build/
*.perspectivev3
!default.perspectivev3
xcuserdata
## Other
*.xccheckout
profile
*.moved-aside
DerivedData
*.xcuserstate
*.xcscmblueprint
## Obj-C/Swift specific
*.hmap
*.ipa
# Bundler
.bundle
Carthage
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
#
# Note: if you ignore the Pods directory, make sure to uncomment
# `pod install` in .travis.yml
#
# Pods/
Pods/
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build
contents.xcworkspacedata
@@ -36,7 +36,7 @@
607FACDA1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
607FACDC1AFB9204008FA782 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
607FACE51AFB9204008FA782 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; name = Tests.xctest; path = Oriole_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
607FACE51AFB9204008FA782 /* Oriole_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Oriole_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
607FACEB1AFB9204008FA782 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = "<group>"; };
78F2E1761DB47DA7F809D839 /* Pods-Oriole_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Oriole_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Oriole_Tests/Pods-Oriole_Tests.debug.xcconfig"; sourceTree = "<group>"; };
@@ -105,7 +105,7 @@
isa = PBXGroup;
children = (
607FACD01AFB9204008FA782 /* Oriole_Example.app */,
607FACE51AFB9204008FA782 /* Tests.xctest */,
607FACE51AFB9204008FA782 /* Oriole_Tests.xctest */,
);
name = Products;
sourceTree = "<group>";
@@ -200,7 +200,7 @@
);
name = Oriole_Tests;
productName = Tests;
productReference = 607FACE51AFB9204008FA782 /* Tests.xctest */;
productReference = 607FACE51AFB9204008FA782 /* Oriole_Tests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
@@ -209,7 +209,8 @@
607FACC81AFB9204008FA782 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0630;
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0700;
ORGANIZATIONNAME = CocoaPods;
TargetAttributes = {
607FACCF1AFB9204008FA782 = {
@@ -422,6 +423,7 @@
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
@@ -490,6 +492,7 @@
INFOPLIST_FILE = Oriole/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MODULE_NAME = ExampleApp;
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
@@ -502,6 +505,7 @@
INFOPLIST_FILE = Oriole/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MODULE_NAME = ExampleApp;
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
@@ -521,6 +525,7 @@
);
INFOPLIST_FILE = Tests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Oriole_Example.app/Oriole_Example";
};
@@ -537,6 +542,7 @@
);
INFOPLIST_FILE = Tests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Oriole_Example.app/Oriole_Example";
};
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0630"
LastUpgradeVersion = "0700"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -62,6 +62,8 @@
ReferencedContainer = "container:Oriole.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
@@ -71,6 +73,7 @@
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
@@ -7,11 +7,16 @@
//
import UIKit
import Oriole
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print([4, 8, 15, 16, 23, 42].chunk(2))
print([4, 8, 15, 16, 23, 42].every {$0 == 23})
print([42, 42, 42, 42].every {$0 == 42})
// Do any additional setup after loading the view, typically from a nib.
}
@@ -8,6 +8,6 @@ end
target 'Oriole_Tests', :exclusive => true do
pod "Oriole", :path => "../"
pod 'Quick', '~> 0.3.1'
pod 'Nimble'
pod 'Quick', '~> 0.5.1'
pod 'Nimble', '2.0.0-rc.2'
end
@@ -0,0 +1,20 @@
PODS:
- Nimble (2.0.0-rc.2)
- Oriole (0.1.0)
- Quick (0.5.1)
DEPENDENCIES:
- Nimble (= 2.0.0-rc.2)
- Oriole (from `../`)
- Quick (~> 0.5.1)
EXTERNAL SOURCES:
Oriole:
:path: "../"
SPEC CHECKSUMS:
Nimble: e3cf5e73a491daf21c2bc88783dbfc55ce8b8e02
Oriole: 83308ff34cc46658857ea7965d6a844b76a740bc
Quick: 7426537a99e75076d6930c5b6da58006e4a9f38a
COCOAPODS: 0.38.2
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
@@ -4,47 +4,36 @@ import Quick
import Nimble
import Oriole
class TableOfContentsSpec: QuickSpec {
class OrioleSpec: QuickSpec {
override func spec() {
describe("these will fail") {
it("can do maths") {
expect(1) == 2
}
it("can read") {
expect("number") == "string"
}
it("will eventually fail") {
expect("time").toEventually( equal("done") )
}
context("these will pass") {
it("can do maths") {
expect(23) == 23
}
it("can read") {
expect("🐮") == "🐮"
}
it("will eventually pass") {
var time = "passing"
dispatch_async(dispatch_get_main_queue()) {
time = "done"
}
waitUntil { done in
NSThread.sleepForTimeInterval(0.5)
expect(time) == "done"
done()
}
}
}
}
describe("Oriole") {
context("CollectionType") {
it("safely accesses a collection element by index") {
let array = [4, 8, 15, 16, 23, 42]
expect(array[safe: 0]) == 4
expect(array[safe: 6]).to(beNil())
}
it("safely retrieves multiple elements from a collection by index") {
let array = [5, 4, 3, 2, 1]
expect(array.at([0, 1, 4])) == [5, 4, 1]
expect(array.at([1, 5, 90])) == [4]
}
it("determines if a callback is true for every collection element") {
let set = Set(arrayLiteral: "Things", "and", "other", "stuff")
expect(set.every { $0.characters.count > 3 }) == true
expect(set.every { $0 == "Things" }) == false
}
}
context("Array") {
it("safely divides a collection into multiple collections with a possible remainder") {
let array = ["This", "is", "a", "test"]
expect(array.chunk(2)) == [["This", "is"], ["a", "test"]]
expect(array.chunk(3)) == [["This", "is", "a"], ["test"]]
}
}
}
}
}
@@ -17,11 +17,10 @@ Pod::Spec.new do |s|
* Markdown format.
* Don't worry about the indent, we strip it!
DESC
s.homepage = "https://github.com/<GITHUB_USERNAME>/Oriole"
# s.screenshots = "www.example.com/screenshots_1", "www.example.com/screenshots_2"
s.homepage = "https://github.com/tptee/Oriole"
s.license = 'MIT'
s.author = { "Tyler Thompson" => "tyler@tylerpaulthompson.com" }
s.source = { :git => "https://github.com/<GITHUB_USERNAME>/Oriole.git", :tag => s.version.to_s }
s.source = { :git => "https://github.com/tptee/Oriole.git", :tag => s.version.to_s }
# s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'
s.platform = :ios, '8.0'
@@ -0,0 +1,51 @@
import Foundation
public extension CollectionType where Index: Comparable {
// Credit: https://gist.github.com/brentdax/72f3fcc3274c0e5f12d7
public subscript(safe index: Index) -> Generator.Element? {
guard startIndex <= index && index < endIndex else {
return nil
}
return self[index]
}
public func at(indices: [Index]) -> [Generator.Element]? {
return indices.map { index in return self[safe: index] }.flatMap { $0 }
}
public func every(callback: (Generator.Element) -> Bool) -> Bool {
return self.reduce(false) { acc, element in
return callback(element)
}
}
public func find(callback: (Generator.Element) -> Bool) -> Generator.Element? {
for element in self {
if callback(element) {
return element
}
}
return nil
}
}
// Helper function for chunk
// Inspired by http://stackoverflow.com/q/26395766
private func chunkArray<T>(s: [T], _ splitSize: Int) -> [[T]] {
if s.count <= splitSize {
return [s]
} else {
return [Array(s[0..<splitSize])] + chunkArray(
Array(s[splitSize..<s.count]), splitSize
)
}
}
public extension Array {
public func chunk(length: Int) -> [[T]] {
return chunkArray(self, length)
}
}
// Use Set for set operations.
No changes.
@@ -5,11 +5,21 @@
[![License](https://img.shields.io/cocoapods/l/Oriole.svg?style=flat)](http://cocoapods.org/pods/Oriole)
[![Platform](https://img.shields.io/cocoapods/p/Oriole.svg?style=flat)](http://cocoapods.org/pods/Oriole)
Oriole is a set of protocol extensions that add useful helper methods to Swift collections. Oriole resembles libraries like Dollar and ExSwift (which in turn take inspiration from Lodash), but with some ideological differences:
- Oriole uses Swift 2.0's new protocol extensions to provide more natural APIs.
- Oriole strives to be as generic as possible. Most methods extend CollectionType. Oriole extends concrete collections like Array, Set, and Dictionary only if necessary.
- Oriole fills in gaps in the Swift standard library. If a method is trivially reproducible by methods in the standard library, it is not included.
- Oriole prefers to implement functional solutions to problems. However, if an imperative solution is elegant and significantly more performant, it will replace the functional solution.
Oriole is in its infancy, but is growing rapidly. I aim to add at least one new tested extension a day until the project is complete. Detailed documentation is forthcoming and will accelerate once [Jazzy](https://github.com/realm/jazzy/pull/261) works with Swift 2.0.
## Usage
To run the example project, clone the repo, and run `pod install` from the Example directory first.
## Requirements
This library is Swift 2.0 only due to its reliance on protocol extensions.
## Installation

0 comments on commit f9c3c06

Please sign in to comment.