elixir-book/issues/lib/issues/cli.ex

120 lines
3.2 KiB
Elixir

defmodule Issues.CLI do
@default_count 4
@moduledoc """
Handle the command line parsing and the dispatch to the various functions that end up
generating a table of the last _n_ issues in a github project.
"""
def run(argv) do
argv
|> parse_args
|> process
end
@doc """
`argv` can be -h or --help, which returns :help.
Otherwise it is a github user name, project name, and (optionally)
the number of entries to format.
Return a tuple of `{ user, project, count }`, or `:help` if help was given
"""
def parse_args(argv) do
OptionParser.parse(argv,
switches: [help: :boolean],
aliases: [h: :help]
)
|> elem(1)
|> args_to_internal_representation
end
def args_to_internal_representation([user, project, count]) do
{user, project, String.to_integer(count)}
end
def args_to_internal_representation([user, project]) do
{user, project, @default_count}
end
# either bad arg or --help
def args_to_internal_representation(_) do
:help
end
def process(:help) do
IO.puts("""
usage: issues <user> <project> [count | #{@default_count}]
""")
System.halt(0)
end
def process({user, project, count}) do
Issues.GithubIssues.fetch(user, project)
|> decode_response()
|> sort_into_descending_order
|> last(count)
|> show_issues_as_table
end
def decode_response({:ok, body}), do: body
def decode_response({:error, error}) do
IO.puts("Error fetching from Github: #{error["message"]}")
System.halt(2)
end
def sort_into_descending_order(list_of_issues) do
list_of_issues
|> Enum.sort(fn lhs, rhs -> Map.get(lhs, "created_at") >= Map.get(rhs, "created_at") end)
end
def last(list, count) do
list
|> Enum.take(count)
|> Enum.reverse()
end
def show_issues_as_table(issues_list) do
# get the width of each colum for id, created at and title
longest_id =
issues_list
|> Enum.map(&Map.get(&1, "id"))
|> Enum.max_by(&(String.length("#{&1}") + 2))
id_column_width = String.length(Integer.to_string(longest_id))
longest_creation_date =
issues_list
|> Enum.map(&Map.get(&1, "created_at"))
|> Enum.max_by(&(String.length(&1) + 2))
creation_date_width = String.length(longest_creation_date)
longest_title =
issues_list
|> Enum.map(&Map.get(&1, "title"))
|> Enum.max_by(&(String.length(&1) + 2))
title_length = String.length(longest_title)
# print the title
IO.puts(
"#{String.pad_trailing("#id", id_column_width)} | #{String.pad_trailing("created_at", creation_date_width)} | #{String.pad_trailing("title", title_length)} "
)
# print seperator
IO.puts(
"#{String.pad_trailing("-", id_column_width, "-")}-+-#{String.pad_trailing("-", creation_date_width, "-")}-+-#{String.pad_trailing("-", title_length, "-")}-"
)
# print each issue
issues_list
|> Enum.each(fn issue ->
IO.puts(
"#{String.pad_trailing(Integer.to_string(Map.get(issue, "id")), id_column_width)} | #{String.pad_trailing(Map.get(issue, "created_at"), creation_date_width)} | #{String.pad_trailing(Map.get(issue, "title"), title_length)}"
)
end)
end
end