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
You can’t perform that action at this time.