Created
September 20, 2015 09:10
-
-
Save josdirksen/9051baf09003dac37386 to your computer and use it in GitHub Desktop.
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
object ReadSample extends App { | |
/** | |
* The readable trait defines how objects can be converted from a string | |
* representation to the objects instance. For most of the standard types | |
* we can simply use the toType function of String. | |
*/ | |
trait Readable[T] { | |
def read(x: String): T | |
} | |
/** | |
* Companion object containing helper functions and standard implementations | |
*/ | |
object Readable { | |
/** | |
* Helper function which allows creation of Readable instances | |
*/ | |
def toReadable[T](p: String => T): Readable[T] = new Readable[T] { | |
def read(x: String): T = p(x) | |
} | |
/** | |
* Allow for construction of standalone readables, if the ops aren't used | |
*/ | |
def apply[A](implicit instance: Readable[A]): Readable[A] = instance | |
// Using the toReadable creates cleaner code, we could also explicitly | |
// define the implicit instances: | |
// | |
// implicit object ReadableDouble extends Readable[Double] { | |
// def read(s: String): Double = s.toDouble | |
// } | |
// implicit object ReadableInt extends Readable[Int] { | |
// def read(s: String): Int = s.toInt | |
// } | |
implicit val ReadableDouble = toReadable[Double](_.toDouble) | |
implicit val ReadableInt = toReadable[Int](_.toInt) | |
implicit val ReadableLong = toReadable[Long](_.toLong) | |
implicit val ReadableString = toReadable[String](new String(_)) | |
implicit val ReadableBoolean = toReadable[Boolean](_.toBoolean) | |
implicit val ReadableCharList = toReadable[List[Char]](_.toCharArray.toList) | |
implicit val ReadableStringList = toReadable[List[String]](_.split(':').toList) | |
/** | |
* Extend the string object with a read function. | |
*/ | |
object ops { | |
implicit class pp[T](s: String) { | |
/** | |
* The type parameter should have an implcit Readable in scope. Use | |
* implicitly to access it and call the read function | |
*/ | |
def read[T: Readable]= implicitly[Readable[T]].read(s) | |
} | |
} | |
} | |
// to use it, import the standard classes and import the String operation. | |
import Readable._ | |
import Readable.ops._ | |
// now we can just get an instance of a readable and call the read function | |
// to parse a string to a specific type. | |
println(Readable[Double].read("10")) | |
println(Readable[Int].read("10")) | |
println(Readable[String].read("Well duh!")) | |
println(Readable[List[Char]].read("Well duh!")) | |
println(Readable[List[String]].read("Using:A:Separator:to:split:a:String")) | |
// we can also use the read function directly | |
println("20".read[Double]); | |
println("Using:A:Separator:to:split:a:String".read[List[Char]]); | |
println("Using:A:Separator:to:split:a:String".read[List[String]]); | |
// creating custom read function can be done without tying a case class | |
// to the reads implementation. In the following sample assume we | |
// serialize it to a string with | as separators: | |
// 10|Title Text|Title Content | |
case class Task(id: Long, title: String, content: String) | |
// simple convert the incoming string to a Task | |
implicit val readableTask = toReadable( | |
_.split('|') match { | |
case Array(id: String, title: String, content: String) => new Task(id.read[Long], title, content) | |
} | |
) | |
println(Readable[Task].read("10|Title Text|Title Content")) | |
println("20|Another title Text|Another title Content".read[Task]) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment