Created
January 20, 2010 23:58
-
-
Save benjaminjackman/282446 to your computer and use it in GitHub Desktop.
This file contains 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
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)) | |
} | |
This file contains 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
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