Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Things you could do with Mix, but probably shou...

Things you could do with Mix, but probably shouldn't

Elixir's build tool Mix can be used for a lot more things than most people think of. In this talk I explore some of the things you could do with Mix...

Avatar for Tjaco Oostdijk

Tjaco Oostdijk

November 30, 2018
Tweet

Other Decks in Technology

Transcript

  1. We are passionately committed to exceed your expectations in every

    step we take. We value creativity and flexibility.
  2. TDD

  3. defmodule Mix.Tasks.Cocktail do @moduledoc """ Find a cocktail by ingredient

    """ use Mix.Task alias Mix.Shell.IO def run(_argv) do IO.info "Ran Cocktail Task" end end
  4. defmodule MixHelp.Api.Cocktails do @moduledoc false use HTTPoison.Base def process_url(url) do

    "https://www.thecocktaildb.com/api/json/v1/1/" <> url end def process_response_body(body) do body |> Poison.decode!() end
  5. defmodule MixHelp.Api.Cocktails do @moduledoc false use HTTPoison.Base def find_by_ingredient(ingredient) do

    result = __MODULE__.get!("filter.php?i=#{ingredient}").body result["drinks"] end def process_url(url) do "https://www.thecocktaildb.com/api/json/v1/1/" <> url end def process_response_body(body) do body |> Poison.decode!() end end
  6. defmodule Mix.Tasks.Cocktail do @moduledoc """ Find a cocktail by ingredient

    """ use Mix.Task alias MixHelp.Api.Cocktails def run(argv) do HTTPoison.start() Cocktails.find_by_ingredient(argv) |> Enum.map(fn(x) -> x["strDrink"] end) |> Enum.join("\n") |> IO.puts end end
  7. defmodule Mix.Tasks.Generate.Task do @moduledoc """ Generate boilerplate for a new

    mix task """ use Mix.Task alias Mix.Shell.IO def run(_argv) do IO.info "Let's create a new mix task!" taskname = IO.prompt("What should we call this new task?") description = IO.prompt("PLease describe what your task does.") modulename = (String.trim(taskname) |> String.capitalize) …
  8. Mix.Generator.create_file( "lib/mix/tasks/#{String.trim(taskname)}.ex", “"" defmodule Mix.Tasks.#{modulename} do @moduledoc \""" #{description} \"""

    use Mix.Task alias Mix.Shell.IO def run(_argv) do IO.info \“”” Nothing implemented yet…\nAdd your implementation in lib/mix/tasks/#{taskname}.ex \“”” end end )
  9. defmodule Mix.Tasks.Neighbeerhood do @moduledoc """ Get location in a city

    to enjoy a nice beer! """ use Mix.Task def run(_argv) do IO.info "Nothing implemented yet... Add your implementation in lib/mix/tasks/neighbeerhood.ex" end end
  10. defmodule Mix.Tasks.Generate.Api do @moduledoc """ Generate boilerplate setup for an

    API endpoint """ use Mix.Task alias Mix.Shell.IO def run(_argv) do IO.info "Great! Let's create a new API endpoint." api_module = IO.prompt("Please provide the module name to use for this new API:") answer = IO.yes? "You have entered #{api_module}. Is that correct?" base_url = IO.prompt("Please provide the base_url for the api endpoint: ") case answer do false -> IO.info "You have entered no!" exit(:normal) _ -> "" end filename = (String.trim(api_module) |> String.downcase)
  11. Mix.Generator.create_file( "lib/api/#{filename}.ex", """ defmodule MixHelp.Api.#{String.trim(api_module)} do @moduledoc false use HTTPoison.Base

    def process_url(url) do "#{String.trim(base_url)}" <> url end def process_response_body(body) do body |> Poison.decode!() end end """)
  12. defmodule Mix.Tasks.Generate.Api do @moduledoc """ Generate boilerplate setup for an

    API endpoint """ use Mix.Task alias Mix.Shell.IO def run(_argv) do IO.info "Great! Let's create a new API endpoint." api_module = IO.prompt("Please provide the module name to use for this new API:") answer = IO.yes? "You have entered #{api_module}. Is that correct?" base_url = IO.prompt("Please provide the base_url for the api endpoint: ") case answer do false -> IO.info "You have entered no!" exit(:normal) _ -> "" end filename = (String.trim(api_module) |> String.downcase) Mix.Generator.create_file( "lib/api/#{filename}.ex", """ defmodule MixHelp.Api.#{String.trim(api_module)} do @moduledoc false use HTTPoison.Base def process_url(url) do "#{String.trim(base_url)}" <> url end def process_response_body(body) do body |> Poison.decode!() end end """) end
  13. defmodule MixHelp.Api.Beermapping do @moduledoc false use HTTPoison.Base def find_by_city(city) do

    query_string = URI.encode(city) __MODULE__.get!("#{query_string}&s=json").body end def process_url(url) do "http://beermapping.com/webservice/loccity/#{api_key}/" <> url end def process_response_body(body) do body |> Poison.decode!() end defp api_key do Application.get_env(:mix_help, :beermapping_api_key) end end
  14. defmodule MixHelp.Api.Beermapping do @moduledoc false use HTTPoison.Base def find_by_city(city) do

    query_string = URI.encode(city) __MODULE__.get!("#{query_string}&s=json").body end def process_url(url) do "http://beermapping.com/webservice/loccity/#{api_key}/" <> url end def process_response_body(body) do body |> Poison.decode!() end defp api_key do Application.get_env(:mix_help, :beermapping_api_key) end end
  15. defmodule Mix.Tasks.Neighbeerhood do @moduledoc """ Get location in a city

    to enjoy a nice beer! """ use Mix.Task def run(_argv) do IO.info "Nothing implemented yet... Add your implementation in lib/mix/tasks/neighbeerhood.ex" end end
  16. defmodule Mix.Tasks.Neighbeerhood do @moduledoc """ Get location in a city

    to enjoy a nice beer! """ use Mix.Task alias MixHelp.Api.Beermapping def run(argv) do HTTPoison.start() beerdata = Beermapping.find_by_city(argv) |> Enum.map(fn(x) -> "#{x["name"]} -#{x["status"]} => #{x["reviewlink"]}" end) |> Enum.join("\n") |> IO.puts end end
  17. defmodule Spotiplay.Api.Spotify do @moduledoc false use HTTPoison.Base @spec get_random_track(any()) ::

    any() def get_random_track(artist) do query_string = URI.encode_query(%{q: artist, type: "artist"}) result = __MODULE__.get!("search?#{query_string}").body["artists"]["items"] case result do [] -> nil _ -> result |> List.first |> Map.get("id") |> get_top_tracks |> Enum.random end end @spec get_top_tracks(any()) :: any() def get_top_tracks(artist_id) do __MODULE__.get!("artists/#{artist_id}/top-tracks?country=NL").body["tracks"] end def process_url(url) do "https://api.spotify.com/v1/" <> url end def process_response_body(body) do body |> Poison.decode!() end
  18. defmodule Spotiplay.Api.Spotify do @moduledoc false use HTTPoison.Base @spec get_random_track(any()) ::

    any() def get_random_track(artist) do query_string = URI.encode_query(%{q: artist, type: "artist"}) result = __MODULE__.get!("search?#{query_string}").body["artists"]["items"] case result do [] -> nil _ -> result |> List.first |> Map.get("id") |> get_top_tracks |> Enum.random end end @spec get_top_tracks(any()) :: any() def get_top_tracks(artist_id) do __MODULE__.get!("artists/#{artist_id}/top-tracks?country=NL").body["tracks"] end def process_url(url) do "https://api.spotify.com/v1/" <> url end def process_response_body(body) do body |> Poison.decode!() end
  19. defmodule Spotiplay.Api.Spotify do @moduledoc false use HTTPoison.Base @spec get_random_track(any()) ::

    any() def get_random_track(artist) do query_string = URI.encode_query(%{q: artist, type: "artist"}) result = __MODULE__.get!("search?#{query_string}").body["artists"]["items"] case result do [] -> nil _ -> result |> List.first |> Map.get("id") |> get_top_tracks |> Enum.random end end @spec get_top_tracks(any()) :: any() def get_top_tracks(artist_id) do __MODULE__.get!("artists/#{artist_id}/top-tracks?country=NL").body["tracks"] end def process_url(url) do "https://api.spotify.com/v1/" <> url end def process_response_body(body) do body |> Poison.decode!() end
  20. defmodule Spotiplay.Api.Spotify do @moduledoc false use HTTPoison.Base def get_random_track(artist) do

    query_string = URI.encode_query(%{q: artist, type: "artist"}) result = __MODULE__.get!("search?#{query_string}").body["artists"]["items"] case result do [] -> nil _ -> result |> List.first |> Map.get("id") |> get_top_tracks |> Enum.random end end def get_top_tracks(artist_id) do __MODULE__.get!("artists/#{artist_id}/top-tracks?country=NL").body["tracks"] end def process_url(url) do "https://api.spotify.com/v1/" <> url end def process_response_body(body) do body |> Poison.decode!() end
  21. def process_request_headers(headers) do headers ++ [{"Authorization", "Bearer #{access_token()}"}] end def

    access_token do client_id = Application.get_env(:spotiplay, :spotify_client_id) client_secret = Application.get_env(:spotiplay, :spotify_client_secret) headers = [ {"Authorization", "Basic #{Base.encode64("#{client_id}:#{client_secret}")}"} ] body = {:form, [grant_type: "client_credentials"]} HTTPoison.post!("https://accounts.spotify.com/api/token", body, headers).body |> Poison.decode! |> Map.get("access_token") end
  22. defmodule Spotiplay.CLI do @moduledoc """ Command Line client for SPitplay

    """ alias Spotiplay.Api.Spotify def main(argv \\ []) do artist = Enum.join(argv, " ") IO.puts("Let me find some music by #{artist}") HTTPoison.start() artist |> Spotify.get_random_track() |> play_track end … defp play_track(track) do case track["preview_url"] do nil -> play_track(nil) _ -> System.cmd("curl", ["-o", "file.mp3", track["preview_url"]], stderr_to_stdout: true) IO.puts("Ok, playing #{track["name"]} by #{artist(track)}") System.cmd("mplayer", ["file.mp3"], stderr_to_stdout: true) File.rm("file.mp3") end end … …
  23. Mix task vs escript? Use a mix archive when you:

    • are creating tooling to use in mix projects • are creating a global tool that doesn’t need any dependencies(ie. mix new, mix phx.new) Use an escript when: • You need external dependencies • The task is not specifically related to mix projects
  24. Still a lot of Ruby in my day to day…

    but, wait…. I have just discovered mix…
  25. Still a lot of Ruby in my day to day…

    but, wait…. I have just discovered mix… I wonder I if I could…
  26. Still a lot of Ruby in my day to day…

    but, wait…. I have just discovered mix… I wonder I if I could… No…
  27. Still a lot of Ruby in my day to day…

    but, wait…. I have just discovered mix… I wonder I if I could… No… I couldn’t….
  28. Still a lot of Ruby in my day to day…

    but, wait…. I have just discovered mix… I wonder I if I could… No… I couldn’t…. Or … could I ???