diff --git a/MapPointMapper.xcodeproj/project.pbxproj b/MapPointMapper.xcodeproj/project.pbxproj index 9c4337e..15cbb34 100644 --- a/MapPointMapper.xcodeproj/project.pbxproj +++ b/MapPointMapper.xcodeproj/project.pbxproj @@ -195,7 +195,8 @@ 547424DC1A1C1CE800A8478C /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0610; + LastSwiftUpdateCheck = 0700; + LastUpgradeCheck = 0700; ORGANIZATIONNAME = dmiedema; TargetAttributes = { 547424E31A1C1CE800A8478C = { @@ -316,6 +317,7 @@ COPY_PHASE_STRIP = NO; EMBEDDED_CONTENT_CONTAINS_SWIFT = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -404,6 +406,7 @@ INFOPLIST_FILE = MapPointMapper/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.10; + PRODUCT_BUNDLE_IDENTIFIER = "dmiedema.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; RUN_CLANG_STATIC_ANALYZER = YES; @@ -440,6 +443,7 @@ INFOPLIST_FILE = MapPointMapper/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.10; + PRODUCT_BUNDLE_IDENTIFIER = "dmiedema.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; RUN_CLANG_STATIC_ANALYZER = YES; @@ -454,7 +458,6 @@ FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -462,6 +465,7 @@ ); INFOPLIST_FILE = MapPointMapperTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "dmiedema.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MapPointMapper.app/Contents/MacOS/MapPointMapper"; }; @@ -475,10 +479,10 @@ FRAMEWORK_SEARCH_PATHS = ( "$(DEVELOPER_FRAMEWORKS_DIR)", "$(inherited)", - "$(PROJECT_DIR)/Carthage/Build/Mac", ); INFOPLIST_FILE = MapPointMapperTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "dmiedema.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MapPointMapper.app/Contents/MacOS/MapPointMapper"; }; diff --git a/MapPointMapper/Info.plist b/MapPointMapper/Info.plist index bceefd8..2488ff6 100644 --- a/MapPointMapper/Info.plist +++ b/MapPointMapper/Info.plist @@ -9,7 +9,7 @@ CFBundleIconFile CFBundleIdentifier - dmiedema.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/MapPointMapper/Parser/Parser.swift b/MapPointMapper/Parser/Parser.swift index a3abd1c..ea5c522 100644 --- a/MapPointMapper/Parser/Parser.swift +++ b/MapPointMapper/Parser/Parser.swift @@ -12,6 +12,8 @@ import MapKit extension NSString { /** Convenience so `isEmpty` can be performed on an `NSString` instance just as if it were a `String` + + - returns: `true` if the string is empty, `false` if not */ var isEmpty: Bool { get { return self.length == 0 || self.isEqualToString("") } @@ -21,7 +23,7 @@ extension String { /** Strip all leading and trailing whitespace from a given `String` instance. - :returns: a newly stripped string instance. + - returns: a newly stripped string instance. */ func stringByStrippingLeadingAndTrailingWhiteSpace() -> String { let mutable = self.mutableCopy() as! NSMutableString @@ -35,12 +37,12 @@ class Parser { /** Parse a given string of Lat/Lng values to return a collection of `CLLocationCoordinate2D` arrays. - :note: The preferred way/format of the input string is `Well-Known Text` as the parser supports that for multipolygons and such + - note: The preferred way/format of the input string is `Well-Known Text` as the parser supports that for multipolygons and such - :param: input String to parse - :param: longitudeFirst Only used if it is determined to not be `Well-Known Text` format. + - parameter input: String to parse + - parameter longitudeFirst: Only used if it is determined to not be `Well-Known Text` format. - :returns: An array of `CLLocationCoordinate2D` arrays representing the parsed areas/lines + - returns: An array of `CLLocationCoordinate2D` arrays representing the parsed areas/lines */ class func parseString(input: NSString, longitudeFirst: Bool) -> [[CLLocationCoordinate2D]] { return Parser(longitudeFirst: longitudeFirst).parseInput(input) @@ -60,23 +62,23 @@ class Parser { /** Parse input string into a collection of `CLLocationCoordinate2D` arrays that can be drawn on a map - :note: This method supports (and really works best with/prefers) `Well-Known Text` format + - note: This method supports (and really works best with/prefers) `Well-Known Text` format - :param: input `NSString` to parse + - parameter input: `NSString` to parse - :returns: Collection of `CLLocationCoordinate2D` arrays + - returns: Collection of `CLLocationCoordinate2D` arrays */ internal func parseInput(input: NSString) -> [[CLLocationCoordinate2D]] { var array = [[NSString]]() - let line = input as! String + let line = input as String if isProbablyGeoString(line) { self.longitudeFirst = true var items = [NSString]() if isMultiItem(line) { - items = stripExtraneousCharacters(line).componentsSeparatedByString("),") as! [NSString] + items = stripExtraneousCharacters(line).componentsSeparatedByString("),") } else { items = [stripExtraneousCharacters(line)] } @@ -92,18 +94,19 @@ class Parser { /** Convert an array of strings into tuple pairs. - :note: the number of values passed in should probably be even, since it creates pairs. + - note: the number of values passed in should probably be even, since it creates pairs. - :param: array of `[NSString]` array to create tuples from + - parameter array: of `[NSString]` array to create tuples from - :returns: array of collections of tuple pairs where the tuples are lat/lng values as `NSString`s + - returns: array of collections of tuple pairs where the tuples are lat/lng values as `NSString`s */ internal func convertStringArraysToTuples(array: [[NSString]]) -> [[(NSString, NSString)]] { var tmpResults = [(NSString, NSString)]() var results = [[(NSString, NSString)]]() for arr in array { for var i = 0; i < arr.count - 1; i += 2 { - tmpResults.append((arr[i], arr[i + 1])) + let elem = (arr[i], arr[i + 1]) + tmpResults.append(elem) } if tmpResults.count == 1 { @@ -117,13 +120,13 @@ class Parser { } /** - :abstract: Naively format a `Well-Known Text` string into array of string values, where each string is a single value + _abstract_: Naively format a `Well-Known Text` string into array of string values, where each string is a single value - :discussion: This removes any lingering parens from the given string, breaks on `,` then breaks on ` ` while filtering out any empty strings. + _discussion_: This removes any lingering parens from the given string, breaks on `,` then breaks on ` ` while filtering out any empty strings. - :param: input String to format, assumed `Well-Known Text` format + - parameter input: String to format, assumed `Well-Known Text` format - :returns: array of strings where each string is one value from the string with all empty strings filtered out. + - returns: array of strings where each string is one value from the string with all empty strings filtered out. */ internal func formatStandardGeoDataString(input: NSString) -> [NSString] { // Remove Extra () @@ -150,7 +153,7 @@ class Parser { private func splitLine(input: NSString, delimiter: NSString) -> (NSString, NSString) { let array = input.componentsSeparatedByString(delimiter as String) - return (array.first! as! NSString, array.last! as! NSString) + return (array.first! as NSString, array.last! as NSString) } /** @@ -158,10 +161,10 @@ class Parser { :discussion: This attempts to parse the string's double values but does no safety checks if they can be parsed as `double`s. - :param: pairs array of `String` tuples to parse as `Double`s - :param: longitudeFirst boolean flag if the first item in the tuple should be the longitude value + - parameter pairs: array of `String` tuples to parse as `Double`s + - parameter longitudeFirst: boolean flag if the first item in the tuple should be the longitude value - :returns: array of `CLLocationCoordinate2D` values + - returns: array of `CLLocationCoordinate2D` values */ internal func convertToCoordinates(pairs: [(NSString, NSString)], longitudeFirst: Bool) -> [CLLocationCoordinate2D] { var coordinates = [CLLocationCoordinate2D]() @@ -184,18 +187,25 @@ class Parser { Removes any text before lat long points as well as two outer sets of parens. Example: + ``` input => "POLYGON(( 15 32 ))" output => "15 32" input => "MULTIPOLYGON((( 15 32 )))" output => "( 15 32 )" + ``` + + - parameter input: NSString to strip extraneous characters from - :param: input NSString to strip extraneous characters from - - :returns: stripped string instance + - returns: stripped string instance */ internal func stripExtraneousCharacters(input: NSString) -> NSString { - let regex = NSRegularExpression(pattern: "\\w+\\s*\\((.*)\\)", options: .CaseInsensitive, error: nil) + let regex: NSRegularExpression? + do { + regex = try NSRegularExpression(pattern: "\\w+\\s*\\((.*)\\)", options: .CaseInsensitive) + } catch _ { + regex = nil + } let match: AnyObject? = regex?.matchesInString(input as String, options: .ReportCompletion, range: NSMakeRange(0, input.length)).first let range = match?.rangeAtIndex(1) @@ -206,17 +216,17 @@ class Parser { } /** - :abstract: Attempt to determine if a given string is in `Well-Known Text` format (GeoString as its referred to internally) + _abstract_: Attempt to determine if a given string is in `Well-Known Text` format (GeoString as its referred to internally) - :discussion: This strips any leading & trailing white space before checking for the existance of word characters at the start of the string. + _discussion_: This strips any leading & trailing white space before checking for the existance of word characters at the start of the string. - :param: input String to attempt determine if is in `Well-Known Text` format + - parameter input: String to attempt determine if is in `Well-Known Text` format - :returns: `true` if it thinks it is, `false` otherwise + - returns: `true` if it thinks it is, `false` otherwise */ internal func isProbablyGeoString(input: String) -> Bool { let stripped = input.stringByStrippingLeadingAndTrailingWhiteSpace() - if let geoString = stripped.rangeOfString("^\\w+", options: .RegularExpressionSearch) { + if stripped.rangeOfString("^\\w+", options: .RegularExpressionSearch) != nil { return true } return false @@ -225,12 +235,12 @@ class Parser { /** Determine if a given string is a `MULTI*` item. - :param: input String to check + - parameter input: String to check - :returns: `true` if the string starts with `MULTI`. `false` otherwise + - returns: `true` if the string starts with `MULTI`. `false` otherwise */ internal func isMultiItem(input: String) -> Bool { - if let isPolygon = input.rangeOfString("MULTI", options: .RegularExpressionSearch) { + if input.rangeOfString("MULTI", options: .RegularExpressionSearch) != nil { return true } return false @@ -239,11 +249,11 @@ class Parser { /** Determines if a the collection is space delimited or not - :note: This function should only be passed a single entry or else it will probably have incorrect results + - note: This function should only be passed a single entry or else it will probably have incorrect results - :param: input a single entry from the collection as a string + - parameter input: a single entry from the collection as a string - :returns: `true` if elements are space delimited, `false` otherwise + - returns: `true` if elements are space delimited, `false` otherwise */ private func isSpaceDelimited(input: String) -> Bool { let array = input.componentsSeparatedByString(" ") diff --git a/MapPointMapper/ViewController.swift b/MapPointMapper/ViewController.swift index 8be0576..c73eccc 100644 --- a/MapPointMapper/ViewController.swift +++ b/MapPointMapper/ViewController.swift @@ -91,19 +91,20 @@ class ViewController: NSViewController, MKMapViewDelegate, NSTextFieldDelegate { } @IBAction func centerAllLinesPressed(sender: NSButton) { - let polylines = mapview.overlays as! [MKOverlay] + let polylines = mapview.overlays as [MKOverlay] let boundingMapRect = boundingMapRectForPolylines(polylines) mapview.setVisibleMapRect(boundingMapRect, edgePadding: NSEdgeInsets(top: 10, left: 10, bottom: 10, right: 10), animated: true) } // MARK: MKMapDelegate - func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! { + func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer { let renderer = MKPolylineRenderer(overlay: overlay) renderer.alpha = 1.0 renderer.lineWidth = 4.0 renderer.strokeColor = colorWell.color return renderer } + // MARK: NSTextFieldDelegate override func keyUp(theEvent: NSEvent) { if theEvent.keyCode == 36 { // 36 is the return key apparently @@ -116,9 +117,9 @@ class ViewController: NSViewController, MKMapViewDelegate, NSTextFieldDelegate { /** Create an `MKOverlay` for a given array of `CLLocationCoordinate2D` instances - :param: mapPoints array of `CLLocationCoordinate2D` instances to convert + - parameter mapPoints: array of `CLLocationCoordinate2D` instances to convert - :returns: an MKOverlay created from array of `CLLocationCoordinate2D` instances + - returns: an MKOverlay created from array of `CLLocationCoordinate2D` instances */ private func createPolylineForCoordinates(mapPoints: [CLLocationCoordinate2D]) -> MKOverlay { let coordinates = UnsafeMutablePointer.alloc(mapPoints.count) @@ -139,11 +140,11 @@ class ViewController: NSViewController, MKMapViewDelegate, NSTextFieldDelegate { /** Get the bounding `MKMapRect` that contains all given `MKOverlay` objects - :warning: If no `MKOverlay` objects are included the resulting `MKMapRect` will be nonsensical and will results in a warning. + - warning: If no `MKOverlay` objects are included the resulting `MKMapRect` will be nonsensical and will results in a warning. - :param: polylines array of `MKOverlay` objects. + - parameter polylines: array of `MKOverlay` objects. - :returns: an `MKMapRect` that contains all the given `MKOverlay` objects + - returns: an `MKMapRect` that contains all the given `MKOverlay` objects */ private func boundingMapRectForPolylines(polylines: [MKOverlay]) -> MKMapRect { var minX = Double.infinity @@ -171,25 +172,20 @@ class ViewController: NSViewController, MKMapViewDelegate, NSTextFieldDelegate { /** Read a given file at a url - :param: passedURL `NSURL` to attempt to read + - parameter passedURL: `NSURL` to attempt to read */ private func readFileAtURL(passedURL: NSURL?) { - if let url = passedURL { - if !NSFileManager.defaultManager().isReadableFileAtPath(url.absoluteString!) { - NSAlert(error: NSError(domain: "com.dmiedema.MapPointMapper", code: -42, userInfo: [NSLocalizedDescriptionKey: "File is unreadable at \(url.absoluteString)"])) - } - - var error: NSError? - let contents = NSString(contentsOfURL: url, encoding: NSUTF8StringEncoding, error: &error) - - if let err = error { - NSAlert(error: err) - return - } - - if let content = contents { - renderInput(content) - } + guard let url = passedURL else { return } + + if !NSFileManager.defaultManager().isReadableFileAtPath(url.absoluteString) { + NSAlert(error: NSError(domain: "com.dmiedema.MapPointMapper", code: -42, userInfo: [NSLocalizedDescriptionKey: "File is unreadable at \(url.absoluteString)"])).runModal() + } + + do { + let contents = try NSString(contentsOfURL: url, encoding: NSUTF8StringEncoding) as String + renderInput(contents) + } catch { + NSAlert(error: error as NSError).runModal() } } // end readFileAtURL @@ -205,7 +201,7 @@ class ViewController: NSViewController, MKMapViewDelegate, NSTextFieldDelegate { /** Parse the given input. - :param: input `NSString` to parse and draw on the map. If no string is given this is essentially a noop + - parameter input: `NSString` to parse and draw on the map. If no string is given this is essentially a noop */ private func parseInput(input: NSString) { diff --git a/MapPointMapperTests/Info.plist b/MapPointMapperTests/Info.plist index e86e2c5..ba72822 100644 --- a/MapPointMapperTests/Info.plist +++ b/MapPointMapperTests/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - dmiedema.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/MapPointMapperTests/Parser/ParserTests.swift b/MapPointMapperTests/Parser/ParserTests.swift index f78452f..e94c4f9 100644 --- a/MapPointMapperTests/Parser/ParserTests.swift +++ b/MapPointMapperTests/Parser/ParserTests.swift @@ -105,8 +105,8 @@ class ParserSpec: XCTestCase { let coordinatesArray = converted.map({self.parser.convertToCoordinates($0, longitudeFirst: true)}) if let coordinates = coordinatesArray.first { - XCTAssertEqualWithAccuracy(coordinates.first!.latitude, 10.0, 0.001, "latitude should be 10, was \(coordinates.first!.latitude)") - XCTAssertEqualWithAccuracy(coordinates.first!.longitude, 30.0, 0.001, "longitude should be 30, was \(coordinates.first!.longitude)") + XCTAssertEqualWithAccuracy(coordinates.first!.latitude, 10.0, accuracy: 0.001, "latitude should be 10, was \(coordinates.first!.latitude)") + XCTAssertEqualWithAccuracy(coordinates.first!.longitude, 30.0, accuracy: 0.001, "longitude should be 30, was \(coordinates.first!.longitude)") } else { XCTFail("Unable to take first from coordinatesArray") }