stephen_m
stephen_m

Reputation: 910

Error - implementing a protocol in elixir

I'm running the following code:

ExHubic.Request.request({:get, "/account", nil, :hubic}, ExHubic)   

and getting the following error:

** (Protocol.UndefinedError) protocol ExHubic.Request not implemented for {:get, "/account", nil, :hubic}
    (ex_hubic) lib/request.ex:1: ExHubic.Request.impl_for!/1
    (ex_hubic) lib/request.ex:6: ExHubic.Request.request/2

This error message suggests to me that the protocol is not implemented for the type ExHubic.Query.Hubic.t which is defined as @type t :: {atom, String.t, any, :hubic}

It could well be a problem with the types that I have created but I can't see it.

Some context:

defprotocol ExHubic.Request do
  @moduledoc false
  @spec request(query :: ExHubic.Query.t, client :: atom)
                :: ExHubic.Query.http_query_t
  def request(query, client)
end

defimpl ExHubic.Request, for:  ExHubic.Query.Hubic  do
  @spec request(query :: ExHubic.Query.Hubic.t, client :: atom)
                :: {:ok, ExHubic.Client.response_t} | {:error, ExHubic.Client.response_t}
  def request({method, uri, params, :hubic} = query, client) do
     implementation_details
  end
end

defmodule ExHubic.Query do
  @moduledoc false
  @type t ::  {atom, String.t, any, atom}
end

defmodule ExHubic.Query.Hubic do
  @type t :: {atom, String.t, any, :hubic}
  @spec account() :: __MODULE__.t
  def account(), do: {:get, "/account", :nil, :hubic}
end

Upvotes: 0

Views: 493

Answers (1)

Gazler
Gazler

Reputation: 84140

There are a couple of issues here, first of all, you are using an atom (module name) for the protocol. You need to use either a built in type or a struct as described in http://elixir-lang.org/getting-started/protocols.html#protocols-and-structs. This means adding a defstruct to the module:

defmodule ExHubic.Query.Hubic do
  defstruct [:method, :uri, :params,  service: :hubic]
  @type t :: %__MODULE__{method: atom, uri: String.t, params: any, service: :hubic}
  def account(), do: {:get, "/account", :nil, :hubic}
end

defprotocol ExHubic.Request do
  def request(query, client)
end


defimpl ExHubic.Request, for:  ExHubic.Query.Hubic  do

  @spec request(Query.t, atom) :: any
  def request(query, client) do
    IO.inspect query
  end
end

You can then use this with:

ExHubic.Request.request(%ExHubic.Query.Hubic{method: :get, params: nil, service: :hubic, uri: "/account"}, client)

Upvotes: 3

Related Questions