Hello, is Elixir there?

So, another day, another … well, sorry, I just can’t find something funnier to start with! Anyway, this time it’s the “hey, let’s format some phone numbers, but let’s do it for US only” kind of problem.

And today, the highlights are:

Tuples & pattern matching

Let’s say that you have a function that knows how to split a phone number into meaningful parts (hmm, I wonder where did I get that idea?!). So you might end up with code area of that phone number, prefix and finally line number.

The question is, how do you pass that information around? Well, aside from structs, you can just use tuples. Just wrap values in curly braces and that’s it:

defp split(phone) do
  {code(phone), prefix(phone), line(phone)}
end

This effectively means that the output might be something like {“123”, “456”, “7890”}. The good thing about that, as opposed to using for example a list, is that you can easily access each member, by index, or just use pattern matching to extract values, like this:

def pretty(phone) do
  {code, prefix, line} = split(phone)
  "(#{code}) #{prefix}-#{line}"
end

That way, it’s pretty easy to pass multiple results around.

Guard clauses

Until now, I didn’t really have a use for those. But, this time, the sort of complex number format and validation rules complicate things, and guard clauses help with the reasoning.

def number(raw) do
  case raw |> String.replace(~r/\W/, "") |> to_char_list do
    phone when length(phone) == 11 and hd(phone) == ?1 ->
      tl(phone)
    phone when length(phone) != 10 ->
      '0000000000'
    phone ->
      phone
  end |> to_string
end

This way, the rules become easy to follow. And situations like “if phone length is 11 and starts with ‘1’, then it’s a valid number but remove the ‘1’ before moving on” become easy to write and follow quite nicely the natural language.

Doctest

Doctest is a great thing all modern languages support. The idea is to write examples as part of a function documentation, and have test execute those very examples. So, the phrase “the tests are the code’s documentation” comes to life in a splendid manner 🙂

This specific exercism.io problem had some of those already in the supplied exercise code, and I wanted to use those tests as well. If we were to use `mix`, then it would be easy, since the tool would set up everything for us. But, since exercism.io problems are meant to offer as little distraction as possible, you can’t use it out of the box.

Fortunately, there is a work around. You just need to:

  • add `doctest Phone` to the test file / module, as shown here
  • build source file, because otherwise doctest will not find the documentation
  • run tests as usual

So, for the last 2 steps, just create a shell script that does that for you. For example:

elixirc phone_number.exs && elixir phone_number_test.exs

Elixirc compiles the code, creating a beam file, tests load it and use it to run the tests / examples from documentation. And oh, forgot to show an example of such a test:

  @doc """
  Remove formatting from a phone number.

  ## Examples
  iex> Phone.number("123-456-7890")
  "1234567890"
  """
  def number(raw) do
  end

And, when executed, it reports like this:

$ ./test.sh
PhoneTest
  * doc at Phone.number/1 (4) (0.7ms)

Finished in 0.1 seconds (0.1s on load, 0.01s on tests)
1 tests, 0 failures

Randomized with seed 543612

That’s it folks!

Here’s a Github issue that related to all of this.

You can find the entire phone number solution here.

P.S. All pun intended 🙂

Advertisements
Tagged , , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: