0

My application uses a properties-file to load several properties.

Every instance of the application has 3 environment-related parameters - one of them is a property, the other two are computed based on it.

class Environment(val properties: Properties) {
    val dbUrl = valueOrError("db.url")
    val host = valueOrError("host")
    //... 

    val environmentFlag = valueOrError("env.flag") 
    val environmentToken = environmentFlag match {
        case "live" => "L"
        case "staging" => "S"
        case "test" => "T"
    val environmentUrlPrefix = environmentFlag match {
        case "live" => ""
        case "staging" => "staging-"
        case "test" => "test"
    }       

}

It seems to me that the 3 environment* properties should be somehow encapsulated.

I called the sought abstraction Discriminator, since it's used to distinguish between the 3 (for now) environment types. Since in one running application, there is only one set of such environment* properties, I implemented it as an object:

class Environment(val properties: Properties) { 
    val dbUrl ... 

    object Discriminator {
        val flag = valueOrError("env.flag")
        val token = flag match {
            case "live" => "L"
            case "staging" => "S"
            case "test" => "T"
        val urlPrefix = flag match {
            case "live" => ""
            case "staging"=> "staging-"
            case "test" => "test-"
        }
     }
}

I can call: environment.Discriminator.urlPrefix, which is fine, but how can I improve the code? How do I get rid of the duplicated match?
Now it feels like the values of token and urlPrefix of live should live together (as should the ones for staging and so on) - kinda like as part of one instance of a Discriminator class.

abstract class Discriminator(val flag = valueOrError("env.flag"), 
                             val token: String
                             val urlPrefix: String)

Since I still want to use environment.Discriminator.urlPrefix, I still need the Discriminator (now) companion object.

But I'm stuck here - I don't know how to combine the concepts.

I clearly have to create myself 3 instances of Discriminator - based on the concrete flag field, but how? How do I call the constructor - passing it the last two parameters based on the first one (which is common to all instances)?

And once I have this, how do I connect the three instances with the Discriminator companion object, so that I can use environment.Discriminator.urlPrefix?

kiritsuku
  • 52,967
  • 18
  • 114
  • 136
teo
  • 1,393
  • 1
  • 15
  • 25

2 Answers2

2

You can initialize both token and urlPrefix at the same time like this:

val (token, urlPrefix) = flag match {
  case "live" => ("L", "")
  case "staging" => ("S", "staging-")
  case "test" => ("T", "test-")
}
Régis Jean-Gilles
  • 32,541
  • 5
  • 83
  • 97
  • Yes! I was struggling to create case objects from pairs (like this: Discriminator(flag match {.. => ("L", "').. }), when I in fact I didn't need any explicit objects at all. Thanks! – teo Apr 04 '13 at 09:09
1

Why not replace this:

   val token = flag match {
        case "live" => "L"
        ....
    val urlPrefix = flag match {
        case "live" => ""
        .....

with something returning a tuple ? e.g.

   val tokens = flag match {
        case "live" => ("L", "")
Brian Agnew
  • 268,207
  • 37
  • 334
  • 440