-
Notifications
You must be signed in to change notification settings - Fork 5
27: Add pagination support (Elixir) #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: elixir-repos-in-folder-22
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,9 @@ | ||
| defmodule GithubRepoCloner.CLI do | ||
| alias GithubRepoCloner.Cloner | ||
| alias GithubRepoCloner.PageIterator | ||
|
|
||
| def main(args \\ []) do | ||
| args | ||
| |> List.first | ||
| |> GithubRepoCloner.Cloner.clone | ||
| username = List.first(args) | ||
| PageIterator.repeat(&Cloner.clone_page/1, %{username: username, page: 1}) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the name should change to
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might wrap this in a new |
||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,19 +2,18 @@ defmodule GithubRepoCloner.Cloner do | |
| @http_client Application.compile_env(:github_repo_cloner, :http_client) | ||
| @system Application.compile_env(:github_repo_cloner, :system) | ||
|
|
||
| def clone(nil), do: true | ||
| def clone_page(%{username: nil}), do: {:error, "No repositories found"} | ||
| def clone_page(%{page: nil}), do: {:error, "No repositories found"} | ||
|
|
||
| def clone(username) do | ||
| def clone_page(%{username: username, page: page}) do | ||
| username | ||
| |> request_repo_info | ||
| |> request_repo_info(page) | ||
| |> parse_response | ||
| |> clone_repos(username) | ||
| end | ||
|
|
||
| def clone, do: true | ||
|
|
||
| defp request_repo_info(username) do | ||
| @http_client.get("https://api.github.com/users/#{username}/repos") | ||
| defp request_repo_info(username, page) do | ||
| @http_client.get("https://api.github.com/users/#{username}/repos?page=#{page}") | ||
| end | ||
|
|
||
| defp parse_response({:ok, %Tesla.Env{status: 200, body: body}}) do | ||
|
|
@@ -30,7 +29,11 @@ defmodule GithubRepoCloner.Cloner do | |
| |> run_command | ||
| end | ||
|
|
||
| defp run_command("") do | ||
| {:error, "No repositories found"} | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Return an |
||
| end | ||
|
|
||
| defp run_command(command) do | ||
| @system.cmd("sh", ["-c", command]) | ||
| {:ok, @system.cmd("sh", ["-c", command])} | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Return an |
||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| defmodule GithubRepoCloner.PageIterator do | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rules of the page iterator:
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. write these in as a comment in this code.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if you felt the need to add it here just add it as a comment in the code.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At the very least leave a comment describing the base condition that terminates the repeat iterator. |
||
| def repeat(function, arguments = %{page: page}) do | ||
| {status, _} = function.(%{arguments | page: page}) | ||
| repeat(function, arguments, status) | ||
| end | ||
|
|
||
| def repeat(function, arguments = %{page: page}, :ok) do | ||
| repeat(function, %{arguments | page: page + 1}) | ||
| end | ||
|
|
||
| def repeat(_function, %{page: page}, :error), do: {:ok, page} | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| defmodule GithubRepoCloner.PageIteratorTest do | ||
| use ExUnit.Case | ||
| alias GithubRepoCloner.PageIterator | ||
|
|
||
| test "repeat/3: Repeat function with next page until it returns an error" do | ||
| {:ok, page_reached} = PageIterator.repeat(&TestIteratable.runner/1, %{username: "murjax", page: 1}) | ||
| assert ^page_reached = 3 | ||
| end | ||
| end | ||
|
|
||
| defmodule TestIteratable do | ||
| def runner(%{username: username, page: 1}) do | ||
| {:ok, username} | ||
| end | ||
|
|
||
| def runner(%{username: username, page: 2}) do | ||
| {:ok, username} | ||
| end | ||
|
|
||
| def runner(%{username: _, page: 3}) do | ||
| {:error, "Finished"} | ||
| end | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had to rethink the cloner logic here. I could have simply tossed the existing logic in a loop that runs until we reach an empty page. That increases the cyclomatic complexity, or in other words the number of scenarios the function handles. I decided it was better to isolate the logic for cloning one page of repos (
Cloner) and extract the logic for handling pagination elsewhere (PageIterator).