Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
trait CEnum {
/** The concrete subtype of EnumElements
*/
type ET <: EnumElement
/**
* Override this trait in your subclass with the
* base type of the EnumElements, then set ET = to that value
* the Template type in Ordered might need to be ET
* to ensure proper type safety, however I was getting
* circular type errors i think so I just left it like
* this because it works, and i don't think there are too
* many error people comparing Apples to MakesOfCars
*/
trait EnumElement extends Ordered[EnumElement] {
//Gets set automatically
private[CEnum] var ord: Int = 0
final def ordinal: Int = ord
//Forces the entire enumeration to
//be initialized, ensuring that elements
//in added in the correct order
CEnum.this.getClass
//Makes enum elements comparable by their
//ordinal so that they can be used in SortedMaps
override def compare(that: EnumElement) =
if (this.ordinal < that.ordinal) -1
else if (this.ordinal == that.ordinal) 0
else 1
}
//Temporary holder used to build up the ordinal numbers
final private var lb = new scala.collection.mutable.ListBuffer[ET]
//Call this method after each element, otherwise
//things won't work
final protected def add(element: ET) {
element.ord = lb.size
lb += element
added(element)
}
/**
* Override this method to add your enum elements to the map
* Rarely needs to be used.
*/
protected[this] def added(enumElement: ET) {}
/**
* Gets the values of the enumeration as an array
*/
final lazy val toArray: Array[ET] = lb.toArray
/**Gets all the values in the enumeration as a list
*/
final lazy val toList: List[ET] = lb.toList
/**Gets all the values in the enumeration as a set
*/
final lazy val toSet: Set[ET] = Set() ++ toList
/**Gets all the values in the enumeration as a map
* of (name->value)
*/
final lazy val toMap: Map[String, ET] = Map() ++ toList.map(e => (e.toString, e))
}
import org.scalatest.Suite
class TestCEnum extends Suite {
//An enumeration of Fruits
//each element is obviously a fruit
case object Fruits extends CEnum {
//What is the trait of elements in this enum?
//ah yes it's fruits.
sealed trait Fruit extends EnumElement
//set the type of enumelements equal to Fruit
override type ET = Fruit
//IMPORTANT!! Use case objects for the enum elements
//so that toString
//is autogenerated to a sensible value in this case "Apple"
case object Apple extends Fruit
//you must call add for each element, otherwise
//it won't make it into the maps and the ordinal will be messed up
//the order of the calls to add determines the ordinals!
//ordinals start at 0
add(Apple)
case object Pear extends Fruit
add(Pear)
}
object MakesOfCars extends CEnum {
override type ET = MakeOfCar
trait MakeOfCar extends EnumElement
case object Honda extends MakeOfCar; add(Honda)
case object Toyota extends MakeOfCar; add(Toyota)
case object BMW extends MakeOfCar; add(BMW)
case object Lexus extends MakeOfCar; add(Lexus)
case object Ford extends MakeOfCar; add(Ford)
case object Chevy extends MakeOfCar; add(Chevy)
}
def testVariousEnumerationBehaviours {
expect(1)(Fruits.Pear.ordinal)
expect(0)(Fruits.Apple.ordinal)
expect(Fruits.Pear)(Fruits.toMap("Pear"))
expect(Fruits.Apple)(Fruits.toMap("Apple"))
expect(Fruits.Apple)(Fruits.toList(0))
expect(Fruits.Pear)(Fruits.toList(1))
}
def testClassExtendsProperly {
expect(Fruits.Pear.getClass)(Fruits.toMap("Pear").getClass)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment