1

In CoffeeScript, let's say I've got the following:

class Greeter
    message: ->
        greeting = switch @gender
            when 'male' then 'Sir'
            when 'female' then 'Madame'
            else 'Unknown'

        "Hello #{greeting}!"

greeter = new Greeter
greeter.gender = 'Male'
alert greeter.message()

This currently alerts Hello Unknown! when I want it to output Hello Sir!.

How do I make it so that the Greeter class will lowercase the @gender instance variable so that the correct output is achieved? I don't want to just lowercase it in the message method, but rather, all throughout an Instance of the Class. This is so that it works in other methods too.

I think I'm missing something very basic but I just can't seem to wrap my head around it.

NOTE: To those saying I got the capitalization wrong for "Male". Yes, I purposely did that. I'd like the class to automatically lowercase gender in all cases, before using it. So the user can get the capitalization wrong and it still works.

The reason is that I'd eventually like to extrapolate this to other situations, rather than just those dealing with case-insensitivity issues.

Some people have mentioned JavaScript Getters and Setters, which are relatively new and therefore not supported in all major browsers. I'll take a look at those. I'm somewhat familiar with them through Ruby.

Gary
  • 3,891
  • 8
  • 38
  • 60
  • What does it write when you change `#{greeting}` too `#{gender}` – Andrew Jul 30 '14 at 19:47
  • Then it says it is not defined. Otherwise if I used `#{@gender}` then it says "Hello Male!" as expected. – Gary Jul 30 '14 at 19:49
  • @Gary I'm going to change the title here; you really care about the case sensitivity, not the value of the `@gender` – jcollum Jul 30 '14 at 20:08
  • Well this is not specific to case-sensitivity; I'm more generally looking for a way to change variables passed to an Instance. Although I guess yes, in this specific case I gave the example as a case-sensitivity issue because that is the easiest way to show an example. – Gary Jul 30 '14 at 20:09
  • Ah, yes I see what you mean. OK I can come up with a better answer and title then. – jcollum Jul 30 '14 at 20:11
  • Yes, I now know I should probably have worded my question better because there seems to be lots of confusion regarding it. The example of case-sensitivity was, in hindsight, a poor example, because providing a solution seems really trivial at first. But this has led me to JS Getters and Setters, which seem promising. – Gary Jul 30 '14 at 20:15

2 Answers2

2

Male is not male. Try normalize your string as lower case:

message: ->
    greeting = switch @gender.toLowerCase()
        when 'male' then 'Sir'
        when 'female' then 'Madame'
        else 'Unknown'

If necessary, you might want to encapsulate the call to lowercase in some property getter: https://stackoverflow.com/a/11592890/2363712 Something like that:

class Greeter
    constructor: ->
        Object.defineProperty  @, 'gender',
            get: ->
                return @_gender
            set: (value) ->
                @_gender = value.toLowerCase()

    message: ->
        greeting = switch @gender
            when 'male' then 'Sir'
            when 'female' then 'Madame'
            else 'Unknown'

        "Hello #{greeting}!"

For this to work, your run-time environment must support Object.defineProperty
See that table for a quick lookup of supported browsers.

Community
  • 1
  • 1
Sylvain Leroux
  • 50,096
  • 7
  • 103
  • 125
  • No this is not what I want, though. I want `@gender` to be lowercased for ALL of the class's methods, not just one. – Gary Jul 30 '14 at 19:51
  • Thanks I will take a look at JavaScript getters and setters to see if they are fully supported yet. – Gary Jul 30 '14 at 20:14
  • @Gary See my edit for a working version (tested on node.js) If you want to go that way, you will be restricted to browser supporting `Object.defineProperty` (part of EMCAScript 5, if I'm not too wrong). – Sylvain Leroux Jul 30 '14 at 20:18
0
coffee> 
  class Greeter
    message: =>
        greeting =
          if /^male/i.test(@gender) then 'Sir'
          else if /^female/i.test(@gender) then 'Madame'
          else 'Unknown'

        "Hello #{greeting}!"

greeter = new Greeter
greeter.gender = 'Male'
greeter.message()

'Hello Sir!'
coffee> greeter.gender  = 'female' 
'female'
coffee> greeter.message()
'Hello Madame!'
coffee> greeter.gender  = 'smizmar' 
'smizmar'
coffee> greeter.message()
'Hello Unknown!'
coffee> 

So that's the simple way to do it, but it doesn't change the value stored. To do that, you'll need to use Object.defineProperty (SO answer about it):

Function::property = (prop, desc) ->
  Object.defineProperty @prototype, prop, desc

class Greeter
  constructor: () ->
  @property 'gender',
    get: -> "#{@ciGender}"
    set: (v) -> @ciGender = v.toLowerCase()
  message: ->
    greeting = switch @ciGender
        when 'male' then 'Sir'
        when 'female' then 'Madame'
        else 'Unknown'

    "Hello #{greeting}!"
Community
  • 1
  • 1
jcollum
  • 43,623
  • 55
  • 191
  • 321