Skip to content

Instantly share code, notes, and snippets.

@ilyannn
Last active August 29, 2015 14:06
Show Gist options
  • Save ilyannn/2ede211dfa9b4351ec64 to your computer and use it in GitHub Desktop.
Save ilyannn/2ede211dfa9b4351ec64 to your computer and use it in GitHub Desktop.
Timer with Alice, Bob, Carol, Daniel and Eva.
// -------------------------
// 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