Home > Back-end >  Returning a Hash as an 'else branch' dependant on Regex match
Returning a Hash as an 'else branch' dependant on Regex match

Time:03-03

The below is a challenge assignment so may not reflect 'real-world' code. I am trying to setup my method in a way that uses the properties of one hash to return a new hash. In this case, my method is taking an email as a string, uses regex to extrapolate the tld of the email and then outputs a hash-based message based of the tld. In this example, it generates an email in the language of the tld it registers.

The code works as it should but is failing one test: "should return a Hash with the message informations in english for any other ccTlD mail"

I cannot work out how to just set up a default value of 'en' when the tld is not in the original translation hash i.e. [email protected] should just return the English-based translation.

BONUS: I also note that my Rubocop doesn't like my styling because my compose_translated_email method has too many lines. I couldn't work out how to put the translation in another method without making that method too long too.

Any help would be greatly appreciated - rather than just the answer, I would love if you could explain what the code is doing too. Thank you.

LOCALES = {
  en: {
    subject: "Our website is online",
    body: "Come and visit us!",
    closing: "See you soon",
    signature: "The Team"
  },
  fr: {
    subject: "Notre site est en ligne",
    body: "Venez nous rendre visite !",
    closing: "A bientot",
    signature: "L'équipe"
  },
  de: {
    subject: "Unsere Website ist jetzt online",
    body: "Komm und besuche uns!",
    closing: "Bis bald",
    signature: "Das Team"
  }
}

def compose_translated_email(email)
  username = email.match(/^(\w*)/)[1]
  domain = email.match(/[^@] (?=\.)/)[0]
  tld = email.match(/.*\.(\w )$/)[1]

  tldsym = tld.to_sym

  new_hash = {
    username: username,
    domain: domain,
    tld: tld,
    subject: LOCALES[tldsym][:subject],
    body: LOCALES[tldsym][:body],
    closing: LOCALES[tldsym][:closing],
    signature: LOCALES[tldsym][:signature]
  }
  return new_hash
end

CodePudding user response:

Wouldn't it be enough to default the value of tld to en before creating the hash? As in:

(...)
# default to english language
tldsym = tld.to_sym
# i.e. if the key does not exist in LOCALES, use "en" as key
tldsym = LOCALES.key?(tldsym) ? tldsym : "en".to_sym
(...)

Considering your bonus question, you might fill the translated values via loop to save a few lines:

(...)
new_hash = {
  username: username,
  domain: domain,
  tld: tld,
}
%i(subject body closing signature).each { |k| new_hash[k] = LOCALES[tldsym][k] }
(...)

Explanation: We're iterating over an array of key names (subject, body, closing, signature) that will be filled in from the LOCALES hash. That %i notation (requires Ruby 2.0.0 or newer) gives us an array with symbols to these keys right away, so no to_sym is needed inside the each block - we can just use the current symbols (named k in this case) in both the source and the target hash.


Save additional lines by filling the other hash slots iteratively, too:

(...)
new_hash = {}
%W(username domain tld).each { |k| new_hash[k.to_sym] = eval(k) }
%i(subject body closing signature).each { |k| new_hash[k] = LOCALES[tldsym][k] }
(...)

Explanation: Here we're using %W to get an array of strings, so we need to_sym for the key in the target. The target value is then resolved using evaluation, which is probably not considered the cleanest style, I guess.

Please forgive any stupid mistakes, I'm a Ruby beginner myself :)

CodePudding user response:

I would do something like this:

LOCALES = Hash.new({
  subject: "Our website is online",
  body: "Come and visit us!",
  closing: "See you soon",
  signature: "The Team"
}).merge({
  'fr' => {
    subject: "Notre site est en ligne",
    body: "Venez nous rendre visite !",
    closing: "A bientot",
    signature: "L'équipe"
  },
  'de' => {
    subject: "Unsere Website ist jetzt online",
    body: "Komm und besuche uns!",
    closing: "Bis bald",
    signature: "Das Team"
  }
}).freeze

def compose_translated_email(email)
  email.scan(/([^@] )@(.*\.([^.] ))/) => [[username, domain, tld]]

  {
    username:,
    domain:,
    tld:,
    **LOCALES[tld]
  }
end

It's not the most beautiful code in the world, but it'll do.

  • Related