From 157bb933242626078eaa3f1ffaa5e711b1473779 Mon Sep 17 00:00:00 2001 From: Carlo Gilmar Date: Wed, 12 Jun 2019 00:02:20 -0500 Subject: [PATCH 1/6] Adding elixir solution Adding gitignore for the elixir solution Adding elixir empty project Adding dependencies for make http requests Adding first attemp Refactoring functions Refactoring functions Getting answer from console Removing eol from response Adding retry Adding refactor Adding refactor Adding documentation --- .gitignore | 8 +++ elixir_fizz/.formatter.exs | 4 ++ elixir_fizz/README.md | 102 +++++++++++++++++++++++++++++++++ elixir_fizz/config/config.exs | 1 + elixir_fizz/lib/elixir_fizz.ex | 77 +++++++++++++++++++++++++ elixir_fizz/mix.exs | 26 +++++++++ elixir_fizz/mix.lock | 12 ++++ 7 files changed, 230 insertions(+) create mode 100644 .gitignore create mode 100644 elixir_fizz/.formatter.exs create mode 100644 elixir_fizz/README.md create mode 100644 elixir_fizz/config/config.exs create mode 100644 elixir_fizz/lib/elixir_fizz.ex create mode 100644 elixir_fizz/mix.exs create mode 100644 elixir_fizz/mix.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2791d3d --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +elixir_fizz/_build/ +elixir_fizz/cover/ +elixir_fizz/deps/ +elixir_fizz/doc/ +elixir_fizz/.fetch +elixir_fizz/erl_crash.dump +elixir_fizz/*.ez +elixir_fizz/elixir_fizz-*.tar diff --git a/elixir_fizz/.formatter.exs b/elixir_fizz/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/elixir_fizz/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/elixir_fizz/README.md b/elixir_fizz/README.md new file mode 100644 index 0000000..4767dad --- /dev/null +++ b/elixir_fizz/README.md @@ -0,0 +1,102 @@ +# FizzBot Elixir Solution + +- Requirements for test this solution +- Download dependencies +- Run this solution +- How it works +- ElixirFizz module design + +## Requirements for test this solution + + 1. Install in your computer Elixir (I used 1.8.1 version) + +## Download dependencies + +For this project I created a mix project because I needed two dependencies for make http requests *httpoison 1.0* and parser the responses *poison 3.1*, that's the reason that I'm using a mix project. + +For download this dependencies you need an elixir installation in your computer, and in this directory *fizzbot/elixir_fizz* run: + +> mix deps.get + +## Run this solution + +Elixir have a useful REPL, we should use it for test this project. For run a REPL with this mix project you have to run: + +> iex -S mix + +Then for test the solution, into the REPL run: + +> ElixirFizz.start + +``` +$ iex -S mix + +Erlang/OTP 21 [erts-10.3.4] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [dtrace] +Compiling 1 file (.ex) +Interactive Elixir (1.8.1) - press Ctrl+C to exit (type h() ENTER for help) + +iex(1)> ElixirFizz.start +``` + +## How it works + +The next step is answer the questions in the REPL. If your answer is *correct* then you will have to answer the next question, but if your answer is *incorrect* you will have to answer again until your answer will be correct. + +#### Correct Answer + +``` +iex(1)> ElixirFizz.start +What is your favorite programming language? +Mine is COBOL, of course. +POST your answer back to this URL in JSON format. If you are having difficulties, see the exampleResponse provided. + +Write your answer::_ Elixir + +Your answer is: Elixir + +Answer Correct!! +Next question... +``` + +#### Incorrect Answer + +``` +Your numbers are: +[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + +Write your answer::_ 1 2 Fizz 4 Buzz 6 + +Your answer is: 1 2 Fizz 4 Buzz 6 +Answer is incorrect starting at position 16 ("6") +Try again!! + +Write your answer::_ +``` + +## ElixirFizz module design + +The *ElixirFizz* elixir module contains many funcions. + +The main funcion is *start()* and it's the only public function, this initialize the Fizzbot and start to make the request for answer to this bot. + +This are the private functions: + +Make the first request to Fizzbot +- `start_fizzbot_for_first_time(starter_uri)` + +Ask and answer +- `ask_to_fizzbot(fizzbot)` +- `answer_to_fizzbot({fizzbot, question_uri})` + +Input and output functions +- `getting_answer()` +- `show_rules(fizzbot)` + +Retry answer when it's wrong +- `validate_answer({fizzbot_answer, fizzbot, question_uri})` + +Make and parse requests +- `get(uri)` +- `post(uri)` + +If you want to see it you could follow this simple guide for understand how it works, and if you have some questions you can find me at Twitter as @carlogilmar. diff --git a/elixir_fizz/config/config.exs b/elixir_fizz/config/config.exs new file mode 100644 index 0000000..d2d855e --- /dev/null +++ b/elixir_fizz/config/config.exs @@ -0,0 +1 @@ +use Mix.Config diff --git a/elixir_fizz/lib/elixir_fizz.ex b/elixir_fizz/lib/elixir_fizz.ex new file mode 100644 index 0000000..5dbd59d --- /dev/null +++ b/elixir_fizz/lib/elixir_fizz.ex @@ -0,0 +1,77 @@ +defmodule ElixirFizz do + + @base_url "https://api.noopschallenge.com" + + # Only you have to open the iEX in this project and: + # + # > iex -S mix + # + # Interactive Elixir (1.8.1) - press Ctrl+C to exit (type h() ENTER for help) + # iex(1)> ElixirFizz.start + # + def start() do + "/fizzbot" + |> start_fizzbot_for_first_time() + |> ask_to_fizzbot() + end + + defp start_fizzbot_for_first_time(starter_uri), do: get(starter_uri) + + defp ask_to_fizzbot(fizzbot) do + next_fizzbot = get(fizzbot["nextQuestion"]) + show_rules(next_fizzbot) + answer_to_fizzbot({next_fizzbot, fizzbot["nextQuestion"]}) + end + + defp answer_to_fizzbot({fizzbot, question_uri}) do + answer = getting_answer() + fizzbot_answer = post(question_uri, %{"answer" => answer}) + validate_answer({fizzbot_answer, fizzbot, question_uri}) + end + + defp getting_answer() do + answer = IO.gets("\nWrite your answer::_ ") |> String.trim() + IO.puts "\nYour answer is: #{answer}" + answer + end + + defp show_rules(fizzbot) do + validate_rules = fn + true -> + IO.puts ":: GitHub :: Meet the Noobs :: Fizzbot Message ::" + IO.puts fizzbot["message"] + IO.puts "The rules are:" + IO.inspect fizzbot["rules"] + IO.puts "\nYour numbers are:" + IO.inspect fizzbot["numbers"] + false -> + IO.puts fizzbot["message"] + end + validate_rules.(Map.has_key?(fizzbot, "rules")) + end + + defp validate_answer({fizzbot_answer, fizzbot, question_uri}) do + validate_fizzbot = fn + "correct" -> + IO.puts "\nAnswer Correct!!" + IO.puts "Next question...\n" + ask_to_fizzbot(fizzbot_answer) + "incorrect" -> + IO.puts fizzbot_answer["message"] + IO.puts "Try again!!" + answer_to_fizzbot({fizzbot, question_uri}) + end + validate_fizzbot.(fizzbot_answer["result"]) + end + + defp get(uri) do + {:ok, response} = HTTPoison.get("#{@base_url}#{uri}") + Poison.decode!(response.body) + end + + defp post(uri, body) do + {:ok, response} = HTTPoison.post("#{@base_url}#{uri}", Poison.encode!(body), [{"Content-type", "application/json"}]) + Poison.decode!(response.body) + end + +end diff --git a/elixir_fizz/mix.exs b/elixir_fizz/mix.exs new file mode 100644 index 0000000..3c83c0f --- /dev/null +++ b/elixir_fizz/mix.exs @@ -0,0 +1,26 @@ +defmodule ElixirFizz.MixProject do + use Mix.Project + + def project do + [ + app: :elixir_fizz, + version: "0.1.0", + elixir: "~> 1.8", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + def application do + [ + extra_applications: [:logger] + ] + end + + defp deps do + [ + {:httpoison, "~> 1.0", override: true}, + {:poison, "~> 3.1"} + ] + end +end diff --git a/elixir_fizz/mix.lock b/elixir_fizz/mix.lock new file mode 100644 index 0000000..d33695c --- /dev/null +++ b/elixir_fizz/mix.lock @@ -0,0 +1,12 @@ +%{ + "certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"}, + "hackney": {:hex, :hackney, "1.15.1", "9f8f471c844b8ce395f7b6d8398139e26ddca9ebc171a8b91342ee15a19963f4", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, + "httpoison": {:hex, :httpoison, "1.5.1", "0f55b5b673b03c5c327dac7015a67cb571b99b631acc0bc1b0b98dcd6b9f2104", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, + "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, + "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"}, + "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"}, + "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"}, + "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"}, +} From 5196977042397887082c65fa94ed77187358c97b Mon Sep 17 00:00:00 2001 From: Carlo Gilmar Date: Wed, 12 Jun 2019 03:04:40 -0500 Subject: [PATCH 2/6] Adding bot --- elixir_fizz/lib/bot.ex | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 elixir_fizz/lib/bot.ex diff --git a/elixir_fizz/lib/bot.ex b/elixir_fizz/lib/bot.ex new file mode 100644 index 0000000..e032172 --- /dev/null +++ b/elixir_fizz/lib/bot.ex @@ -0,0 +1,16 @@ +defmodule ElixirFizz.Bot do + + def generate_answer(numbers) do + tokens = + for number <- numbers do + fizzbuzz({number, rem(number, 3)== 0, rem(number, 5) == 0}) + end + Enum.join(tokens, " ") + end + + def fizzbuzz({number, false, false}), do: "#{number}" + def fizzbuzz({_number, true, false}), do: "Fizz" + def fizzbuzz({_number, false, true}), do: "Buzz" + def fizzbuzz({_number, true, true}), do: "FizzBuzz" + +end From a506d6f755cc973252749fdcc1f79491ed7c5ef2 Mon Sep 17 00:00:00 2001 From: Carlo Gilmar Date: Wed, 12 Jun 2019 03:12:54 -0500 Subject: [PATCH 3/6] Adding a bot for answer automatic --- elixir_fizz/lib/bot.ex | 13 ++++++++----- elixir_fizz/lib/elixir_fizz.ex | 8 +++++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/elixir_fizz/lib/bot.ex b/elixir_fizz/lib/bot.ex index e032172..9323b4d 100644 --- a/elixir_fizz/lib/bot.ex +++ b/elixir_fizz/lib/bot.ex @@ -1,6 +1,9 @@ defmodule ElixirFizz.Bot do - def generate_answer(numbers) do + def answer({_fizzbot, false}), do: "Elixir" + def answer({fizzbot, true}), do: generate_answer(fizzbot["numbers"]) + + defp generate_answer(numbers) do tokens = for number <- numbers do fizzbuzz({number, rem(number, 3)== 0, rem(number, 5) == 0}) @@ -8,9 +11,9 @@ defmodule ElixirFizz.Bot do Enum.join(tokens, " ") end - def fizzbuzz({number, false, false}), do: "#{number}" - def fizzbuzz({_number, true, false}), do: "Fizz" - def fizzbuzz({_number, false, true}), do: "Buzz" - def fizzbuzz({_number, true, true}), do: "FizzBuzz" + defp fizzbuzz({number, false, false}), do: "#{number}" + defp fizzbuzz({_number, true, false}), do: "Fizz" + defp fizzbuzz({_number, false, true}), do: "Buzz" + defp fizzbuzz({_number, true, true}), do: "FizzBuzz" end diff --git a/elixir_fizz/lib/elixir_fizz.ex b/elixir_fizz/lib/elixir_fizz.ex index 5dbd59d..8fb508b 100644 --- a/elixir_fizz/lib/elixir_fizz.ex +++ b/elixir_fizz/lib/elixir_fizz.ex @@ -1,4 +1,5 @@ defmodule ElixirFizz do + alias ElixirFizz.Bot @base_url "https://api.noopschallenge.com" @@ -20,11 +21,12 @@ defmodule ElixirFizz do defp ask_to_fizzbot(fizzbot) do next_fizzbot = get(fizzbot["nextQuestion"]) show_rules(next_fizzbot) - answer_to_fizzbot({next_fizzbot, fizzbot["nextQuestion"]}) + answer = Bot.answer({next_fizzbot, Map.has_key?(next_fizzbot, "numbers")}) + answer_to_fizzbot({next_fizzbot, fizzbot["nextQuestion"], answer}) end - defp answer_to_fizzbot({fizzbot, question_uri}) do - answer = getting_answer() + defp answer_to_fizzbot({fizzbot, question_uri, answer}) do + IO.puts "\nSe generĂ³ la siguiente respuesta: #{answer}" fizzbot_answer = post(question_uri, %{"answer" => answer}) validate_answer({fizzbot_answer, fizzbot, question_uri}) end From 7f8a1b47c82891a6c11ca72a79d8d9089a6e3438 Mon Sep 17 00:00:00 2001 From: Carlo Gilmar Date: Wed, 12 Jun 2019 03:19:49 -0500 Subject: [PATCH 4/6] Adding rules for write the answer --- elixir_fizz/lib/bot.ex | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/elixir_fizz/lib/bot.ex b/elixir_fizz/lib/bot.ex index 9323b4d..9c1a309 100644 --- a/elixir_fizz/lib/bot.ex +++ b/elixir_fizz/lib/bot.ex @@ -1,19 +1,21 @@ defmodule ElixirFizz.Bot do def answer({_fizzbot, false}), do: "Elixir" - def answer({fizzbot, true}), do: generate_answer(fizzbot["numbers"]) + def answer({fizzbot, true}), do: generate_answer(fizzbot) - defp generate_answer(numbers) do + defp generate_answer(fizzbot) do + numbers = fizzbot["numbers"] + [numberA, numberB] = fizzbot["rules"] tokens = for number <- numbers do - fizzbuzz({number, rem(number, 3)== 0, rem(number, 5) == 0}) + fizzbuzz({number, rem(number, numberA["number"])== 0, numberA["response"], rem(number, numberB["number"]) == 0, numberB["response"]}) end Enum.join(tokens, " ") end - defp fizzbuzz({number, false, false}), do: "#{number}" - defp fizzbuzz({_number, true, false}), do: "Fizz" - defp fizzbuzz({_number, false, true}), do: "Buzz" - defp fizzbuzz({_number, true, true}), do: "FizzBuzz" + defp fizzbuzz({number, false, _numberA, false, _numberB}), do: "#{number}" + defp fizzbuzz({_number, true, numberA, false, _numberB}), do: numberA + defp fizzbuzz({_number, false, _numberA, true, numberB}), do: numberB + defp fizzbuzz({_number, true, numberA, true, numberB}), do: "#{numberA}#{numberB}" end From 4de869341cface73f98effec4014f699cdd018af Mon Sep 17 00:00:00 2001 From: Carlo Gilmar Date: Wed, 12 Jun 2019 03:31:32 -0500 Subject: [PATCH 5/6] Adding case for three rules --- elixir_fizz/lib/bot.ex | 33 +++++++++++++++++++++++++++++---- elixir_fizz/lib/elixir_fizz.ex | 8 ++------ 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/elixir_fizz/lib/bot.ex b/elixir_fizz/lib/bot.ex index 9c1a309..50748a1 100644 --- a/elixir_fizz/lib/bot.ex +++ b/elixir_fizz/lib/bot.ex @@ -1,21 +1,46 @@ defmodule ElixirFizz.Bot do def answer({_fizzbot, false}), do: "Elixir" - def answer({fizzbot, true}), do: generate_answer(fizzbot) + def answer({fizzbot, true}), do: generate_answer(fizzbot, length(fizzbot["rules"])) - defp generate_answer(fizzbot) do - numbers = fizzbot["numbers"] + defp generate_answer(fizzbot, 2) do [numberA, numberB] = fizzbot["rules"] tokens = - for number <- numbers do + for number <- fizzbot["numbers"] do fizzbuzz({number, rem(number, numberA["number"])== 0, numberA["response"], rem(number, numberB["number"]) == 0, numberB["response"]}) end Enum.join(tokens, " ") end + defp generate_answer(fizzbot, 3) do + [numberA, numberB, numberC] = fizzbot["rules"] + tokens = + for number <- fizzbot["numbers"] do + fizzbot({ number, + rem(number, numberA["number"])== 0, + numberA["response"], + rem(number, numberB["number"]) == 0, + numberB["response"], + rem(number, numberC["number"]) == 0, + numberC["response"] + }) + end + Enum.join(tokens, " ") + end + defp fizzbuzz({number, false, _numberA, false, _numberB}), do: "#{number}" defp fizzbuzz({_number, true, numberA, false, _numberB}), do: numberA defp fizzbuzz({_number, false, _numberA, true, numberB}), do: numberB defp fizzbuzz({_number, true, numberA, true, numberB}), do: "#{numberA}#{numberB}" + + defp fizzbot({_number, true, respA, true, respB, true, respC}), do: "#{respA}#{respB}#{respC}" + defp fizzbot({_number, true, respA, false, _respB, false, _respC}), do: respA + defp fizzbot({_number, false, _respA, true, respB, false, _respC}), do: respB + defp fizzbot({_number, false, _respA, false, _respB, true, respC}), do: respC + defp fizzbot({number, false, _respA, false, _respB, false, _respC}), do: number + defp fizzbot({_number, true, respA, true, respB, false, _respC}), do: "#{respA}#{respB}" + defp fizzbot({_number, true, respA, false, _respB, true, respC}), do: "#{respA}#{respC}" + defp fizzbot({_number, false, _respA, true, respB, true, respC}), do: "#{respB}#{respC}" + end diff --git a/elixir_fizz/lib/elixir_fizz.ex b/elixir_fizz/lib/elixir_fizz.ex index 8fb508b..2020698 100644 --- a/elixir_fizz/lib/elixir_fizz.ex +++ b/elixir_fizz/lib/elixir_fizz.ex @@ -31,12 +31,6 @@ defmodule ElixirFizz do validate_answer({fizzbot_answer, fizzbot, question_uri}) end - defp getting_answer() do - answer = IO.gets("\nWrite your answer::_ ") |> String.trim() - IO.puts "\nYour answer is: #{answer}" - answer - end - defp show_rules(fizzbot) do validate_rules = fn true -> @@ -62,6 +56,8 @@ defmodule ElixirFizz do IO.puts fizzbot_answer["message"] IO.puts "Try again!!" answer_to_fizzbot({fizzbot, question_uri}) + "interview complete" -> + IO.puts " DONE " end validate_fizzbot.(fizzbot_answer["result"]) end From b349bd58caa57c125b2cc118858e62a445ab9d4f Mon Sep 17 00:00:00 2001 From: Carlo Gilmar Date: Mon, 17 Jun 2019 01:58:00 -0500 Subject: [PATCH 6/6] Adding duration --- elixir_fizz/lib/elixir_fizz.ex | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/elixir_fizz/lib/elixir_fizz.ex b/elixir_fizz/lib/elixir_fizz.ex index 2020698..1a718b7 100644 --- a/elixir_fizz/lib/elixir_fizz.ex +++ b/elixir_fizz/lib/elixir_fizz.ex @@ -11,9 +11,13 @@ defmodule ElixirFizz do # iex(1)> ElixirFizz.start # def start() do + start_time = :os.system_time(:millisecond) "/fizzbot" |> start_fizzbot_for_first_time() |> ask_to_fizzbot() + end_time = :os.system_time(:millisecond) + duration = (end_time - start_time)/1000 + IO.puts "Interview finalized in #{duration} seconds" end defp start_fizzbot_for_first_time(starter_uri), do: get(starter_uri)