debajit

debajit

Doctests for private functions

I have the following module where as I developed the code I was using doctests to verify if the function did what I expected. The problem is these doctests that I was writing are for functions that eventually became private functions:

  • Removing the doctests for the private functions does not help here as I need the tests — they help with catching regressions and help document the functionality of the code. Without these tests, it may not be clear to someone reading the code what exactly the private function does.

  • I could move the code inside the public function but that results in a big monolithic function and the separate functions help clarify the logic.

What is the recommended way to reconcile this in Elixir? (I seem to run into this problem very often — requiring doctests for private functions, that is)

The only solution I know is to create a separate Impl module and move the private functions as public functions like @pragdave describes here: Redirect . Is this an anti-pattern (given that I would be effectively “exposing” the private functions in a way)? I love this approach, but I was wondering if there was another way to have doctests for private functions — I would presume this would be a common problem?

What is the guidance here? Also, is there a way to remove these warnings for @docs on private functions?

defmodule InverseCaptcha do
  @moduledoc """
  Solves the Inverse Captcha problem.
  http://adventofcode.com/2017/day/1

  Run with:

      mix
      ./inverse_captcha 1122
  """

  def solve_captcha(string) do
    string
    |> string_to_list
    |> sum_of_digits_matching_next
  end

  @doc """
      iex> string_to_list("1122")
      [1, 1, 2, 2]
  """
  defp string_to_list(string) do
    string
    |> String.splitter("", trim: true)
    |> Stream.map(& String.to_integer(&1))
    |> Enum.to_list
  end

  @doc """
  ## Examples

      iex> sum_of_digits_matching_next([1, 1, 2, 2])
      3

      iex> sum_of_digits_matching_next([1, 1, 1, 1])
      4

      iex> sum_of_digits_matching_next([1, 2, 3, 4])
      0

      iex> sum_of_digits_matching_next([9, 1, 2, 1, 2, 1, 2, 9])
      9
  """
  defp sum_of_digits_matching_next(list) do
    list_with_head = (list ++ [hd(list)])

    list_with_head
    |> Enum.zip(tl(list_with_head))
    |> Enum.reduce(0, fn {x, y}, acc ->
         if x == y do
           x + acc
         else
           acc
         end
       end)
  end
end

defmodule InverseCaptcha.CLI do
  def main(args) do
    string = hd(args)
    IO.puts InverseCaptcha.solve_captcha(string)
  end
end

Most Liked

jwarlander

jwarlander

Sometimes I’ve seen a tendency in my own code for private functions to grow a bit too complex; I usually take that as a hint that maybe they should be public functions in some kind of utility module or similar.

My idea of a “good” private function is mostly along the lines of a one-liner to shorten, and give a proper name to, a part of a larger transformation / pipe sequence.

If it gets more complex, like mapping a set of values to something else, etc, then I definitely feel it should be a public function, either in the current module or another one that fits better.

imobachgs

imobachgs

I consider private functions just as “implementation details”, so I focus on testing only the module’s public APIs. On the other hand, if your public functions are working as expected, I think you can happily assume that your private functions are working aswell.

About documenting private methods, I understand the reasons to not doing so. But to be honest, I find this documentation useful for other developers contributing to the project.

LostKobrakai

LostKobrakai

Private functions have different semantics than public ones, what Jose explained here quite well: https://forum.elixirforum.com/t/proposal-docp-for-private-function-documentation-and-doctests/3732/2?u=lostkobrakai

Where Next?

Popular in Questions Top

_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
marick
I had some trouble figuring out how to make many-to-many associations work. Once I got it working, I wrote a blog post. Because I’m a nov...
New

Other popular topics Top

Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 47930 226
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement