Last active
August 29, 2015 14:06
-
-
Save ilyannn/2ede211dfa9b4351ec64 to your computer and use it in GitHub Desktop.
Timer with Alice, Bob, Carol, Daniel and Eva.
This file contains hidden or 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
// ------------------------- | |
// General-purpose functions. Created by Alice. | |
import Foundation | |
func <(lhs:NSDate, rhs:NSDate) -> Bool { | |
// This should be in the standard library. - Alice. | |
return lhs.compare(rhs) == .OrderedAscending | |
} | |
enum Result { | |
case Success(Timer) | |
case Errors([NSError]) // must be non-empty | |
} | |
protocol ErrorCollector { | |
func append(@autoclosure () -> NSError) | |
} | |
class ErrorDevNull: ErrorCollector { | |
func append(_: @autoclosure () -> NSError) {} | |
} | |
class ErrorArray: ErrorCollector { | |
var errors:[NSError] = [] | |
func append(factory: @autoclosure () -> NSError) { | |
errors.append(factory()) | |
} | |
} | |
struct InitState { | |
let errorCollector:ErrorCollector | |
var isFailed = false | |
init(collector:ErrorCollector?) { | |
errorCollector = collector ?? ErrorDevNull() | |
} | |
} | |
// ------------------------- | |
// Timer. Developed by Bob. | |
private func <<(inout state:InitState, reason:String) { | |
state.errorCollector.append(Timer.initError(reason)) | |
state.isFailed = true | |
} | |
class Timer { | |
// Seriously, most of this class is error handling. - Bob. | |
let startDate: NSDate | |
let endDate: NSDate | |
// Create timer error instance. | |
final class func initError(reason:String) -> NSError { | |
return NSError(domain: "timer.domain", code: 1, userInfo: [ | |
NSLocalizedDescriptionKey: "cannot create timer" , | |
NSLocalizedFailureReasonErrorKey: reason, | |
NSLocalizedRecoverySuggestionErrorKey: "try with different inputs" , | |
]) | |
} | |
// Collects errors in case of error (and returns nil in that case). | |
init?(_ start: NSDate, _ end: NSDate, errors collector: ErrorCollector? = nil) { | |
var state = InitState(collector: collector) | |
if end < start { | |
state << "endDate < startDate" | |
} | |
startDate = start | |
endDate = end | |
if state.isFailed { return nil } | |
} | |
// Or you can work with the Result. | |
class func withDates(start: NSDate, _ end: NSDate) -> Result { | |
let errors = ErrorArray() | |
if let timer = Timer(start, end, errors: errors) { | |
return .Success(timer) | |
} else { | |
return .Errors(errors.errors) | |
} | |
} | |
} | |
// Does your class supports different init styles? - Alice. | |
// Totally. See here. - Bob. | |
let timerOrNil = Timer(NSDate(), NSDate()) // This can fail ;) | |
let result = Timer.withDates(NSDate(), NSDate()) | |
// ------------------------- | |
// Extended by Carol. | |
private let Formatter = NSDateFormatter() | |
Formatter.timeZone = NSTimeZone(name: "UTC") | |
Formatter.dateFormat = "yyyyMMddHHmmss" | |
private func &&<T>(value:T, block: () -> ()) -> T { | |
block() | |
return value | |
} | |
extension Timer { | |
// Look, I told you from the start, we need to process a STRING file! - Carol. | |
convenience init?(_ start: String, _ end: String, errors collector: ErrorCollector? = nil) { | |
var state = InitState(collector: collector) | |
let start_date = Formatter.dateFromString(start) ?? NSDate() && { | |
state << "cannot parse start date = '\(start)'" | |
} | |
let end_date = Formatter.dateFromString(end) ?? NSDate() && { | |
state << "cannot parse end date = '\(end)'" | |
} | |
self.init(start_date, end_date, errors: collector) | |
if state.isFailed { return nil } | |
} | |
} | |
// ------------------------- | |
// Subclassed by Daniel. | |
class FutureTimer: Timer { | |
// Surprisingly large numbers of people were trying to create timers in the past. - Daniel | |
override init?(_ start: NSDate, _ end: NSDate, errors collector: ErrorCollector? = nil) { | |
var state = InitState(collector: collector) | |
if start < NSDate() { | |
state << "start date in the past!" | |
} | |
if end < NSDate() { | |
state << "end date in the past!" | |
} | |
super.init(start, end, errors: collector) | |
if state.isFailed { return nil } | |
} | |
} | |
// ------------------------- | |
// Used by Eva. | |
if let recording = FutureTimer("20141009000000", "20141009010000") { | |
println("Recording successfully scheduled. - Eva.") | |
} else { | |
println("Failed to schedule recording. - Eva.") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment