Current section

Files

Jump to
tesla lib tesla.ex
Raw

lib/tesla.ex

defmodule Tesla.Env do
defstruct url: "",
method: nil,
status: nil,
headers: %{},
body: nil,
opts: []
end
defmodule Tesla.Builder do
defmacro __using__(_what) do
method_defs = for method <- [:get, :head, :delete, :trace, :options] do
quote do
def unquote(method)(fun, url, opts) when is_function(fun) do
request(fun, unquote(method), url, nil, opts)
end
def unquote(method)(fun, url) when is_function(fun) do
request(fun, unquote(method), url, nil, [])
end
def unquote(method)(url, opts) do
request(unquote(method), url, nil, opts)
end
def unquote(method)(url) do
request(unquote(method), url, nil, [])
end
end
end
method_defs_with_body = for method <- [:post, :put, :patch] do
quote do
def unquote(method)(fun, url, body, opts) when is_function(fun) do
request(fun, unquote(method), url, body, opts)
end
def unquote(method)(fun, url, body) when is_function(fun) do
request(fun, unquote(method), url, body, [])
end
def unquote(method)(url, body, opts) do
request(unquote(method), url, body, opts)
end
def unquote(method)(url, body) do
request(unquote(method), url, body, [])
end
end
end
quote do
unquote(method_defs)
unquote(method_defs_with_body)
defp request(fun, method, url, body, opts) when is_function(fun) do
env = %Tesla.Env{
method: method,
url: url,
body: body,
opts: opts
}
fun.(env, &call_middleware/1)
end
defp request(method, url, body, opts) do
request(fn (env, run) -> run.(env) end, method, url, body, opts)
end
import Tesla.Builder
Module.register_attribute(__MODULE__, :middleware, accumulate: true)
@before_compile Tesla.Builder
end
end
defmacro __before_compile__(env) do
middleware = Module.get_attribute(env.module, :middleware)
reduced = Enum.reduce(middleware, (quote do: call_adapter(env)), fn {mid, args}, acc ->
quote do
unquote(mid).call(env, fn(env) -> unquote(acc) end, unquote(args))
end
end)
quote do
def call_middleware(env) do
unquote(reduced)
end
end
end
def process_adapter_response(env, res) do
case res do
{status, headers, body} ->
%{env | status: status, headers: headers, body: body}
e -> e
end
end
defmacro adapter({:fn, _, _} = ad) do # pattern match for function
quote do
def call_adapter(env) do
Tesla.Builder.process_adapter_response(env, unquote(ad).(env))
end
end
end
defmacro adapter(ad) do
quote do
def call_adapter(env) do
Tesla.Builder.process_adapter_response(env, unquote(ad).call(env))
end
end
end
defmacro with(middleware) do
quote do
@middleware {unquote(middleware), nil}
end
end
defmacro with(middleware, args) do
quote do
@middleware {unquote(middleware), unquote(args)}
end
end
end
defmodule Tesla do
use Tesla.Builder
adapter Tesla.Adapter.Ibrowse
def build_client(stack) do
fn (env, run) ->
f = Enum.reduce(stack, run, fn ({mid, args}, acc) ->
fn (env) -> mid.call(env, fn(e) -> acc.(e) end, args) end
end)
f.(env)
end
end
def start do
Tesla.Adapter.Ibrowse.start
end
end