# jpleboeuf's solution

## to Bob in the Nim Track

Published at Sep 16 2020 · 0 comments
Instructions
Test suite
Solution

#### Note:

This exercise has changed since this solution was written.

Bob is a lackadaisical teenager. In conversation, his responses are very limited.

Bob answers 'Sure.' if you ask him a question, such as "How are you?".

He answers 'Whoa, chill out!' if you YELL AT HIM (in all capitals).

He answers 'Calm down, I know what I'm doing!' if you yell a question at him.

He says 'Fine. Be that way!' if you address him without actually saying anything.

He answers 'Whatever.' to anything else.

Bob's conversational partner is a purist when it comes to written communication and always follows normal rules regarding sentence punctuation in English.

## Running the tests

To compile and run the tests, just run the following in your exercise directory:

\$ nim c -r bob_test.nim

## Submitting Exercises

Note that, when trying to submit an exercise, make sure the solution is in the \$EXERCISM_WORKSPACE/nim/bob directory.

You can find your Exercism workspace by running exercism debug and looking for the line that starts with Exercises Directory.

## Source

Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial. http://pine.fm/LearnToProgram/?Chapter=06

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### bob_test.nim

import unittest
import bob

# version 1.6.0

suite "Bob":
test "stating something":
check hey("Tom-ay-to, tom-aaaah-to.") == "Whatever."

test "shouting":
check hey("WATCH OUT!") == "Whoa, chill out!"

test "shouting gibberish":
check hey("FCECDFCAAB") == "Whoa, chill out!"

check hey("Does this cryogenic chamber make me look fat?") == "Sure."

check hey("You are, what, like 15?") == "Sure."

check hey("fffbbcbeab?") == "Sure."

test "talking forcefully":
check hey("Hi there!") == "Whatever."

test "using acronyms in regular speech":
check hey("It's OK if you don't want to go work for NASA.") == "Whatever."

test "forceful question":
check hey("WHAT'S GOING ON?") == "Calm down, I know what I'm doing!"

test "shouting numbers":
check hey("1, 2, 3 GO!") == "Whoa, chill out!"

test "no letters":
check hey("1, 2, 3") == "Whatever."

test "question with no letters":
check hey("4?") == "Sure."

test "shouting with special characters":
check hey("ZOMG THE %^*@#\$(*^ ZOMBIES ARE COMING!!11!!1!") == "Whoa, chill out!"

test "shouting with no exclamation mark":
check hey("I HATE THE DENTIST") == "Whoa, chill out!"

test "statement containing question mark":
check hey("Ending with ? means a question.") == "Whatever."

test "non-letters with question":
check hey(":) ?") == "Sure."

test "prattling on":
check hey("Wait! Hang on. Are you going to be OK?") == "Sure."

test "silence":
check hey("") == "Fine. Be that way!"

test "prolonged silence":
check hey("          ") == "Fine. Be that way!"

test "alternate silence":
check hey("\t\t\t\t\t\t\t\t\t\t") == "Fine. Be that way!"

test "multiple line question":
check hey("\nDoes this cryogenic chamber make me look fat?\nNo.") == "Whatever."

test "starting with whitespace":
check hey("         hmmmmmmm...") == "Whatever."

test "ending with whitespace":
check hey("Okay if like my  spacebar  quite a bit?   ") == "Sure."

test "other whitespace":
check hey("\n\r \t") == "Fine. Be that way!"

test "non-question ending with whitespace":
check hey("This is a statement ending with whitespace      ") == "Whatever."
# Enable experimental ``case`` statement macros:
import macros
{.experimental: "caseStmtMacros".}
#
import strutils
import tables

type
MsgKind = enum
mkY  # Yelling
mkN  # Nothing
MsgKinds = set[MsgKind]

proc msgKinds(msg: string): MsgKinds =
var msgKinds: MsgKinds
if msg.isEmptyOrWhitespace():
incl(msgKinds, mkN)
else:
if msg.strip().endsWith('?'):
incl(msgKinds, mkA)
if Letters in msg and msg == msg.toUpperAscii():
incl(msgKinds, mkY)
msgKinds

macro match(n: set): untyped =
# Macro allowing ``case`` statements to deal with ``set``s.
# It does so by rewriting these ``case`` statements to ``if`` statements.
# It only matches ``case`` statement's selectors of type ``set``.
#
# Produce a new ``if`` statement node:
result = newTree(nnkIfStmt)
# Name the ``case`` statement's selector:
let nSelector = n[0]
# Iterate over the ``case`` statement's branches:
for i in 1..<n.len:
# Name the current ``case`` statement's branch:
let nBranch = n[i]
# Switch depending on the kind of the ``case`` statement's part:
case nBranch.kind:
# ``if`` statement/expression branch:
of nnkElifBranch, nnkElse, nnkElifExpr, nnkElseExpr:
# Just copy these kinds of branch:
# ``of`` branch:
of nnkOfBranch:
# Iterate over the comma-separated list of ``set``s:
for j in 0..nBranch.len-2:
# Replace the ``of`` branch by an ``elif`` branch
#  testing for equality between
#  the ``set`` in the selector
#  and the current ``set``
#  (leveraging the existing equality operator for ``set``s):
let cond = newCall("==", nSelector, nBranch[j])
else:
error "'match' cannot handle this node", nBranch
echo repr result

proc hey*(message: string): string =
"yelling": "Whoa, chill out!",
"yelling_question": "Calm down, I know what I'm doing!",
"saying_nothing": "Fine. Be that way!",
"default": "Whatever.",
}.toTable
case msgKinds(message):
of {mkA}:
of {mkY}:
of {mkA} + {mkY}:
of {mkN}:
else: