diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f067d67
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,33 @@
+# OS X
+.DS_Store
+
+# Xcode
+build/
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata
+*.xccheckout
+profile
+*.moved-aside
+DerivedData
+*.hmap
+*.ipa
+
+# Bundler
+.bundle
+
+Carthage
+# 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/
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..d3f73cd
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,13 @@
+# references:
+# * http://www.objc.io/issue-6/travis-ci.html
+# * https://github.com/supermarin/xcpretty#usage
+
+language: objective-c
+# cache: cocoapods
+# podfile: Example/Podfile
+# before_install:
+# - gem install cocoapods # Since Travis is not always on latest version
+# - pod install --project-directory=Example
+script:
+- set -o pipefail && xcodebuild test -workspace Example/RoutePatterns.xcworkspace -scheme RoutePatterns-Example -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO | xcpretty
+- pod lib lint
diff --git a/Example/Info.plist b/Example/Info.plist
new file mode 100644
index 0000000..eb18faa
--- /dev/null
+++ b/Example/Info.plist
@@ -0,0 +1,39 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+
+
+
diff --git a/Example/Podfile b/Example/Podfile
new file mode 100644
index 0000000..bb22962
--- /dev/null
+++ b/Example/Podfile
@@ -0,0 +1,11 @@
+use_frameworks!
+
+target 'URLPatterns_Example', :exclusive => true do
+ pod 'URLPatterns', :path => '../'
+end
+
+target 'URLPatterns_Tests', :exclusive => true do
+ pod 'URLPatterns', :path => '../'
+
+
+end
diff --git a/Example/Podfile.lock b/Example/Podfile.lock
new file mode 100644
index 0000000..da92bcb
--- /dev/null
+++ b/Example/Podfile.lock
@@ -0,0 +1,14 @@
+PODS:
+ - URLPatterns (0.1.0)
+
+DEPENDENCIES:
+ - URLPatterns (from `../`)
+
+EXTERNAL SOURCES:
+ URLPatterns:
+ :path: "../"
+
+SPEC CHECKSUMS:
+ URLPatterns: f01472d7655c87767efb582362ef017c3cc1004c
+
+COCOAPODS: 0.39.0
diff --git a/Example/RoutePatterns.xcworkspace/contents.xcworkspacedata b/Example/RoutePatterns.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..bbe9ab9
--- /dev/null
+++ b/Example/RoutePatterns.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/Example/Source/AppDelegate.swift b/Example/Source/AppDelegate.swift
new file mode 100644
index 0000000..caef501
--- /dev/null
+++ b/Example/Source/AppDelegate.swift
@@ -0,0 +1,39 @@
+//
+// AppDelegate.swift
+// URLPatterns
+//
+// Created by johnmorgan on 04/29/2016.
+// Copyright (c) 2016 johnmorgan. All rights reserved.
+//
+
+import UIKit
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+ var window: UIWindow?
+
+ func application(application: UIApplication, didFinishLaunchingWithOptions options: [NSObject: AnyObject]?) -> Bool {
+
+ if let url = options?[UIApplicationLaunchOptionsURLKey] as? NSURL, link = DeepLink(url: url) {
+ DeepLinker.open(link)
+ }
+
+ let testURL = NSURL(string: "myscheme://myhost/users/john_morgan12/profile")!
+
+ if let link = DeepLink(url: testURL) {
+ DeepLinker.open(link)
+ }
+
+ return true
+ }
+
+ func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
+
+ if let link = DeepLink(url: url) {
+ return DeepLinker.open(link)
+ }
+ return false
+ }
+}
+
diff --git a/Example/Source/Base.lproj/LaunchScreen.xib b/Example/Source/Base.lproj/LaunchScreen.xib
new file mode 100644
index 0000000..8038e5f
--- /dev/null
+++ b/Example/Source/Base.lproj/LaunchScreen.xib
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Example/Source/Base.lproj/Main.storyboard b/Example/Source/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..1140508
--- /dev/null
+++ b/Example/Source/Base.lproj/Main.storyboard
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Example/Source/DeepLink.swift b/Example/Source/DeepLink.swift
new file mode 100644
index 0000000..f3a2f99
--- /dev/null
+++ b/Example/Source/DeepLink.swift
@@ -0,0 +1,39 @@
+//
+// DeepLink.swift
+// URLPatterns
+//
+// Created by John Morgan on 29/04/2016.
+// Copyright © 2016 CocoaPods. All rights reserved.
+//
+
+import Foundation
+import URLPatterns
+
+enum DeepLink {
+
+ case Home, History, Settings, Terms, News
+ case Chat(room: String)
+ case Profile(userId: String)
+}
+
+extension DeepLink {
+
+ init?(url: NSURL) {
+
+ guard url.scheme == "myscheme" else { return nil }
+ guard url.host == "myhost" else { return nil }
+
+ switch url.countedPathComponents() {
+
+ case .N0, .N1(""): self = .Home
+ case .N1("history"): self = .History
+ case .N2(_, "settings"): self = .Settings
+ case .N2("chat", let room): self = .Chat(room: room)
+ case .N3("users", let userId, "profile"): self = .Profile(userId: userId)
+ case Begins("news", "latest"): self = .News
+ case Ends("terms"): self = .Terms
+
+ default: return nil
+ }
+ }
+}
diff --git a/Example/Source/DeepLinker.swift b/Example/Source/DeepLinker.swift
new file mode 100644
index 0000000..b65be75
--- /dev/null
+++ b/Example/Source/DeepLinker.swift
@@ -0,0 +1,34 @@
+//
+// DeepLinker.swift
+// URLPatterns
+//
+// Created by John Morgan on 29/04/2016.
+// Copyright © 2016 CocoaPods. All rights reserved.
+//
+
+import Foundation
+
+struct DeepLinker {
+
+ static func open(link: DeepLink, animated: Bool = true) -> Bool {
+
+ switch link {
+
+ case .Profile(let userId):
+ print("Opening profile for \(userId)")
+ case .History:
+ print("Opening history")
+ case .Chat(let room):
+ print("Opening chat room \(room)")
+ case .Home:
+ print("Opening home")
+ case .Settings:
+ print("Opening settings")
+ case .News:
+ print("Opening news")
+ case .Terms:
+ print("Opening terms")
+ }
+ return true
+ }
+}
diff --git a/Example/Source/Images.xcassets/AppIcon.appiconset/Contents.json b/Example/Source/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..d3942e9
--- /dev/null
+++ b/Example/Source/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,38 @@
+{
+ "images" : [
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/Example/TODO.md b/Example/TODO.md
new file mode 100644
index 0000000..a82d2ee
--- /dev/null
+++ b/Example/TODO.md
@@ -0,0 +1,5 @@
+## Possible future additions
+
+- Make Counted conform to CollectionType?
+- Add matching for Contains
+- Add Regex matching for individual path elements
diff --git a/Example/Tests/Info.plist b/Example/Tests/Info.plist
new file mode 100644
index 0000000..ba72822
--- /dev/null
+++ b/Example/Tests/Info.plist
@@ -0,0 +1,24 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ BNDL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+
+
diff --git a/Example/Tests/Tests.swift b/Example/Tests/Tests.swift
new file mode 100644
index 0000000..8d6f265
--- /dev/null
+++ b/Example/Tests/Tests.swift
@@ -0,0 +1,29 @@
+import UIKit
+import XCTest
+import URLPatterns
+
+class Tests: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDown() {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ super.tearDown()
+ }
+
+ func testExample() {
+ // This is an example of a functional test case.
+ XCTAssert(true, "Pass")
+ }
+
+ func testPerformanceExample() {
+ // This is an example of a performance test case.
+ self.measureBlock() {
+ // Put the code you want to measure the time of here.
+ }
+ }
+
+}
diff --git a/Example/URLPatterns.xcodeproj/project.pbxproj b/Example/URLPatterns.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..a1558ed
--- /dev/null
+++ b/Example/URLPatterns.xcodeproj/project.pbxproj
@@ -0,0 +1,1311 @@
+
+
+
+
+ archiveVersion
+ 1
+ classes
+
+ objectVersion
+ 46
+ objects
+
+ 04AC2450233B25049373E0FD
+
+ fileRef
+ 6D7553EA99BA34A221C8FF5A
+ isa
+ PBXBuildFile
+
+ 083BBF27E4A3856F9B8FA743
+
+ buildActionMask
+ 2147483647
+ files
+
+ inputPaths
+
+ isa
+ PBXShellScriptBuildPhase
+ name
+ Embed Pods Frameworks
+ outputPaths
+
+ runOnlyForDeploymentPostprocessing
+ 0
+ shellPath
+ /bin/sh
+ shellScript
+ "${SRCROOT}/Pods/Target Support Files/Pods-URLPatterns_Tests/Pods-URLPatterns_Tests-frameworks.sh"
+
+ showEnvVarsInLog
+ 0
+
+ 19BD0D0E3E101FBDBD3AE2AC
+
+ children
+
+ 420EF5F92CB2F4AAC83EE210
+ 7A3E559FD770C00738A65287
+ 60961F768D76907B370B2372
+ 6D7553EA99BA34A221C8FF5A
+
+ isa
+ PBXGroup
+ name
+ Frameworks
+ sourceTree
+ <group>
+
+ 31F14D6FF664B9445D965A9B
+
+ includeInIndex
+ 1
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.xcconfig
+ name
+ Pods-RoutePatterns_Tests.debug.xcconfig
+ path
+ Pods/Target Support Files/Pods-RoutePatterns_Tests/Pods-RoutePatterns_Tests.debug.xcconfig
+ sourceTree
+ <group>
+
+ 328A1D340421006AEE73F2E5
+
+ fileRef
+ 60961F768D76907B370B2372
+ isa
+ PBXBuildFile
+
+ 3341D564529E3FB8309A0E12
+
+ includeInIndex
+ 1
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.xcconfig
+ name
+ Pods-RoutePatterns_Example.debug.xcconfig
+ path
+ Pods/Target Support Files/Pods-RoutePatterns_Example/Pods-RoutePatterns_Example.debug.xcconfig
+ sourceTree
+ <group>
+
+ 420EF5F92CB2F4AAC83EE210
+
+ explicitFileType
+ wrapper.framework
+ includeInIndex
+ 0
+ isa
+ PBXFileReference
+ path
+ Pods_RoutePatterns_Example.framework
+ sourceTree
+ BUILT_PRODUCTS_DIR
+
+ 4B1B919AF1DD570060652FEE
+
+ fileRef
+ 7A3E559FD770C00738A65287
+ isa
+ PBXBuildFile
+
+ 52484F0E1CD4086500D65195
+
+ fileEncoding
+ 4
+ isa
+ PBXFileReference
+ lastKnownFileType
+ sourcecode.swift
+ path
+ DeepLink.swift
+ sourceTree
+ <group>
+
+ 52484F0F1CD4086500D65195
+
+ fileEncoding
+ 4
+ isa
+ PBXFileReference
+ lastKnownFileType
+ sourcecode.swift
+ path
+ DeepLinker.swift
+ sourceTree
+ <group>
+
+ 52484F101CD4086500D65195
+
+ fileRef
+ 52484F0E1CD4086500D65195
+ isa
+ PBXBuildFile
+
+ 52484F111CD4086500D65195
+
+ fileRef
+ 52484F0F1CD4086500D65195
+ isa
+ PBXBuildFile
+
+ 52A2D3D31CE6834B0047B233
+
+ fileEncoding
+ 4
+ isa
+ PBXFileReference
+ lastKnownFileType
+ net.daringfireball.markdown
+ path
+ TODO.md
+ sourceTree
+ <group>
+
+ 52A2D3D41CE6834B0047B233
+
+ fileRef
+ 52A2D3D31CE6834B0047B233
+ isa
+ PBXBuildFile
+
+ 607FACC71AFB9204008FA782
+
+ children
+
+ 607FACF51AFB993E008FA782
+ 607FACD21AFB9204008FA782
+ 607FACE81AFB9204008FA782
+ 607FACD11AFB9204008FA782
+ 9DCD43277AC5972AD780930E
+ 19BD0D0E3E101FBDBD3AE2AC
+
+ isa
+ PBXGroup
+ sourceTree
+ <group>
+
+ 607FACC81AFB9204008FA782
+
+ attributes
+
+ LastSwiftUpdateCheck
+ 0720
+ LastUpgradeCheck
+ 0720
+ ORGANIZATIONNAME
+ CocoaPods
+ TargetAttributes
+
+ 607FACCF1AFB9204008FA782
+
+ CreatedOnToolsVersion
+ 6.3.1
+
+ 607FACE41AFB9204008FA782
+
+ CreatedOnToolsVersion
+ 6.3.1
+ TestTargetID
+ 607FACCF1AFB9204008FA782
+
+
+
+ buildConfigurationList
+ 607FACCB1AFB9204008FA782
+ compatibilityVersion
+ Xcode 3.2
+ developmentRegion
+ English
+ hasScannedForEncodings
+ 0
+ isa
+ PBXProject
+ knownRegions
+
+ en
+ Base
+
+ mainGroup
+ 607FACC71AFB9204008FA782
+ productRefGroup
+ 607FACD11AFB9204008FA782
+ projectDirPath
+
+ projectReferences
+
+ projectRoot
+
+ targets
+
+ 607FACCF1AFB9204008FA782
+ 607FACE41AFB9204008FA782
+
+
+ 607FACCB1AFB9204008FA782
+
+ buildConfigurations
+
+ 607FACED1AFB9204008FA782
+ 607FACEE1AFB9204008FA782
+
+ defaultConfigurationIsVisible
+ 0
+ defaultConfigurationName
+ Release
+ isa
+ XCConfigurationList
+
+ 607FACCC1AFB9204008FA782
+
+ buildActionMask
+ 2147483647
+ files
+
+ 607FACD61AFB9204008FA782
+ 52484F111CD4086500D65195
+ 52484F101CD4086500D65195
+
+ isa
+ PBXSourcesBuildPhase
+ runOnlyForDeploymentPostprocessing
+ 0
+
+ 607FACCD1AFB9204008FA782
+
+ buildActionMask
+ 2147483647
+ files
+
+ CE3632B9B3A9FB34CBCC0F4B
+ 328A1D340421006AEE73F2E5
+
+ isa
+ PBXFrameworksBuildPhase
+ runOnlyForDeploymentPostprocessing
+ 0
+
+ 607FACCE1AFB9204008FA782
+
+ buildActionMask
+ 2147483647
+ files
+
+ 607FACDB1AFB9204008FA782
+ 607FACE01AFB9204008FA782
+ 52A2D3D41CE6834B0047B233
+ 607FACDD1AFB9204008FA782
+
+ isa
+ PBXResourcesBuildPhase
+ runOnlyForDeploymentPostprocessing
+ 0
+
+ 607FACCF1AFB9204008FA782
+
+ buildConfigurationList
+ 607FACEF1AFB9204008FA782
+ buildPhases
+
+ F199345C9703A1736DBE77C4
+ 607FACCC1AFB9204008FA782
+ 607FACCD1AFB9204008FA782
+ 607FACCE1AFB9204008FA782
+ 8FB60C215339BABAF14E2D62
+ 9518AD4E4BDA9F0E3FB9183B
+
+ buildRules
+
+ dependencies
+
+ isa
+ PBXNativeTarget
+ name
+ URLPatterns_Example
+ productName
+ RoutePatterns
+ productReference
+ 607FACD01AFB9204008FA782
+ productType
+ com.apple.product-type.application
+
+ 607FACD01AFB9204008FA782
+
+ explicitFileType
+ wrapper.application
+ includeInIndex
+ 0
+ isa
+ PBXFileReference
+ path
+ URLPatterns_Example.app
+ sourceTree
+ BUILT_PRODUCTS_DIR
+
+ 607FACD11AFB9204008FA782
+
+ children
+
+ 607FACD01AFB9204008FA782
+ 607FACE51AFB9204008FA782
+
+ isa
+ PBXGroup
+ name
+ Products
+ sourceTree
+ <group>
+
+ 607FACD21AFB9204008FA782
+
+ children
+
+ 607FACD51AFB9204008FA782
+ 52484F0E1CD4086500D65195
+ 52484F0F1CD4086500D65195
+ 607FACD91AFB9204008FA782
+ 607FACDC1AFB9204008FA782
+ 607FACDE1AFB9204008FA782
+ 607FACD31AFB9204008FA782
+
+ isa
+ PBXGroup
+ path
+ Source
+ sourceTree
+ <group>
+
+ 607FACD31AFB9204008FA782
+
+ children
+
+ 607FACD41AFB9204008FA782
+
+ isa
+ PBXGroup
+ name
+ Supporting Files
+ sourceTree
+ <group>
+
+ 607FACD41AFB9204008FA782
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.xml
+ name
+ Info.plist
+ path
+ ../Info.plist
+ sourceTree
+ <group>
+
+ 607FACD51AFB9204008FA782
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ sourcecode.swift
+ path
+ AppDelegate.swift
+ sourceTree
+ <group>
+
+ 607FACD61AFB9204008FA782
+
+ fileRef
+ 607FACD51AFB9204008FA782
+ isa
+ PBXBuildFile
+
+ 607FACD91AFB9204008FA782
+
+ children
+
+ 607FACDA1AFB9204008FA782
+
+ isa
+ PBXVariantGroup
+ name
+ Main.storyboard
+ sourceTree
+ <group>
+
+ 607FACDA1AFB9204008FA782
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ file.storyboard
+ name
+ Base
+ path
+ Base.lproj/Main.storyboard
+ sourceTree
+ <group>
+
+ 607FACDB1AFB9204008FA782
+
+ fileRef
+ 607FACD91AFB9204008FA782
+ isa
+ PBXBuildFile
+
+ 607FACDC1AFB9204008FA782
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ folder.assetcatalog
+ path
+ Images.xcassets
+ sourceTree
+ <group>
+
+ 607FACDD1AFB9204008FA782
+
+ fileRef
+ 607FACDC1AFB9204008FA782
+ isa
+ PBXBuildFile
+
+ 607FACDE1AFB9204008FA782
+
+ children
+
+ 607FACDF1AFB9204008FA782
+
+ isa
+ PBXVariantGroup
+ name
+ LaunchScreen.xib
+ sourceTree
+ <group>
+
+ 607FACDF1AFB9204008FA782
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ file.xib
+ name
+ Base
+ path
+ Base.lproj/LaunchScreen.xib
+ sourceTree
+ <group>
+
+ 607FACE01AFB9204008FA782
+
+ fileRef
+ 607FACDE1AFB9204008FA782
+ isa
+ PBXBuildFile
+
+ 607FACE11AFB9204008FA782
+
+ buildActionMask
+ 2147483647
+ files
+
+ 607FACEC1AFB9204008FA782
+
+ isa
+ PBXSourcesBuildPhase
+ runOnlyForDeploymentPostprocessing
+ 0
+
+ 607FACE21AFB9204008FA782
+
+ buildActionMask
+ 2147483647
+ files
+
+ 4B1B919AF1DD570060652FEE
+ 04AC2450233B25049373E0FD
+
+ isa
+ PBXFrameworksBuildPhase
+ runOnlyForDeploymentPostprocessing
+ 0
+
+ 607FACE31AFB9204008FA782
+
+ buildActionMask
+ 2147483647
+ files
+
+ isa
+ PBXResourcesBuildPhase
+ runOnlyForDeploymentPostprocessing
+ 0
+
+ 607FACE41AFB9204008FA782
+
+ buildConfigurationList
+ 607FACF21AFB9204008FA782
+ buildPhases
+
+ FF5124D308E46B52037DF9F1
+ 607FACE11AFB9204008FA782
+ 607FACE21AFB9204008FA782
+ 607FACE31AFB9204008FA782
+ 083BBF27E4A3856F9B8FA743
+ E2C2146117CCD0A6BAC5ED48
+
+ buildRules
+
+ dependencies
+
+ 607FACE71AFB9204008FA782
+
+ isa
+ PBXNativeTarget
+ name
+ URLPatterns_Tests
+ productName
+ Tests
+ productReference
+ 607FACE51AFB9204008FA782
+ productType
+ com.apple.product-type.bundle.unit-test
+
+ 607FACE51AFB9204008FA782
+
+ explicitFileType
+ wrapper.cfbundle
+ includeInIndex
+ 0
+ isa
+ PBXFileReference
+ path
+ URLPatterns_Example.xctest
+ sourceTree
+ BUILT_PRODUCTS_DIR
+
+ 607FACE61AFB9204008FA782
+
+ containerPortal
+ 607FACC81AFB9204008FA782
+ isa
+ PBXContainerItemProxy
+ proxyType
+ 1
+ remoteGlobalIDString
+ 607FACCF1AFB9204008FA782
+ remoteInfo
+ RoutePatterns
+
+ 607FACE71AFB9204008FA782
+
+ isa
+ PBXTargetDependency
+ target
+ 607FACCF1AFB9204008FA782
+ targetProxy
+ 607FACE61AFB9204008FA782
+
+ 607FACE81AFB9204008FA782
+
+ children
+
+ 607FACEB1AFB9204008FA782
+ 607FACE91AFB9204008FA782
+
+ isa
+ PBXGroup
+ path
+ Tests
+ sourceTree
+ <group>
+
+ 607FACE91AFB9204008FA782
+
+ children
+
+ 607FACEA1AFB9204008FA782
+
+ isa
+ PBXGroup
+ name
+ Supporting Files
+ sourceTree
+ <group>
+
+ 607FACEA1AFB9204008FA782
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.plist.xml
+ path
+ Info.plist
+ sourceTree
+ <group>
+
+ 607FACEB1AFB9204008FA782
+
+ isa
+ PBXFileReference
+ lastKnownFileType
+ sourcecode.swift
+ path
+ Tests.swift
+ sourceTree
+ <group>
+
+ 607FACEC1AFB9204008FA782
+
+ fileRef
+ 607FACEB1AFB9204008FA782
+ isa
+ PBXBuildFile
+
+ 607FACED1AFB9204008FA782
+
+ buildSettings
+
+ ALWAYS_SEARCH_USER_PATHS
+ NO
+ CLANG_CXX_LANGUAGE_STANDARD
+ gnu++0x
+ CLANG_CXX_LIBRARY
+ libc++
+ CLANG_ENABLE_MODULES
+ YES
+ CLANG_ENABLE_OBJC_ARC
+ YES
+ CLANG_WARN_BOOL_CONVERSION
+ YES
+ CLANG_WARN_CONSTANT_CONVERSION
+ YES
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE
+ YES_ERROR
+ CLANG_WARN_EMPTY_BODY
+ YES
+ CLANG_WARN_ENUM_CONVERSION
+ YES
+ CLANG_WARN_INT_CONVERSION
+ YES
+ CLANG_WARN_OBJC_ROOT_CLASS
+ YES_ERROR
+ CLANG_WARN_UNREACHABLE_CODE
+ YES
+ CLANG_WARN__DUPLICATE_METHOD_MATCH
+ YES
+ CODE_SIGN_IDENTITY[sdk=iphoneos*]
+ iPhone Developer
+ 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
+ GCC_OPTIMIZATION_LEVEL
+ 0
+ GCC_PREPROCESSOR_DEFINITIONS
+
+ DEBUG=1
+ $(inherited)
+
+ GCC_SYMBOLS_PRIVATE_EXTERN
+ NO
+ GCC_WARN_64_TO_32_BIT_CONVERSION
+ YES
+ GCC_WARN_ABOUT_RETURN_TYPE
+ YES_ERROR
+ GCC_WARN_UNDECLARED_SELECTOR
+ YES
+ GCC_WARN_UNINITIALIZED_AUTOS
+ YES_AGGRESSIVE
+ GCC_WARN_UNUSED_FUNCTION
+ YES
+ GCC_WARN_UNUSED_VARIABLE
+ YES
+ IPHONEOS_DEPLOYMENT_TARGET
+ 8.3
+ MTL_ENABLE_DEBUG_INFO
+ YES
+ ONLY_ACTIVE_ARCH
+ YES
+ SDKROOT
+ iphoneos
+ SWIFT_OPTIMIZATION_LEVEL
+ -Onone
+
+ isa
+ XCBuildConfiguration
+ name
+ Debug
+
+ 607FACEE1AFB9204008FA782
+
+ buildSettings
+
+ ALWAYS_SEARCH_USER_PATHS
+ NO
+ CLANG_CXX_LANGUAGE_STANDARD
+ gnu++0x
+ CLANG_CXX_LIBRARY
+ libc++
+ CLANG_ENABLE_MODULES
+ YES
+ CLANG_ENABLE_OBJC_ARC
+ YES
+ CLANG_WARN_BOOL_CONVERSION
+ YES
+ CLANG_WARN_CONSTANT_CONVERSION
+ YES
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE
+ YES_ERROR
+ CLANG_WARN_EMPTY_BODY
+ YES
+ CLANG_WARN_ENUM_CONVERSION
+ YES
+ CLANG_WARN_INT_CONVERSION
+ YES
+ CLANG_WARN_OBJC_ROOT_CLASS
+ YES_ERROR
+ CLANG_WARN_UNREACHABLE_CODE
+ YES
+ CLANG_WARN__DUPLICATE_METHOD_MATCH
+ YES
+ CODE_SIGN_IDENTITY[sdk=iphoneos*]
+ iPhone Developer
+ COPY_PHASE_STRIP
+ NO
+ DEBUG_INFORMATION_FORMAT
+ dwarf-with-dsym
+ ENABLE_NS_ASSERTIONS
+ NO
+ ENABLE_STRICT_OBJC_MSGSEND
+ YES
+ GCC_C_LANGUAGE_STANDARD
+ gnu99
+ GCC_NO_COMMON_BLOCKS
+ YES
+ GCC_WARN_64_TO_32_BIT_CONVERSION
+ YES
+ GCC_WARN_ABOUT_RETURN_TYPE
+ YES_ERROR
+ GCC_WARN_UNDECLARED_SELECTOR
+ YES
+ GCC_WARN_UNINITIALIZED_AUTOS
+ YES_AGGRESSIVE
+ GCC_WARN_UNUSED_FUNCTION
+ YES
+ GCC_WARN_UNUSED_VARIABLE
+ YES
+ IPHONEOS_DEPLOYMENT_TARGET
+ 8.3
+ MTL_ENABLE_DEBUG_INFO
+ NO
+ SDKROOT
+ iphoneos
+ VALIDATE_PRODUCT
+ YES
+
+ isa
+ XCBuildConfiguration
+ name
+ Release
+
+ 607FACEF1AFB9204008FA782
+
+ buildConfigurations
+
+ 607FACF01AFB9204008FA782
+ 607FACF11AFB9204008FA782
+
+ defaultConfigurationIsVisible
+ 0
+ defaultConfigurationName
+ Release
+ isa
+ XCConfigurationList
+
+ 607FACF01AFB9204008FA782
+
+ baseConfigurationReference
+ 82207C030FAC5BD36B749741
+ buildSettings
+
+ ASSETCATALOG_COMPILER_APPICON_NAME
+ AppIcon
+ INFOPLIST_FILE
+ Info.plist
+ LD_RUNPATH_SEARCH_PATHS
+ $(inherited) @executable_path/Frameworks
+ MODULE_NAME
+ ExampleApp
+ PRODUCT_BUNDLE_IDENTIFIER
+ org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)
+ PRODUCT_NAME
+ URLPatterns_Example
+
+ isa
+ XCBuildConfiguration
+ name
+ Debug
+
+ 607FACF11AFB9204008FA782
+
+ baseConfigurationReference
+ 77F91B464F092D4B8B42EE69
+ buildSettings
+
+ ASSETCATALOG_COMPILER_APPICON_NAME
+ AppIcon
+ INFOPLIST_FILE
+ Info.plist
+ LD_RUNPATH_SEARCH_PATHS
+ $(inherited) @executable_path/Frameworks
+ MODULE_NAME
+ ExampleApp
+ PRODUCT_BUNDLE_IDENTIFIER
+ org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)
+ PRODUCT_NAME
+ URLPatterns_Example
+
+ isa
+ XCBuildConfiguration
+ name
+ Release
+
+ 607FACF21AFB9204008FA782
+
+ buildConfigurations
+
+ 607FACF31AFB9204008FA782
+ 607FACF41AFB9204008FA782
+
+ defaultConfigurationIsVisible
+ 0
+ defaultConfigurationName
+ Release
+ isa
+ XCConfigurationList
+
+ 607FACF31AFB9204008FA782
+
+ baseConfigurationReference
+ CC9BAB497C95F30DBFA0BE84
+ buildSettings
+
+ FRAMEWORK_SEARCH_PATHS
+
+ $(SDKROOT)/Developer/Library/Frameworks
+ $(inherited)
+
+ GCC_PREPROCESSOR_DEFINITIONS
+
+ DEBUG=1
+ $(inherited)
+
+ 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
+ URLPatterns_Example
+
+ isa
+ XCBuildConfiguration
+ name
+ Debug
+
+ 607FACF41AFB9204008FA782
+
+ baseConfigurationReference
+ 7CEDBEB38D0715BCD182B958
+ buildSettings
+
+ FRAMEWORK_SEARCH_PATHS
+
+ $(SDKROOT)/Developer/Library/Frameworks
+ $(inherited)
+
+ 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
+ URLPatterns_Example
+
+ isa
+ XCBuildConfiguration
+ name
+ Release
+
+ 607FACF51AFB993E008FA782
+
+ children
+
+ B29E1194CFEFFC4565D88853
+ 52A2D3D31CE6834B0047B233
+ C6FA60F6465206D70E1FBBF2
+ BE59EFF3174E9618FC1B3145
+
+ isa
+ PBXGroup
+ name
+ Podspec Metadata
+ sourceTree
+ <group>
+
+ 60961F768D76907B370B2372
+
+ explicitFileType
+ wrapper.framework
+ includeInIndex
+ 0
+ isa
+ PBXFileReference
+ path
+ Pods_URLPatterns_Example.framework
+ sourceTree
+ BUILT_PRODUCTS_DIR
+
+ 6D7553EA99BA34A221C8FF5A
+
+ explicitFileType
+ wrapper.framework
+ includeInIndex
+ 0
+ isa
+ PBXFileReference
+ path
+ Pods_URLPatterns_Tests.framework
+ sourceTree
+ BUILT_PRODUCTS_DIR
+
+ 6F960D29C60F05E780539907
+
+ includeInIndex
+ 1
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.xcconfig
+ name
+ Pods-RoutePatterns_Tests.release.xcconfig
+ path
+ Pods/Target Support Files/Pods-RoutePatterns_Tests/Pods-RoutePatterns_Tests.release.xcconfig
+ sourceTree
+ <group>
+
+ 77F91B464F092D4B8B42EE69
+
+ includeInIndex
+ 1
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.xcconfig
+ name
+ Pods-URLPatterns_Example.release.xcconfig
+ path
+ Pods/Target Support Files/Pods-URLPatterns_Example/Pods-URLPatterns_Example.release.xcconfig
+ sourceTree
+ <group>
+
+ 7A3E559FD770C00738A65287
+
+ explicitFileType
+ wrapper.framework
+ includeInIndex
+ 0
+ isa
+ PBXFileReference
+ path
+ Pods_RoutePatterns_Tests.framework
+ sourceTree
+ BUILT_PRODUCTS_DIR
+
+ 7CEDBEB38D0715BCD182B958
+
+ includeInIndex
+ 1
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.xcconfig
+ name
+ Pods-URLPatterns_Tests.release.xcconfig
+ path
+ Pods/Target Support Files/Pods-URLPatterns_Tests/Pods-URLPatterns_Tests.release.xcconfig
+ sourceTree
+ <group>
+
+ 82207C030FAC5BD36B749741
+
+ includeInIndex
+ 1
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.xcconfig
+ name
+ Pods-URLPatterns_Example.debug.xcconfig
+ path
+ Pods/Target Support Files/Pods-URLPatterns_Example/Pods-URLPatterns_Example.debug.xcconfig
+ sourceTree
+ <group>
+
+ 8FB60C215339BABAF14E2D62
+
+ buildActionMask
+ 2147483647
+ files
+
+ inputPaths
+
+ isa
+ PBXShellScriptBuildPhase
+ name
+ Embed Pods Frameworks
+ outputPaths
+
+ runOnlyForDeploymentPostprocessing
+ 0
+ shellPath
+ /bin/sh
+ shellScript
+ "${SRCROOT}/Pods/Target Support Files/Pods-URLPatterns_Example/Pods-URLPatterns_Example-frameworks.sh"
+
+ showEnvVarsInLog
+ 0
+
+ 9518AD4E4BDA9F0E3FB9183B
+
+ buildActionMask
+ 2147483647
+ files
+
+ inputPaths
+
+ isa
+ PBXShellScriptBuildPhase
+ name
+ Copy Pods Resources
+ outputPaths
+
+ runOnlyForDeploymentPostprocessing
+ 0
+ shellPath
+ /bin/sh
+ shellScript
+ "${SRCROOT}/Pods/Target Support Files/Pods-URLPatterns_Example/Pods-URLPatterns_Example-resources.sh"
+
+ showEnvVarsInLog
+ 0
+
+ 9DCD43277AC5972AD780930E
+
+ children
+
+ 3341D564529E3FB8309A0E12
+ B18781699E0A2D9305FD283F
+ 31F14D6FF664B9445D965A9B
+ 6F960D29C60F05E780539907
+ 82207C030FAC5BD36B749741
+ 77F91B464F092D4B8B42EE69
+ CC9BAB497C95F30DBFA0BE84
+ 7CEDBEB38D0715BCD182B958
+
+ isa
+ PBXGroup
+ name
+ Pods
+ sourceTree
+ <group>
+
+ B18781699E0A2D9305FD283F
+
+ includeInIndex
+ 1
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.xcconfig
+ name
+ Pods-RoutePatterns_Example.release.xcconfig
+ path
+ Pods/Target Support Files/Pods-RoutePatterns_Example/Pods-RoutePatterns_Example.release.xcconfig
+ sourceTree
+ <group>
+
+ B29E1194CFEFFC4565D88853
+
+ includeInIndex
+ 1
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text
+ name
+ URLPatterns.podspec
+ path
+ ../URLPatterns.podspec
+ sourceTree
+ <group>
+
+ BE59EFF3174E9618FC1B3145
+
+ includeInIndex
+ 1
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text
+ name
+ LICENSE
+ path
+ ../LICENSE
+ sourceTree
+ <group>
+
+ C6FA60F6465206D70E1FBBF2
+
+ includeInIndex
+ 1
+ isa
+ PBXFileReference
+ lastKnownFileType
+ net.daringfireball.markdown
+ name
+ README.md
+ path
+ ../README.md
+ sourceTree
+ <group>
+
+ CC9BAB497C95F30DBFA0BE84
+
+ includeInIndex
+ 1
+ isa
+ PBXFileReference
+ lastKnownFileType
+ text.xcconfig
+ name
+ Pods-URLPatterns_Tests.debug.xcconfig
+ path
+ Pods/Target Support Files/Pods-URLPatterns_Tests/Pods-URLPatterns_Tests.debug.xcconfig
+ sourceTree
+ <group>
+
+ CE3632B9B3A9FB34CBCC0F4B
+
+ fileRef
+ 420EF5F92CB2F4AAC83EE210
+ isa
+ PBXBuildFile
+
+ E2C2146117CCD0A6BAC5ED48
+
+ buildActionMask
+ 2147483647
+ files
+
+ inputPaths
+
+ isa
+ PBXShellScriptBuildPhase
+ name
+ Copy Pods Resources
+ outputPaths
+
+ runOnlyForDeploymentPostprocessing
+ 0
+ shellPath
+ /bin/sh
+ shellScript
+ "${SRCROOT}/Pods/Target Support Files/Pods-URLPatterns_Tests/Pods-URLPatterns_Tests-resources.sh"
+
+ showEnvVarsInLog
+ 0
+
+ F199345C9703A1736DBE77C4
+
+ buildActionMask
+ 2147483647
+ files
+
+ inputPaths
+
+ isa
+ PBXShellScriptBuildPhase
+ name
+ Check Pods Manifest.lock
+ outputPaths
+
+ runOnlyForDeploymentPostprocessing
+ 0
+ shellPath
+ /bin/sh
+ shellScript
+ diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null
+if [[ $? != 0 ]] ; then
+ cat << EOM
+error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.
+EOM
+ exit 1
+fi
+
+ showEnvVarsInLog
+ 0
+
+ FF5124D308E46B52037DF9F1
+
+ buildActionMask
+ 2147483647
+ files
+
+ inputPaths
+
+ isa
+ PBXShellScriptBuildPhase
+ name
+ Check Pods Manifest.lock
+ outputPaths
+
+ runOnlyForDeploymentPostprocessing
+ 0
+ shellPath
+ /bin/sh
+ shellScript
+ diff "${PODS_ROOT}/../Podfile.lock" "${PODS_ROOT}/Manifest.lock" > /dev/null
+if [[ $? != 0 ]] ; then
+ cat << EOM
+error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.
+EOM
+ exit 1
+fi
+
+ showEnvVarsInLog
+ 0
+
+
+ rootObject
+ 607FACC81AFB9204008FA782
+
+
diff --git a/Example/URLPatterns.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Example/URLPatterns.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..f59e7a5
--- /dev/null
+++ b/Example/URLPatterns.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/Example/URLPatterns.xcworkspace/contents.xcworkspacedata b/Example/URLPatterns.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..0581840
--- /dev/null
+++ b/Example/URLPatterns.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..6429757
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2016 johnmorgan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1057b5a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,65 @@
+# 🎯 URLPatterns 🎯
+
+[![Version](https://img.shields.io/cocoapods/v/URLPatterns.svg?style=flat)](http://cocoapods.org/pods/URLPatterns)
+[![License](https://img.shields.io/cocoapods/l/URLPatterns.svg?style=flat)](http://cocoapods.org/pods/URLPatterns)
+
+URLPatterns is a small library to enable more idiomatic Swift pattern matching of URL path elements.
+
+`NSURL` is extended with the method `countedPathElements()`, which converts the URL's' array of path elements into a `Counted` enum. Each case in `Counted` has a different number of associated values, which makes pattern-matching each element easy:
+
+```swift
+if case .N4("user", let userId, "profile", _) = url.countedPathElements() {
+ // show profile for userId
+}
+```
+
+ `Counted` enables us to pattern match paths with any number of elements, and supports **expression**, **wildcard** and **value-binding** patterns for its associated values. It can also match based on `Begins` and `Ends`, which match based on the first/ last elements only. Here's an example of a DeepLink enum which has a failable initializer that takes an `NSURL`:
+
+
+```swift
+enum DeepLink {
+
+ case Home, History, Settings, Terms, News
+ case Chat(room: String)
+ case Profile(userId: String)
+}
+
+extension DeepLink {
+
+ init?(url: NSURL) {
+
+ guard url.scheme == "myscheme" else { return nil }
+ guard url.host == "myhost" else { return nil }
+
+ switch url.countedPathComponents() {
+
+ case .N0, .N1(""): self = .Home
+ case .N1("history"): self = .History
+ case .N2(_, "settings"): self = .Settings
+ case .N2("chat", let room): self = .Chat(room: room)
+ case .N3("users", let userId, "profile"): self = .Profile(userId: userId)
+ case Begins("news", "latest"): self = .News
+ case Ends("terms"): self = .Terms
+
+ default: return nil
+ }
+ }
+}
+```
+
+## Installation
+
+URLPatterns is available through [CocoaPods](http://cocoapods.org). To install
+it, simply add the following line to your Podfile:
+
+```ruby
+pod "URLPatterns"
+```
+
+## Author
+
+johnmorgan, johnpatrickmorganuk@gmail.com
+
+## License
+
+URLPatterns is available under the MIT license. See the LICENSE file for more info.
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..f584ddd
--- /dev/null
+++ b/TODO
@@ -0,0 +1,3 @@
+
+- Add pattern matching for .Starts(Counted) and .Ends(Counted)
+- CollectionType
\ No newline at end of file
diff --git a/URLPatterns.podspec b/URLPatterns.podspec
new file mode 100644
index 0000000..1383414
--- /dev/null
+++ b/URLPatterns.podspec
@@ -0,0 +1,23 @@
+
+Pod::Spec.new do |s|
+ s.name = "URLPatterns"
+ s.version = "0.1.0"
+ s.summary = "A small library to enable more idiomatic Swift pattern matching of URL path elements."
+
+ s.description = <<-DESC
+ URLPatterns is a small library to enable more idiomatic Swift pattern matching of URL path elements.
+ `NSURL` is extended with the method `countedPathElements()`, which converts the URL's' array of path elements
+ into a `Counted` enum. Each case in `Counted` has a different number of associated values, which makes
+ pattern-matching each element easy, including wildcard, value-binding, begins and ends patterns.
+ DESC
+
+ s.homepage = "https://github.com/johnpatrickmorgan/URLPatterns"
+ s.license = 'MIT'
+ s.author = { "johnmorgan" => "johnpatrickmorganuk@gmail.com" }
+ s.source = { :git => "https://github.com//johnpatrickmorgan/URLPatterns.git", :tag => s.version.to_s }
+ s.social_media_url = 'https://twitter.com/jpmmusic'
+
+ s.ios.deployment_target = '8.0'
+
+ s.source_files = 'URLPatterns/Classes/**/*'
+end
diff --git a/URLPatterns/Assets/.gitkeep b/URLPatterns/Assets/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/URLPatterns/Classes/.gitkeep b/URLPatterns/Classes/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/URLPatterns/Classes/Counted.swift b/URLPatterns/Classes/Counted.swift
new file mode 100644
index 0000000..fc6d565
--- /dev/null
+++ b/URLPatterns/Classes/Counted.swift
@@ -0,0 +1,151 @@
+//
+// Counted.swift
+// Pods
+//
+// Created by John Morgan on 29/04/2016.
+//
+//
+
+public enum Counted {
+
+ public typealias E = Element
+
+ case N0
+ case N1(E)
+ case N2(E, E)
+ case N3(E, E, E)
+ case N4(E, E, E, E)
+ case N5(E, E, E, E, E)
+ case N6(E, E, E, E, E, E)
+ case N7(E, E, E, E, E, E, E)
+ case N8(E, E, E, E, E, E, E, E)
+ case N9(E, E, E, E, E, E, E, E, E)
+ case N10(E, E, E, E, E, E, E, E, E, E)
+
+ indirect case N10Plus(E, E, E, E, E, E, E, E, E, E, Counted)
+
+ public init(_ elements: [Element]) {
+
+ let e = elements
+
+ switch e.count {
+ case 0:
+ self = .N0
+ case 1:
+ self = .N1(e[0])
+ case 2:
+ self = .N2(e[0], e[1])
+ case 3:
+ self = .N3(e[0], e[1], e[2])
+ case 4:
+ self = .N4(e[0], e[1], e[2], e[3])
+ case 5:
+ self = .N5(e[0], e[1], e[2], e[3], e[4])
+ case 6:
+ self = .N6(e[0], e[1], e[2], e[3], e[4], e[5])
+ case 7:
+ self = .N7(e[0], e[1], e[2], e[3], e[4], e[5], e[6])
+ case 8:
+ self = .N8(e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7])
+ case 9:
+ self = .N9(e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7], e[8])
+ case 10:
+ self = .N10(e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7], e[8], e[9])
+ default:
+ self = .N10Plus(e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7], e[8], e[9], Counted(Array(e[10..(sequence: S) {
+
+ self.init(Array(sequence))
+ }
+
+ public var elements: [Element] {
+
+ switch self {
+ case .N0:
+ return []
+ case let .N1(e1):
+ return [e1]
+ case let .N2(e1, e2):
+ return [e1, e2]
+ case let .N3(e1, e2, e3):
+ return [e1, e2, e3]
+ case let .N4(e1, e2, e3, e4):
+ return [e1, e2, e3, e4]
+ case let .N5(e1, e2, e3, e4, e5):
+ return [e1, e2, e3, e4, e5]
+ case let .N6(e1, e2, e3, e4, e5, e6):
+ return [e1, e2, e3, e4, e5, e6]
+ case let .N7(e1, e2, e3, e4, e5, e6, e7):
+ return [e1, e2, e3, e4, e5, e6, e7]
+ case let .N8(e1, e2, e3, e4, e5, e6, e7, e8):
+ return [e1, e2, e3, e4, e5, e6, e7, e8]
+ case let .N9(e1, e2, e3, e4, e5, e6, e7, e8, e9):
+ return [e1, e2, e3, e4, e5, e6, e7, e8, e9]
+ case let .N10(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10):
+ return [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10]
+ case let .N10Plus(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, remainder):
+ return [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10] + remainder.elements
+ }
+ }
+
+ public mutating func append(x: Element) {
+
+ self = Counted(elements + [x])
+ }
+
+ public mutating func removeLast() -> Element? {
+
+ switch self {
+ case .N0: return nil
+ default:
+ var elements = self.elements
+ let popped = elements.removeLast()
+ self = Counted(elements)
+ return popped
+ }
+ }
+
+ public mutating func removeFirst() -> Element? {
+
+ switch self {
+ case .N0: return nil
+ default:
+ var elements = self.elements
+ let popped = elements.removeFirst()
+ self = Counted(elements)
+ return popped
+ }
+ }
+
+ public subscript(index: Int) -> Element {
+
+ return elements[index]
+ }
+}
+
+extension Counted: SequenceType {
+
+ public func generate() -> AnyGenerator {
+
+ var current = self
+ return AnyGenerator {
+ current.removeFirst()
+ }
+ }
+}
+
+extension Counted: ArrayLiteralConvertible {
+
+ public init(arrayLiteral elements: Element...) {
+
+ self.init(elements)
+ }
+}
diff --git a/URLPatterns/Classes/CountedExpressionMatching.swift b/URLPatterns/Classes/CountedExpressionMatching.swift
new file mode 100644
index 0000000..0e51b2a
--- /dev/null
+++ b/URLPatterns/Classes/CountedExpressionMatching.swift
@@ -0,0 +1,39 @@
+//
+// CountedExpressionMatching.swift
+// Pods
+//
+// Created by John Morgan on 14/05/2016.
+//
+//
+
+import Foundation
+
+public struct Begins {
+
+ var elements: [E]
+
+ public init(_ elements: E...) {
+
+ self.elements = elements
+ }
+}
+
+public func ~=(pattern: Begins, value: Counted) -> Bool {
+
+ return Array(value.elements.prefix(pattern.elements.count)) == pattern.elements
+}
+
+public struct Ends {
+
+ var elements: [E]
+
+ public init(_ elements: E...) {
+
+ self.elements = elements
+ }
+}
+
+public func ~=(pattern: Ends, value: Counted) -> Bool {
+
+ return Array(value.elements.suffix(pattern.elements.count)) == pattern.elements
+}
diff --git a/URLPatterns/Classes/FoundationExtensions.swift b/URLPatterns/Classes/FoundationExtensions.swift
new file mode 100644
index 0000000..3e7e0cc
--- /dev/null
+++ b/URLPatterns/Classes/FoundationExtensions.swift
@@ -0,0 +1,63 @@
+//
+// FoundationExtensions.swift
+// Pods
+//
+// Created by John Morgan on 29/04/2016.
+//
+//
+
+import Foundation
+
+extension NSURLComponents {
+
+ public func queryArguments() -> [String : String?] {
+
+ var arguments = [String : String?]()
+
+ for item in queryItems ?? [] {
+ arguments[item.name] = item.value
+ }
+ return arguments
+ }
+
+ public func flatQueryArguments() -> [String : String] {
+
+ var arguments = [String : String]()
+
+ for (key, value) in queryArguments() {
+ if value != nil {
+ arguments[key] = value
+ }
+ }
+ return arguments
+ }
+}
+
+extension NSURL {
+
+ public func countedPathComponents(excludingLeadingBackslash: Bool = true) -> Counted {
+
+ var components = pathComponents ?? []
+ if let first = components.first where excludingLeadingBackslash && first == "/" {
+ components.removeFirst()
+ }
+ return Counted(components)
+ }
+}
+
+extension NSURL {
+
+ public func queryArguments() -> [String : String?] {
+
+ guard let components = NSURLComponents(URL: self, resolvingAgainstBaseURL: true) else { return [:] }
+
+ return components.queryArguments()
+ }
+
+ public func flatQueryArguments() -> [String : String] {
+
+ guard let components = NSURLComponents(URL: self, resolvingAgainstBaseURL: true) else { return [:] }
+
+ return components.flatQueryArguments()
+ }
+}
diff --git a/_Pods.xcodeproj b/_Pods.xcodeproj
new file mode 120000
index 0000000..3c5a8e7
--- /dev/null
+++ b/_Pods.xcodeproj
@@ -0,0 +1 @@
+Example/Pods/Pods.xcodeproj
\ No newline at end of file