15 Jul 2013, 03:42
Dave_gnome_head_isolated_pragsmall

Dave Thomas (337 posts)

  • (Tricky) Before reading the next section, see if you can write the code to format the data into columns, like the sample output at the start of the chapter. This is probably the longest piece of Elixir code you’ll have written. Try to do it without using if or cond.
29 Oct 2013, 16:48
Mac 128k logic board 96x96_pragsmall

Roger Turner (5 posts)


   defmodule Issues.Tabulate do

    def print_table_for_columns(list_of_dicts, columns) do

      cells = lc dict inlist list_of_dicts, do: 
        (lc {key, value} inlist Enum.to_list(dict), key in columns, do: 
            to_string(value) )

      headed = Enum.concat([columns], cells)

      lengths = lc row inlist headed, do: 
        Enum.map(row, &String.length/1)

      widths = lc col inlist List.zip(lengths), do: 
        Enum.max(Kernel.tuple_to_list(col))

      padded = lc row inlist headed, do:
        (lc {cell, width} inlist Enum.zip(row, widths), do: 
          String.ljust(cell, width))

      divider = Enum.map(widths, &(String.duplicate("-", &1)))

      IO.puts Enum.join(Enum.at(padded, 0), " | ")
      IO.puts Enum.join(divider, "-+-")
      lc row inlist Enum.drop(padded, 1), do: IO.puts Enum.join(row, " | ")

    end

   end

13 Jul 2014, 15:50
Generic-user-small

Paul Bickford (1 post)

The above code looks much more succinct than mine. (I would be interested to understand the “lc value inlist list, do:” format - what is lc?).

With the following, I tried to format the output for multi-line titles, splitting the lines between words. I also set the column width of the terminal in the config.exs file.

config.exs

[
  issues: [github_url: "https://api.github.com"],
  issues: [command_line_width: 80]
]

cli.ex

...

@command_line_width Application.get_env(:issues, :command_line_width)

...

def process({user, project, count}) do
  Issues.GithubIssues.fetch(user, project)
    |> decode_response
    |> convert_to_list_of_hashdicts
    |> sort_into_ascending_order
    |> Enum.take(count)
    |> display_table
end

...

def display_table(list) do
  line1 = "   #   | created_at" <> String.rjust("| title", 19)
  line2 = String.rjust("+", 8,?-) <> String.rjust("+", 24, ?-) <> String.duplicate("-", @command_line_width - 32)
  IO.write line1 <> "\n" <> line2 <> "\n"
  for entry <- list, do: IO.puts get_row_string(entry)
end
   
def get_row_string(entry) do
  row = " " <> String.ljust(Integer.to_string(entry["number"]), 6) <> "| " <> String.ljust(entry["created_at"], 22) <> "| " <> String.ljust(entry["title"], @command_line_width - 33)
  format_row(row, String.length(row))
end

def format_row(line, len) when len <= @command_line_width, do: line
def format_row(line, len) when len > @command_line_width do
  {l1, l2} = String.split_at(line, splitpoint(line, @command_line_width))
  l1 <> format_additional_row(l2, String.length(l2))
end
  
def format_additional_row(line, len) when len <= @command_line_width-33 do
  "\n" <> String.rjust("| ", 33) <> line
end
def format_additional_row(line, len) when len > @command_line_width-33 do
  pad = "\n" <> String.rjust("| ", 33)
  {l1, l2} = String.split_at(line,splitpoint(line,@command_line_width-33))
  pad <> l1 <> format_additional_row(l2, String.length(l2))
end
  
def splitpoint(string, initial_splitpoint) do
  case {String.at(string, initial_splitpoint), String.at(string, initial_splitpoint + 1)} do
    {" ", _} -> initial_splitpoint
    {_, " "} -> initial_splitpoint
    _        -> splitpoint(string, initial_splitpoint-1)
  end
end
  You must be logged in to comment