Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
/*
Erica Sadun, http://ericasadun.com
Basic Errors
*/
import Foundation
/// A basic utility error type that stores the reason for
/// a failed operation and the context under which the error
/// has occurred
public struct CoreError: ErrorType {
let (reason, context) : (String, String)
public init(
_ reason: String,
_ context: String = __FILE__)
{
(self.reason, self.context) = (reason, context)
}
}
/// By adopting Contextualizable, constructs can build errors
/// specific to their calling conditions
public protocol Contextualizable {}
/// Adding default implementation for error building
public extension Contextualizable {
/// Creates a context error at the point of failure, picking
/// up the file, function, and line of the error event
public func BuildContextError(
items: Any...,
file: String = (__FILE__ as NSString).lastPathComponent,
function: String = __FUNCTION__,
line: Int = __LINE__
) -> CoreError
{
let reasons = items.map({"\($0)"}).joinWithSeparator(", ")
let context = "\(function):\(self.dynamicType):\(file):\(line) "
return CoreError(reasons, context)
}
}
/// A lighter weight alternative to Contextualizable that still
/// picks up file and line context for error handling
///
/// - param items: Caller can supply zero or more instances as "reasons", which
/// need not be strings. Their default representation will be added
/// to the 'reasons' list.
public func ContextError(
items: Any...,
file: String = (__FILE__ as NSString).lastPathComponent,
line: Int = __LINE__
) -> CoreError
{
let reasons = items.map({"\($0)"}).joinWithSeparator(", ")
let context = "\(file):\(line) "
return CoreError(reasons, context)
}
/// Replacement for `try?` that introduces printing for
/// error conditions instead of discarding those errors
///
/// - Parameter shouldCrash: defaults to false. When set to true
/// will raise a fatal error, emulating try! instead of try?
///
/// ```swift
/// attempt {
/// let mgr = NSFileManager.defaultManager()
/// try mgr.createDirectoryAtPath(
/// "/Users/notarealuser",
/// withIntermediateDirectories: true,
/// attributes: nil)
/// }
///
public func attempt<T>(
line line: Int = __LINE__,
shouldCrash: Bool = false,
closure: () throws -> T
) -> T?
{
do {
/// Return executes only if closure succeeds
return try closure()
} catch {
/// Emulate try! by crashing
if shouldCrash {
print("Fatal error on line \(line): \(error)")
abort()
}
/// Force print and return nil like try?
print("Error \(line): \(error)")
return nil
}
}
/// Alternative to attempt that ignores any results and returns
/// a Boolean value indicating success
public func testAttempt<T>(
line line: Int = __LINE__,
shouldCrash: Bool = false,
closure: () throws -> T
) -> Bool
{
/// Throw away result but check for non-nil. Thanks nuclearace
return attempt(
line: line,
shouldCrash: shouldCrash,
closure: closure) == nil ? false : true
}
@digimkr

This comment has been minimized.

Copy link

@digimkr digimkr commented Dec 11, 2015

<My goals are:

Greatest readability and clarity of intent
Easiest modification
Space for commenting where needed>

You have achieved your goals!

@ghost

This comment has been minimized.

Copy link

@ghost ghost commented Dec 12, 2015

On Linux we need 'import Glibc' for 'abort()'.

@BurntCaramel

This comment has been minimized.

Copy link

@BurntCaramel BurntCaramel commented Dec 14, 2015

Some off the top of my head:

Greatest readability and clarity of intent

Why are reason and context not named in the init?
Why let (reason, context) : (String, String) instead of over two lines?
Why is reason a String and not an enum case?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment