Current section
Files
Jump to
Current section
Files
lib/github_trend_ex.ex
defmodule GithubTrendEx do
@moduledoc """
GithubTrendEx get trend data from github.
"""
alias Floki
alias HTTPoison
alias GithubTrendEx.Repo
@scheme "https://"
@github_domain "github.com"
@trending_path "/trending"
@doc """
Get github trending from github.com
"""
@spec trend(bitstring, bitstring) :: bitstring
def trend(lang \\ "", since \\ "daily") do
trending_url = trending_url(lang, since)
trending_url
|> HTTPoison.get!
|> Map.get(:body)
end
@doc """
Generate URL for trending
Example
iex> GithubTrendEx.trending_url
"https://github.com/trending?since=daily"
iex> GithubTrendEx.trending_url("elixir")
"https://github.com/trending/elixir?since=daily"
iex> GithubTrendEx.trending_url("elixir", "weekly")
"https://github.com/trending/elixir?since=weekly"
"""
@spec trending_url(bitstring, bitstring) :: bitstring
def trending_url(lang \\ "", since \\ "daily") do
case lang do
s when is_bitstring(s) and byte_size(s) > 0->
@scheme <> @github_domain <> @trending_path <> "/" <> s <> "?since=#{since}"
_ ->
@scheme <> @github_domain <> @trending_path <> "?since=#{since}"
end
end
@doc """
Return Map `%{name: "a name of the trend", url: "a url to github of the trend", description: "description of the trend"}`
"""
@spec list(bitstring) :: [%Repo{}]
def list(html) do
elements = Floki.find(html, "ol.repo-list > li")
Enum.map(elements, fn(el) ->
%Repo {
name: find_name(el),
description: find_desc(el),
url: generate_url(el),
language: find_language(el),
stars: find_stars(el),
forks: find_forks(el),
contributors: find_contributors(el)
}
end)
end
def find_name(el) do
[{"a", [{"href", "/" <> name}], _}] =
el
|> Floki.find("div > h3 > a")
name
end
def find_desc(el) do
case Floki.find(el, "div.py-1 > p") do
[{"p", _, nested}] ->
Enum.map_join(nested, " ", &(get_text_from(&1)))
[] ->
# there's no description
nil
end
end
def generate_url(el) do
@scheme <> @github_domain <> "/" <> find_name(el)
end
def find_language(el) do
case Floki.find(el, "div.f6 > span[itemprop=programmingLanguage]") do
[{"span", _, [content]}] ->
content |> String.trim()
[] ->
# there's no language
nil
end
end
def find_stars(el) do
el
|> Floki.find("div.f6 > a[aria-label=Stargazers]")
|> Floki.text()
|> String.trim()
|> String.replace(",", "")
|> String.to_integer()
end
def find_forks(el) do
el
|> Floki.find("div.f6 > a[aria-label=Forks]")
|> Floki.text()
|> String.trim()
|> String.replace(",", "")
|> String.to_integer()
end
def find_contributors(el) do
el
|> Floki.attribute("div.f6 > a.no-underline img", "title")
end
def get_text_from({"a", _arrtibutes, text}) do
text
|> List.first
|> String.strip
end
def get_text_from({"img", attributes, _text}) do
attributes
|> Enum.find(fn {tag, _value} ->
tag == "title"
end)
|> elem(1)
end
def get_text_from({"g-emoji", _attributes, [text]}) do
text
end
def get_text_from(text), do: text |> String.strip
end