-
-
Save blakemerryman/76312e1cbf8aec248167 to your computer and use it in GitHub Desktop.
Wrap glob(3) in Swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Glob.swift | |
// | |
// Created by Brad Grzesiak on 6/25/15. | |
// Copyright © 2015 Bendyworks Inc. | |
// Released under the Apache v2 License. | |
// | |
import Darwin | |
class Glob: CollectionType { | |
var paths = [String]() | |
var startIndex: Int { return paths.startIndex } | |
var endIndex: Int { return paths.endIndex } | |
init(pattern: String) { | |
var gt = glob_t() | |
let cPattern = strdup(pattern) | |
if executeGlob(cPattern, gt: >) { | |
populateFiles(gt) | |
} | |
globfree(>) | |
} | |
// MARK: Private | |
private var globalFlags = GLOB_TILDE | GLOB_BRACE | GLOB_MARK | |
private func executeGlob(pattern: UnsafePointer<CChar>, gt: UnsafeMutablePointer<glob_t>) -> Bool { | |
return 0 == glob(pattern, globalFlags, nil, gt) | |
} | |
private func cPattern(pattern: String) -> UnsafeMutablePointer<Int8>? { | |
return strdup(pattern) | |
} | |
private func populateFiles(gt: glob_t) { | |
for var i = 0; i < Int(gt.gl_matchc); i++ { | |
if let path = String.fromCString(gt.gl_pathv[i]) { | |
paths.append(path) | |
} | |
} | |
} | |
// MARK: Subscript Support | |
subscript(i: Int) -> String { | |
return paths[i] | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// GlobTester.swift | |
// | |
// Created by Brad Grzesiak on 6/25/15. | |
// Copyright © 2015 Bendyworks Inc. | |
// Released under the Apache v2 License. | |
// | |
import XCTest | |
class GlobTester: XCTestCase { | |
let tmpFiles = ["foo", "bar", "baz"] | |
var tmpDir: String? | |
override func setUp() { | |
super.setUp() | |
var tmpDirTmpl = "/tmp/glob-test.XXXXX".cStringUsingEncoding(NSUTF8StringEncoding)! | |
self.tmpDir = String.fromCString(mkdtemp(&tmpDirTmpl)) | |
for file in tmpFiles { | |
close(open("\(tmpDir!)/\(file)", O_CREAT)) | |
} | |
} | |
override func tearDown() { | |
for file in tmpFiles { | |
unlink("\(tmpDir!)/\(file)") | |
} | |
rmdir(self.tmpDir!) | |
super.tearDown() | |
} | |
func testBraces() { | |
let pattern = "\(tmpDir!)/ba{r,y,z}" | |
let glob = Glob(pattern: pattern) | |
var contents = [String]() | |
for file in glob { | |
contents.append(file) | |
} | |
XCTAssertEqual(contents, ["\(tmpDir!)/bar", "\(tmpDir!)/baz"], "matching with braces failed") | |
} | |
func testNothingMatches() { | |
let pattern = "\(tmpDir!)/nothing" | |
let glob = Glob(pattern: pattern) | |
var contents = [String]() | |
for file in glob { | |
contents.append(file) | |
} | |
XCTAssertEqual(contents, [], "expected empty list of files") | |
} | |
func testDirectAccess() { | |
let pattern = "\(tmpDir!)/ba{r,y,z}" | |
let glob = Glob(pattern: pattern) | |
XCTAssertEqual(glob.paths, ["\(tmpDir!)/bar", "\(tmpDir!)/baz"], "matching with braces failed") | |
} | |
func testIterateTwice() { | |
let pattern = "\(tmpDir!)/ba{r,y,z}" | |
let glob = Glob(pattern: pattern) | |
var contents1 = [String]() | |
var contents2 = [String]() | |
for file in glob { | |
contents1.append(file) | |
} | |
let filesAfterOnce = glob.paths | |
for file in glob { | |
contents2.append(file) | |
} | |
XCTAssertEqual(contents1, contents2, "results for calling for-in twice are the same") | |
XCTAssertEqual(glob.paths, filesAfterOnce, "calling for-in twice doesn't only memoizes once") | |
} | |
func testIndexing() { | |
let pattern = "\(tmpDir!)/ba{r,y,z}" | |
let glob = Glob(pattern: pattern) | |
XCTAssertEqual(glob[0], "\(tmpDir!)/bar", "indexing") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I took this even further and added globstar (**) support: https://gist.github.com/efirestone/ce01ae109e08772647eb061b3bb387c3