change(ios/engine): usage of #3220's new typings, beter docs

This commit is contained in:
jahorton 2020-06-10 10:30:19 +07:00
parent 3bf2d8f688
commit 315b2de2a0
7 changed files with 79 additions and 74 deletions

View file

@ -11,7 +11,7 @@ import Foundation
public class KeyboardKeymanPackage : TypedKeymanPackage<InstallableKeyboard> {
internal var keyboards: [KMPKeyboard]!
override init(metadata: KMPMetadata, folder: URL) {
override internal init(metadata: KMPMetadata, folder: URL) {
super.init(metadata: metadata, folder: folder)
self.keyboards = []

View file

@ -18,12 +18,15 @@ public enum KMPError : String, Error {
case resourceNotInPackage = "Resource cannot be found in specified package"
}
/**
* Common base class for the different KeymanPackage types.
*/
public class KeymanPackage {
static private let kmpFile = "kmp.json"
public let sourceFolder: URL
internal let metadata: KMPMetadata
init(metadata: KMPMetadata, folder: URL) {
internal init(metadata: KMPMetadata, folder: URL) {
sourceFolder = folder
self.metadata = metadata
}
@ -32,6 +35,21 @@ public class KeymanPackage {
return metadata.packageType == .Keyboard
}
/**
* Returns the type of LanguageResource contained within the parsed Package.
*/
public func resourceType() -> LanguageResourceType {
switch metadata.packageType {
case .Keyboard:
return .keyboard
case .LexicalModel:
return .lexicalModel
default:
// See KeymanPackage.parse below; an error is thrown there for case .Unsupported.
fatalError("KeymanPackage.parse failed to block construction of unsupported KeymanPackage instance")
}
}
// to be overridden by subclasses
public func defaultInfoHtml() -> String {
return "base class!"
@ -68,7 +86,13 @@ public class KeymanPackage {
public var installableResourceSets: [[AnyLanguageResource]] {
fatalError("abstract base method went unimplemented by derived class")
}
/**
* Parses a decompressed KMP's metadata file, producing the typed KeymanPackage instance corresponding to it.
*
* Typecast the return value to either KeyboardKeymanPackage or LexicalModelKeymanPackage for richly-typed
* information about the package's contents.
*/
static public func parse(_ folder: URL) -> KeymanPackage? {
do {
var path = folder
@ -117,22 +141,6 @@ public class KeymanPackage {
}
})
}
public func findMatch(_ resource: AnyLanguageResource) -> AnyLanguageResource? {
let matchesFound: [AnyLanguageResource] = self.installableResourceSets.compactMap { set in
let setMatches: [AnyLanguageResource] = set.compactMap { other in
if resource.id == other.id && resource.languageID == other.languageID {
return other
} else {
return nil
}
}
return setMatches.count > 0 ? setMatches[0] : nil
}
return matchesFound.count > 0 ? matchesFound[0] : nil
}
}
public class TypedKeymanPackage<TypedLanguageResource: LanguageResource>: KeymanPackage {
@ -150,4 +158,20 @@ public class TypedKeymanPackage<TypedLanguageResource: LanguageResource>: Keyman
public override var installableResourceSets: [[AnyLanguageResource]] {
return installables
}
public func findResource(withID fullID: TypedLanguageResource.FullID) -> TypedLanguageResource? {
let matchesFound: [TypedLanguageResource] = self.installables.compactMap { set in
let setMatches: [TypedLanguageResource] = set.compactMap { other in
if fullID.id == other.id && fullID.languageID == other.languageID {
return other
} else {
return nil
}
}
return setMatches.count > 0 ? setMatches[0] : nil
}
return matchesFound.count > 0 ? matchesFound[0] : nil
}
}

View file

@ -11,7 +11,7 @@ import Foundation
public class LexicalModelKeymanPackage : TypedKeymanPackage<InstallableLexicalModel> {
internal var models : [KMPLexicalModel]!
override init(metadata: KMPMetadata, folder: URL) {
override internal init(metadata: KMPMetadata, folder: URL) {
super.init(metadata: metadata, folder: folder)
self.models = []

View file

@ -619,7 +619,7 @@ public class Manager: NSObject, UIGestureRecognizerDelegate {
for resourceSet in kmp.installables {
for resource in resourceSet {
try ResourceFileManager.shared.install(resource, from: kmp)
try ResourceFileManager.shared.install(resourceWithID: resource.fullID, from: kmp)
// Install the keyboard for only the first language pairing defined in the package.
break
}
@ -634,7 +634,7 @@ public class Manager: NSObject, UIGestureRecognizerDelegate {
try kmp.installables.forEach { resourceSet in
try resourceSet.forEach { resource in
try ResourceFileManager.shared.install(resource, from: kmp)
try ResourceFileManager.shared.install(resourceWithID: resource.fullID, from: kmp)
}
}
}

View file

@ -179,23 +179,15 @@ public class ResourceFileManager {
}
}
public func install(_ resourceToMatch: AnyLanguageResource, from package: KeymanPackage, usePackageDefinition: Bool = true) throws {
public func install<ResourceType: LanguageResource,
PackageType: TypedKeymanPackage<ResourceType>> (
resourceWithID fullID: ResourceType.FullID,
from package: PackageType) throws {
var res: AnyLanguageResource
guard let r = package.findMatch(resourceToMatch) else {
guard let resource = package.findResource(withID: fullID) else {
throw KMPError.resourceNotInPackage
}
if(usePackageDefinition) {
res = r
} else {
// In case a KeymanEngine user wants a different definition than is in the source KMP.
res = resourceToMatch
}
// Now to lock down the reference, using 'let' to make it read-only.
let resource = res
// (source, destination)
var installableFiles: [(String, URL)] = [(resource.sourceFilename, Storage.active.resourceURL(for: resource)!)]
let installableFonts: [(String, URL)] = resource.fonts.map { font in

View file

@ -75,10 +75,13 @@ class FileManagementTests: XCTestCase {
ResourceFileManager.shared.prepareKMPInstall(from: TestUtils.Keyboards.khmerAngkorKMP) { kmp, error in
XCTAssertNotNil(kmp, "Failed to prepare KMP for installation")
XCTAssertNil(error, "Error occurred while preparing KMP for installation")
XCTAssertNotNil(kmp as? KeyboardKeymanPackage, "KMP resource type improperly recognized - expected a keyboard package!")
guard let kmp = kmp as? KeyboardKeymanPackage else {
XCTFail("KMP resource type improperly recognized - expected a keyboard package!")
return
}
do {
try ResourceFileManager.shared.install(TestUtils.Keyboards.khmer_angkor, from: kmp!)
try ResourceFileManager.shared.install(resourceWithID: TestUtils.Keyboards.khmer_angkor.fullID, from: kmp)
} catch {
XCTFail("Unexpected error during KeyboardPackage install")
}
@ -100,45 +103,17 @@ class FileManagementTests: XCTestCase {
}
}
func testInstallKeyboardFromPackageCustomDefinition() throws {
// Modified installation - KeymanEngine user supplies external/literal definition for LanguageResource.
// Separate test method b/c "tearDown()" cleans out installation artifacts from the other version.
ResourceFileManager.shared.prepareKMPInstall(from: TestUtils.Keyboards.khmerAngkorKMP) { kmp, error in
XCTAssertNotNil(kmp, "Failed to prepare KMP for installation")
XCTAssertNil(error, "Error occurred while preparing KMP for installation")
XCTAssertNotNil(kmp as? KeyboardKeymanPackage, "KMP resource type improperly recognized - expected a keyboard package!")
do {
try ResourceFileManager.shared.install(TestUtils.Keyboards.khmer_angkor, from: kmp!, usePackageDefinition: false)
} catch {
XCTFail("Unexpected error during KeyboardPackage install")
}
let installURL = Storage.active.keyboardURL(forID: "khmer_angkor", version: "1.0.6")
XCTAssertTrue(FileManager.default.fileExists(atPath: installURL.path),
"Could not find installed keyboard file")
let keyboards = Storage.active.userDefaults.userKeyboards!
XCTAssertEqual(keyboards.count, 1, "Unexpected number of keyboards were installed")
XCTAssertEqual(keyboards[0].id, "khmer_angkor", "Installed keyboard ID mismatch")
// While the KMP's version of the specified InstallableKeyboard does specify Fonts,
// the literal-based testing version does NOT. Since in this test, we're installing from the predefined, test-copy instance, we expect NOT to see the font from this test's install!
let fontURL = Storage.active.fontURL(forKeyboardID: "khmer_angkor", filename: "Mondulkiri-R.ttf")
XCTAssertFalse(FileManager.default.fileExists(atPath: fontURL.path))
}
}
func testInstallLexicalModelFromPackage() {
ResourceFileManager.shared.prepareKMPInstall(from: TestUtils.LexicalModels.mtntKMP) { kmp, error in
XCTAssertNotNil(kmp, "Failed to prepare KMP for installation")
XCTAssertNil(error, "Error occurred while preparing KMP for installation")
XCTAssertNotNil(kmp as? LexicalModelKeymanPackage, "KMP resource type improperly recognized - expected a lexical model package!")
guard let kmp = kmp as? LexicalModelKeymanPackage else {
XCTFail("KMP resource type improperly recognized - expected a lexical model package!")
return
}
do {
try ResourceFileManager.shared.install(TestUtils.LexicalModels.mtnt, from: kmp!)
try ResourceFileManager.shared.install(resourceWithID: TestUtils.LexicalModels.mtnt.fullID, from: kmp)
} catch {
XCTFail("Unexpected error during LexicalModelPackage install")
}

View file

@ -77,13 +77,27 @@ class KeymanPackageTests: XCTestCase {
func testPackageFindResourceMatch() {
ResourceFileManager.shared.prepareKMPInstall(from: TestUtils.Keyboards.khmerAngkorKMP) { kmp, _ in
XCTAssertNotNil(kmp!.findMatch(TestUtils.Keyboards.khmer_angkor))
XCTAssertNil(kmp!.findMatch(TestUtils.LexicalModels.mtnt))
guard let kmp = kmp as? KeyboardKeymanPackage else {
XCTFail("Incorrect package type loaded for test")
return
}
XCTAssertNotNil(kmp.findResource(withID: TestUtils.Keyboards.khmer_angkor.fullID))
// This keyboard's not in the specified testing package.
XCTAssertNil(kmp.findResource(withID: TestUtils.Keyboards.khmer10.fullID))
// Thanks to our package typing hierarchy, it's impossible to even TRY finding
// a FullLexicalModelID within a KeyboardKeymanPackage!
}
ResourceFileManager.shared.prepareKMPInstall(from: TestUtils.LexicalModels.mtntKMP) { kmp, _ in
XCTAssertNotNil(kmp!.findMatch(TestUtils.LexicalModels.mtnt))
XCTAssertNil(kmp!.findMatch(TestUtils.Keyboards.khmer_angkor))
guard let kmp = kmp as? LexicalModelKeymanPackage else {
XCTFail("Incorrect package type loaded for test")
return
}
XCTAssertNotNil(kmp.findResource(withID: TestUtils.LexicalModels.mtnt.fullID))
// Thanks to our package typing hierarchy, it's impossible to even TRY finding
// a FullKeyboardID within a LexicalModelKeymanPackage!
}
}
}