1

So I am creating a parser to parse some configuration files made by our client engineers. I don't particularly trust our client engineers. They can usually spell things right but they can never remember what to capitalize. This makes Enum classes kind of noisome in that they go and break the program cause the Enum fails if they don't type in the exact right string.

Here is my Enum Class:

object EnumLayoutAlignment extends Enumeration
{
     type Alignment = Value
     val Vertical = Value("Vertical")
     val Horizontal = Value("Horizontal")
}

Is there a way I could make it so that "Vertical", "vertical", and "VERTICAL" all mapped to the same enum value?

EDIT: @Radai brought up a good point of just .upper() on the input but I would also like to include "vert" and other similar inputs

I used this as an example

Community
  • 1
  • 1
ford prefect
  • 7,096
  • 11
  • 56
  • 83
  • why not simply uppercase everything? – radai Jul 29 '14 at 15:26
  • The problem is that our client engineers still won't remember that... With all due respect to them I want this to be user proof – ford prefect Jul 29 '14 at 15:27
  • i meant take their input (==any value your code reads from a conf file), and uppercase it. or do you mean they will be using the code directly and not some interface that you control? – radai Jul 29 '14 at 15:28
  • @radai not a bad idea but I would also like to add a couple of other possible mappings – ford prefect Jul 29 '14 at 15:29
  • Why use Enum instead of abstract data types in functional languages? – Naetmul Jul 29 '14 at 15:30
  • @Naetmul Looking here: http://www.scala-lang.org/old/node/105 I don't understand the benefit of that? – ford prefect Jul 29 '14 at 15:33
  • Are you looking for Scala-specific implementation or is it ok to be straight up Java? – gtgaxiola Jul 29 '14 at 15:35
  • @gtgaxiola There is a preference for Scala – ford prefect Jul 29 '14 at 15:36
  • Other than normalizing case before getting the enum value, the best option is probably to create an explicit map from `String -> EnumLayoutAlignment`. For instance, you may want to map "vert" to `Vertical`. – yshavit Jul 29 '14 at 15:36
  • @inquisitiveIdiot I meant case classes and case objects - abstract data types like http://www.haskell.org/haskellwiki/Abstract_data_type not abstract types. Maybe it is better to say algebraic data types. http://gleichmann.wordpress.com/2011/01/30/functional-scala-algebraic-datatypes-enumerated-types/ – Naetmul Jul 30 '14 at 01:59

2 Answers2

3

One way to handle this is to provide a method for deserialization:

def fromString(s: String) = s.upper() match {
  case "VERTICAL" | "VERT" | "V" => Some(Vertical)
  case "HORIZONTAL" | "HORIZ" | "H" => Some(Horizontal)
  case => None
}

Then using it is as simple as:

EnumLayoutAlignment.fromString(someInput).map(doThingWithValidEnum)
Sean Vieira
  • 155,703
  • 32
  • 311
  • 293
0

You can add a method like this to your Enumeration:

def tryAsHardAsPossibleToFindMatch(s: String) = {
  val ls = s.toLowerCase
  val fv = values.filter(_.toString.toLowerCase.startsWith(ls))
  fv.size match {
    case 1 => fv.head
    case 0 => sys.error("No matching value for " + s)
    case _ => sys.error("Ambiguous values for " + s)
  }
}

This will allow you to use any string, regardless of case, that is part of the beginning of a Value. So Vertical can be obtained with "VERT", "vErTi", "vERTICAL", "VerticaL", etc.

wingedsubmariner
  • 13,350
  • 1
  • 27
  • 52