uchcode
12/10/2015 - 3:49 PM

Protocol-Oriented Programming in Swift

Protocol-Oriented Programming in Swift

import Foundation

// ErrorType

public enum OSAScriptError: ErrorType {
    case InitializingFromSource(source: String?)
    case InitializingFromContents(error: NSDictionary)
    case Executing(error: NSDictionary)
    case Unknown
}

// Protocol

public protocol OSAScriptProperty {
    var script : NSAppleScript { get set }
}
public protocol OSAScriptInitialize: OSAScriptProperty {
    init()
    init(contentsOfPath: String) throws
}
public protocol OSAScriptFunction: OSAScriptProperty {
    func run() throws -> NSAppleEventDescriptor
}
public protocol OSAScriptProtocol: OSAScriptInitialize, OSAScriptFunction {}

// Protocol Extension

extension OSAScriptInitialize {
    init(contentsOfPath path: String) throws {
        self.init()
        let url = NSURL(fileURLWithPath: path)
        var err : NSDictionary?
        guard let script = NSAppleScript(contentsOfURL: url, error: &err) else {
            if let err = err {
                throw OSAScriptError.InitializingFromContents(error: err)
            } else {
                throw OSAScriptError.Unknown
            }
        }
        self.script = script
    }
}
extension OSAScriptFunction {
    func run() throws -> NSAppleEventDescriptor {
        var err : NSDictionary?
        let result = self.script.executeAndReturnError(&err)
        if let err = err {
            throw OSAScriptError.Executing(error: err)
        }
        return result
    }
}

// ValueType

struct JavaScript: OSAScriptProtocol {
    var script = NSAppleScript()
}

struct AppleScript: OSAScriptProtocol {
    var script = NSAppleScript()
}

extension AppleScript {
    init(source: String) throws {
        guard let script = NSAppleScript(source: source) else {
            throw OSAScriptError.InitializingFromSource(source: source)
        }
        self.script = script
    }
}

// Main

_ = try? JavaScript(contentsOfPath: "/path/to/script/javascript.scptd").run()
_ = try? AppleScript(source: "say \"hello again\"").run()