Use a delegate to make OsisParser cleaner

robolectric-error
Bradlee Speice 2014-11-11 10:09:47 -05:00
parent c57babd68a
commit c394fce273
6 changed files with 85 additions and 15 deletions

View File

@ -0,0 +1,39 @@
package org.bspeice.minimalbible.test;
import org.bspeice.minimalbible.FinalDelegate;
import org.bspeice.minimalbible.MBTestCase;
import kotlin.PropertyMetadataImpl;
/**
* Test that the FinalDelegate actually obeys its contract
*/
public class FinalDelegateTest extends MBTestCase {
FinalDelegate<String> delegate;
public void setUp() {
delegate = new FinalDelegate<String>();
}
public void testDelegateNullSafety() {
try {
delegate.get(null, new PropertyMetadataImpl(""));
} catch (IllegalStateException e) {
return;
}
fail("Exception not thrown!");
}
public void testDelegateAssignOnce() {
try {
delegate.set(null, new PropertyMetadataImpl(""), "");
delegate.set(null, new PropertyMetadataImpl(""), "");
} catch (IllegalStateException e) {
return;
}
fail("Allowed to set twice!");
}
}

View File

@ -17,7 +17,7 @@ public class OsisParserTest extends MBTestCase {
OsisParser parser;
public void setUp() {
parser = new OsisParser(null);
parser = new OsisParser();
}
@SuppressLint("NewApi")

View File

@ -80,7 +80,8 @@ public class VerseLookupService implements Action1<Verse> {
BookData bookData = new BookData(book, v);
try {
SAXEventProvider provider = bookData.getSAXEventProvider();
OsisParser handler = new OsisParser(v);
OsisParser handler = new OsisParser();
handler.setVerse(v);
provider.provideSAXEvents(handler);
return handler.getVerseContent().toJson();
} catch (BookException e) {

View File

@ -0,0 +1,24 @@
package org.bspeice.minimalbible
/**
* The purpose of this delegate is to guarantee null-safety, while
* also ensuring a pseudo-val type. If you try to read before use, error.
* If you try to set multiple times, error.
*/
public class FinalDelegate<T : Any>() {
private var value: T? = null
private var didAssign: Boolean = false
public fun get(thisRef: Any?, desc: PropertyMetadata): T {
return value ?: throw IllegalStateException("Property ${desc.name} should be initialized before get")
}
public fun set(thisRef: Any?, desc: PropertyMetadata, value: T) {
if (!didAssign) {
this.value = value
this.didAssign = true
} else
throw IllegalStateException("Property ${desc.name} should not be assigned multiple times")
}
}

View File

@ -5,17 +5,20 @@ import org.crosswire.jsword.passage.Verse
import java.util.ArrayDeque
import org.xml.sax.Attributes
import org.crosswire.jsword.book.OSISUtil
import org.bspeice.minimalbible.FinalDelegate
/**
* Created by bspeice on 9/10/14.
*/
class OsisParser(v: Verse?) : DefaultHandler() {
class OsisParser() : DefaultHandler() {
// Don't pass a verse as part of the constructor, but still guarantee
// that it will exist
public var verse: Verse by FinalDelegate()
val verseContent: VerseContent
get() = VerseContent(verse)
val verseContent: VerseContent? = when (v) {
is Verse -> VerseContent(v) // not null
else -> null
}
// TODO: Implement a stack to keep min API 8
val doWrite = ArrayDeque<Boolean>()
@ -33,6 +36,6 @@ class OsisParser(v: Verse?) : DefaultHandler() {
override fun characters(ch: CharArray, start: Int, length: Int) {
if (doWrite.peek())
verseContent?.appendContent(String(ch))
verseContent.appendContent(String(ch))
}
}

View File

@ -9,14 +9,17 @@ import java.util.ArrayList
//TODO: JSON Streaming parsing? http://instagram-engineering.tumblr.com/post/97147584853/json-parsing
class VerseContent(v: Verse) {
var id = v.getOrdinal()
var bookName = v.getName()
var chapter = v.getChapter()
var verseNum = v.getVerse()
val id = v.getOrdinal()
val bookName = v.getName()
val chapter = v.getChapter()
val verseNum = v.getVerse()
val chapterTitle = ""
val paraTitle = ""
val references: MutableList<VerseReference> = ArrayList()
var content = ""
var chapterTitle = ""
var paraTitle = ""
var references: MutableList<VerseReference> = ArrayList()
public val json: String
get() = Gson().toJson(this)
public fun toJson(): String {
// Lazy load Gson - not likely that we'll call this method multiple times, so