Skip to content

Instantly share code, notes, and snippets.

@sleepiecappy
Last active April 11, 2019 00:36
Show Gist options
  • Save sleepiecappy/fb20eb696108ca10c98235078059248a to your computer and use it in GitHub Desktop.
Save sleepiecappy/fb20eb696108ca10c98235078059248a to your computer and use it in GitHub Desktop.
defmodule App.Implementations do
def of(key) do
with impls when is_list(impls) <- Application.get_env(:app, :impls),
{:ok, module} <- Keyword.fetch(impls, key) do
module
else
:error ->
raise KeyError,
message: """
:#{key} key is not defined in the implementations for application :app
configure it as:
config :app, impls: [#{key}: MyImplmentation]
"""
_ ->
raise KeyError,
message: ":impls key is not defined in the current environment for application :app"
end
end
end
defmodule App.MyService do
alias App.Twitter
def average_tweet_length(handle) do
# testable using different implementation for tests
# matching on special handlers returns different cases for tests
twitter = Twitter.client()
handle
|> twitter.tweets()
|> Enum.map(fn tweet -> String.length(tweet.text) end)
|> avg()
end
def avg(lengths) when lengths != [] do
Enum.sum(lengths) / Enum.count(lengths)
end
def avg(_), do: 0
end
defmodule App.Twitter do
@callback tweets(handle :: String.t()) :: list(map())
@doc """
Provides a client implementing this behaviour
configure it per env:
config :app, impls: [twitter: App.Twitter]
"""
def client do
App.Implementations.of(:twitter)
end
end
defmodule App.TwitterAPI do
@behaviour App.Twitter
def tweets(handle) do
# do call to twitter api using HTTP
[%{handle: handle, text: "elixir is awesome"}]
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment