Tom
Tom

Reputation: 1105

Ruby boolean methods

I have a method I wish to use, to be make my code a little more legible (in my opinion)

My code:

def format_chosen_address(address)
  # Add country before the postcode
  postcode = address.split("\n").last
  country = postcode.is_welsh? ? 'WALES' : 'ENGLAND'
  address.split("\n").insert(-2, country).join(' ')
end


def is_welsh?
    welsh_postcodes = ['SA1 6AZ', 'SA7 9BR', 'CF10 1AX']
    welsh_postcodes.include? self
end

I get the following exception:

NoMethodError: undefined method `is_welsh?' for "SA1 6AZ":String

Where have I gone wrong because thought self and boolean methods could be used this way?

I can get it to work if I do the following, but it doesn't read as nice to me.

def format_chosen_address(address)
  # Add country before the postcode
  postcode = address.split("\n").last
  country = is_welsh?(postcode) ? 'WALES' : 'ENGLAND'
  address.split("\n").insert(-2, country).join(' ')
end

def is_welsh?(postcode
  welsh_postcodes = ['SA1 6AZ', 'SA7 9BR', 'CF10 1AX']
  welsh_postcodes.include? postcode
end

Upvotes: 0

Views: 67

Answers (3)

3limin4t0r
3limin4t0r

Reputation: 21160

You could also use a module to add certain helpers to the singleton class of the string. Meaning that they are only added for that specific instance of String and not for all strings.

module PostcodeHelpers
  def is_welsh?
    welsh_postcodes = ['SA1 6AZ', 'SA7 9BR', 'CF10 1AX']
    welsh_postcodes.include?(self)
  end

  def country
    is_welsh? ? 'WALES' : 'ENGLAND'
  end
end

def format_chosen_address(address)
  *lines, postcode = address_lines(address)
  [*lines, postcode.country, postcode].join(' ')
end

private # assuming you are in class or module context

def address_lines(address)
  *lines, postcode = address.split("\n")

  # Default to empty string since you don't want to extend nil by accident.
  postcode ||= ''
  postcode.extend(PostcodeHelpers)

  [*lines, postcode]
end

Like you can see this might be overkill for this scenario and produces quite a bit of additional code.

Upvotes: 0

Viktor
Viktor

Reputation: 2783

You can define the is_welsh? inside the String class like this:

class String
  def is_welsh?
    welsh_postcodes = ['SA1 6AZ', 'SA7 9BR', 'CF10 1AX']
    welsh_postcodes.include? self
  end
end

But it doesn't really make sense for every String to have a method that tells if it's Welsh or not. So the better option is to make it a method that takes a parameter (like your second example in the question):

def is_welsh?(postcode)
  welsh_postcodes = ['SA1 6AZ', 'SA7 9BR', 'CF10 1AX']
  welsh_postcodes.include? postcode
end

Upvotes: 1

spickermann
spickermann

Reputation: 107142

The problem is that you are calling postcode.is_welsh? which means you are calling the method is_welsh? on the string, but you didn't define the method on String but within another class.

Actually, I advise adding methods like to the String class. It is too specific to pollute the whole String namespace. Instead, I suggest just leaving that method as a (probably as a private) helper method and passing the postal code string to it as an argument:

def is_welsh?(postcode)
  welsh_postcodes = ['SA1 6AZ', 'SA7 9BR', 'CF10 1AX']
  welsh_postcodes.include? postcode
end

and call it like:

country = is_welsh?(postcode) ? 'WALES' : 'ENGLAND'

Upvotes: 2

Related Questions