Skip to content

Commit

Permalink
Add ScalaJS Support
Browse files Browse the repository at this point in the history
This is a combination of 8 commits.
Updated to ScalaTest 3.0 but Scala.Js part still seems borked

Add back Eval based spec for JVM only

Dry out test settings to use ScalaJS cross version

Adjust Travis testing

Add coreJVM tests into Travis test runner

Try inlining the test to resolve output dir not found on travis

Add Upickle project

Various test fixes

This is a combination of 10 commits.
Add back non-parallel tests

Uninline travis tasks

Fix build

Remove publish settings from core jvm tests project

Fix toolbox class path

Try to fix Eval utility

Update readme with ScalaJS sections

Better readme version control

Remove old code

Meh
  • Loading branch information
lloydmeta committed Dec 12, 2015
1 parent 14fe07f commit 5d7853e
Show file tree
Hide file tree
Showing 11 changed files with 307 additions and 69 deletions.
23 changes: 20 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@ language: scala
jdk:
- oraclejdk8
scala:
- 2.11.6
script: "sbt clean coverage +test"
after_success: "sbt coveralls"
- 2.11.7
script:
- sbt clean +test:compile
- sbt +test
# Manually select the JVM projects to run coverage on until Scoverage is compatible with ScalaJS
- sbt coverage coreJVM/test enumeratum-play/test enumeratum-play-json/test
after_success:
- sbt coverageReport coverageAggregate coveralls
cache:
directories:
- $HOME/.sbt/0.13
- $HOME/.sbt/boot/scala*
- $HOME/.sbt/cache
- $HOME/.sbt/launchers
- $HOME/.ivy2
before_cache:
- du -h -d 1 $HOME/.ivy2/
- du -h -d 2 $HOME/.sbt/
- find $HOME/.sbt -name "*.lock" -type f -delete
- find $HOME/.ivy2/cache -name "ivydata-*.properties" -type f -delete
40 changes: 35 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,56 @@ Compatible with Scala 2.10.x and 2.11.x

## SBT

Set the Enumeratum version in a variable (for the latest version, use `val enumeratumVersion = "1.3.3"`).

For basic enumeratum (with no Play support):
```scala
libraryDependencies ++= Seq(
"com.beachape" %% "enumeratum" % "1.3.3"
"com.beachape" %% "enumeratum" % enumeratumVersion
)
```

For enumeratum with [uPickle](http://lihaoyi.github.io/upickle/):

```scala
libraryDependencies ++= Seq(
"com.beachape" %% "enumeratum" % enumeratumVersion,
"com.beachape" %% "enumeratum-upickle" % enumeratumVersion
)
```

For enumeratum with Play JSON:
```scala
libraryDependencies ++= Seq(
"com.beachape" %% "enumeratum" % "1.3.3",
"com.beachape" %% "enumeratum-play-json" % "1.3.3"
"com.beachape" %% "enumeratum" % enumeratumVersion,
"com.beachape" %% "enumeratum-play-json" % enumeratumVersion
)
```

For enumeratum with full Play support:
```scala
libraryDependencies ++= Seq(
"com.beachape" %% "enumeratum" % "1.3.3",
"com.beachape" %% "enumeratum-play" % "1.3.3"
"com.beachape" %% "enumeratum" % enumeratumVersion,
"com.beachape" %% "enumeratum-play" % enumeratumVersion
)
```

### ScalaJs

There is support for ScalaJs, though only for the core lib and the UPickle helper lib.

```scala
libraryDependencies ++= Seq(
"com.beachape" %%% "enumeratum" % enumeratumVersion
)
```

To use with uPickle:

```scala
libraryDependencies ++= Seq(
"com.beachape" %%% "enumeratum" % enumeratumVersion,
"com.beachape" %%% "enumeratum-upickle" % enumeratumVersion
)
```

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package enumeratum

import org.scalatest.{ FunSpec, Matchers }

class EnumJVMSpec extends FunSpec with Matchers {

describe("findValues Vector") {

// This is a fairly intense test.
it("should be in the same order that the objects were declared in") {
import scala.util._
(1 to 100).foreach { i =>
val members = Random.shuffle((1 to Random.nextInt(20)).map { m => s"Member$m" })
val membersDefs = members.map { m => s"case object $m extends Enum$i" }.mkString("\n\n")
val objDefinition =
s"""
import enumeratum._
sealed trait Enum$i extends EnumEntry

case object Enum$i extends Enum[Enum$i] {
$membersDefs
val values = findValues
}

Enum$i
"""
val obj = Eval.apply[Enum[_ <: EnumEntry]](objDefinition)
obj.values.map(_.entryName) shouldBe members
}
}

}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package enumeratum

import scala.tools.reflect.ToolBox
import java.io.File

/**
* Eval with bits and pieces stolen from here and there...
Expand All @@ -20,7 +19,7 @@ object Eval {

def macroToolboxClassPath = {
val paths = Seq(
new java.io.File(s"macros/target/scala-${scalaBinaryVersion}/classes")
new java.io.File(s"macros/.jvm/target/scala-$scalaBinaryVersion/classes")
)
paths.foreach { p =>
if (!p.exists) sys.error(s"output directory ${p.getAbsolutePath} does not exist.")
Expand Down
29 changes: 1 addition & 28 deletions enumeratum-core/src/test/scala/enumeratum/EnumSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class EnumSpec extends FunSpec with Matchers {
describe("no values") {

it("should result in findValues finding nothing") {
EmptyEnum.values shouldBe 'empty
EmptyEnum.values.size shouldBe 0
}

}
Expand Down Expand Up @@ -208,33 +208,6 @@ class EnumSpec extends FunSpec with Matchers {

}

describe("findValues Vector") {

// This is a fairly intense test.
it("should be in the same order that the objects were declared in") {
import scala.util._
(1 to 100).foreach { i =>
val members = Random.shuffle((1 to Random.nextInt(20)).map { m => s"Member$m" })
val membersDefs = members.map { m => s"case object $m extends Enum$i" }.mkString("\n\n")
val objDefinition =
s"""
import enumeratum._
sealed trait Enum$i extends EnumEntry

case object Enum$i extends Enum[Enum$i] {
$membersDefs
val values = findValues
}

Enum$i
"""
val obj = Eval[Enum[_ <: EnumEntry]](objDefinition)
obj.values.map(_.entryName) shouldBe members
}
}

}

describe("trying to use with improper types") {

it("should fail to compile for unsealed traits") {
Expand Down
15 changes: 15 additions & 0 deletions enumeratum-upickle/src/main/scala/enumeratum/UPickleEnum.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package enumeratum

import upickle.default.Aliases.RW
import upickle.default.ReadWriter

/**
* Enum mix-in with default Reader and Writers defined (case sensitive)
*/
trait UPickleEnum[A <: EnumEntry] { self: Enum[A] =>

import UPickler._

implicit val uPickleReadWriter: RW[A] = ReadWriter(writer(this).write, reader(this, false).read)

}
46 changes: 46 additions & 0 deletions enumeratum-upickle/src/main/scala/enumeratum/UPickler.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package enumeratum

import upickle.Js
import upickle.default.{ Writer, Reader }

object UPickler {

/**
* Returns a UPickle [[Reader]] for a given [[Enum]]
*
* @param enum the enum you wish to make a Reader for
* @param insensitive whether or not to match case-insensitively
*/
def reader[A <: EnumEntry](enum: Enum[A], insensitive: Boolean = false): Reader[A] = {
Reader[A] {
val memberFinder: String => Option[A] = if (insensitive) enum.withNameInsensitiveOption else enum.withNameOption
val pfIfJsStr: PartialFunction[Js.Value, String] = {
case Js.Str(s) => s
}
val pfMaybeMember = pfIfJsStr.andThen(memberFinder)
val pfMaybeMemberToMember: PartialFunction[Option[A], A] = {
case Some(a) => a
}
andThenPartial(pfMaybeMember, pfMaybeMemberToMember)
}
}

/**
* Returns a [[Writer]] for a given [[Enum]]
*
* @param enum [[Enum]] to make a [[Writer]] for
*/
def writer[A <: EnumEntry](enum: Enum[A]): Writer[A] = Writer[A] {
case member => Js.Str(member.toString)
}

/**
* Private helper for composing PartialFunctions
*
* Stolen from http://stackoverflow.com/questions/23024626/compose-partial-functions
*/
private def andThenPartial[A, B, C](pf1: PartialFunction[A, B], pf2: PartialFunction[B, C]): PartialFunction[A, C] = {
Function.unlift(pf1.lift(_) flatMap pf2.lift)
}

}
14 changes: 14 additions & 0 deletions enumeratum-upickle/src/test/scala/enumeratum/Dummy.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package enumeratum

/**
* Created by Lloyd on 2/4/15.
*/
sealed trait Dummy extends EnumEntry
object Dummy extends Enum[Dummy] with UPickleEnum[Dummy] {
case object A extends Dummy
case object B extends Dummy
case object C extends Dummy
val values = findValues
}

object D extends Dummy
57 changes: 57 additions & 0 deletions enumeratum-upickle/src/test/scala/enumeratum/UPickleSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package enumeratum

import org.scalatest._
import upickle.Js

/**
* Created by Lloyd on 12/12/15.
*/
class UPickleSpec extends FunSpec with Matchers {

import Dummy._

describe("Reader") {

val reader = UPickler.reader(Dummy)

it("should work with valid values") {
reader.read(Js.Str("A")) shouldBe A
}

it("should fail with invalid values") {
intercept[Exception] {
reader.read(Js.Str("D"))
}
intercept[Exception] {
reader.read(Js.Num(2))
}
}

}

describe("insensitive reader") {
val reader = UPickler.reader(Dummy, true)

it("should work with strings, disgregarding case") {
reader.read(Js.Str("A")) shouldBe A
reader.read(Js.Str("a")) shouldBe A
}

it("should work with invalid values") {
intercept[Exception](reader.read(Js.Str("D")))
intercept[Exception](reader.read(Js.Num(5)))
}

}

describe("Writer") {

val writer = UPickler.writer(Dummy)

it("should write enum values to JsString") {
writer.write(A) shouldBe Js.Str("A")
}

}

}
Loading

0 comments on commit 5d7853e

Please sign in to comment.