Skip to content

Commit

Permalink
refactor!: more explicit usage of JSON libraries
Browse files Browse the repository at this point in the history
BREAKING CHANGE: modify Protox.JsonLibrary behaviour
  • Loading branch information
ahamez committed Nov 15, 2024
1 parent ff41e38 commit 0e85717
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 38 deletions.
8 changes: 4 additions & 4 deletions lib/protox/define_message.ex
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,12 @@ defmodule Protox.DefineMessage do

@spec json_decode!(iodata(), keyword()) :: struct() | no_return()
def json_decode!(input, opts \\ []) do
{json_library_wrapper, json_library} = Protox.JsonLibrary.get_library(opts, :decode)
json_library_wrapper = Protox.JsonLibrary.get_library(opts, :decode)

Protox.JsonDecode.decode!(
input,
unquote(msg_name),
&json_library_wrapper.decode!(json_library, &1)
&json_library_wrapper.decode!(&1)
)
end

Expand All @@ -128,9 +128,9 @@ defmodule Protox.DefineMessage do

@spec json_encode!(struct(), keyword()) :: iodata() | no_return()
def json_encode!(msg, opts \\ []) do
{json_library_wrapper, json_library} = Protox.JsonLibrary.get_library(opts, :encode)
json_library_wrapper = Protox.JsonLibrary.get_library(opts, :encode)

Protox.JsonEncode.encode!(msg, &json_library_wrapper.encode!(json_library, &1))
Protox.JsonEncode.encode!(msg, &json_library_wrapper.encode!(&1))
end
end
end
Expand Down
16 changes: 6 additions & 10 deletions lib/protox/jason.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ defmodule Protox.Jason do

if Code.ensure_loaded?(Jason) do
@impl true
def load() do
{:ok, Jason}
end
def load(), do: :ok

@impl true
def decode!(_jason_module, iodata) do
def decode!(iodata) do
try do
Jason.decode!(iodata)
rescue
Expand All @@ -19,7 +17,7 @@ defmodule Protox.Jason do
end

@impl true
def encode!(_jason_module, term) do
def encode!(term) do
try do
Jason.encode!(term)
rescue
Expand All @@ -29,19 +27,17 @@ defmodule Protox.Jason do
end
else
@impl true
def load() do
:error
end
def load(), do: :error

@impl true
def decode!(_jason_module, _iodata) do
def decode!(_iodata) do
raise Protox.JsonDecodingError.new(
"Jason library not loaded. Please check your project dependencies."
)
end

@impl true
def encode!(_jason_module, _term) do
def encode!(_term) do
raise Protox.JsonEncodingError.new(
"Jason library not loaded. Please check your project dependencies."
)
Expand Down
13 changes: 7 additions & 6 deletions lib/protox/json_library.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,26 @@ defmodule Protox.JsonLibrary do
The behaviour to implement when wrapping a JSON library.
"""

@callback load() :: {:ok, atom()} | :error
@callback load() :: :ok | :error

@doc """
Should wrap any exception of the underlying library in Protox.JsonDecodingError.
"""
@callback decode!(atom(), iodata()) :: term() | no_return()
@callback decode!(iodata()) :: term() | no_return()

@doc """
Should wrap any exception of the underlying library in Protox.JsonEncodingError.
"""
@callback encode!(atom(), term()) :: iodata() | no_return()
@callback encode!(term()) :: iodata() | no_return()

@doc false
def get_library(opts, decoding_or_encoding) do
json_library_wrapper = Keyword.get(opts, :json_library, Protox.Jason)
json_library_name = Keyword.get(opts, :json_library, Jason)
json_library_wrapper = Module.concat(Protox, json_library_name)

case json_library_wrapper.load() do
{:ok, json_library} ->
{json_library_wrapper, json_library}
:ok ->
json_library_wrapper

:error ->
message = "cannot load JSON library. Please check your project dependencies."
Expand Down
20 changes: 8 additions & 12 deletions lib/protox/poison.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,40 @@ defmodule Protox.Poison do

if Code.ensure_loaded?(Poison) do
@impl true
def load() do
{:ok, Poison}
end
def load(), do: :ok

@impl true
def decode!(poison_module, iodata) do
def decode!(iodata) do
try do
poison_module.decode!(iodata)
Poison.decode!(iodata)
rescue
e in [Poison.DecodeError, Poison.ParseError] ->
reraise Protox.JsonDecodingError.new(Exception.message(e)), __STACKTRACE__
end
end

@impl true
def encode!(poison_module, term) do
def encode!(term) do
try do
poison_module.encode!(term)
Poison.encode!(term)
rescue
e in Poison.EncodeError ->
reraise Protox.JsonEncodingError.new(Exception.message(e)), __STACKTRACE__
end
end
else
@impl true
def load() do
:error
end
def load(), do: :error

@impl true
def decode!(_poison_module, _iodata) do
def decode!(_iodata) do
raise Protox.JsonDecodingError.new(
"Poison library not loaded. Please check your project dependencies."
)
end

@impl true
def encode!(_poison_module, _term) do
def encode!(_term) do
raise Protox.JsonEncodingError.new(
"Poison library not loaded. Please check your project dependencies."
)
Expand Down
6 changes: 3 additions & 3 deletions test/protox/json_decode_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -692,19 +692,19 @@ defmodule Protox.JsonDecodeTest do
end

test "Success: jason", %{json: json, expected: expected} do
assert Protox.json_decode!(json, Sub, json_library: Protox.Jason) == expected
assert Protox.json_decode!(json, Sub, json_library: Jason) == expected
end

test "Success: poison", %{json: json, expected: expected} do
assert Protox.json_decode!(json, Sub, json_library: Protox.Poison) == expected
assert Protox.json_decode!(json, Sub, json_library: Poison) == expected
end

test "Failure: poison", %{} do
assert_raise Protox.JsonDecodingError, fn ->
Protox.json_decode!(
"{\"mapInt32Int32\": 1",
ProtobufTestMessages.Proto3.TestAllTypesProto3,
json_library: Protox.Poison
json_library: Poison
)
end
end
Expand Down
6 changes: 3 additions & 3 deletions test/protox/json_encode_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ defmodule Protox.JsonEncodeTest do
describe "JSON libraries" do
test "Success: Jason" do
msg = %Msg{msg_k: %{1 => "a", 2 => "b"}}
json = Protox.json_encode!(msg, json_library: Protox.Jason)
json = Protox.json_encode!(msg, json_library: Jason)

assert json == [
"{",
Expand All @@ -405,7 +405,7 @@ defmodule Protox.JsonEncodeTest do

test "Success: Poison" do
msg = %Msg{msg_k: %{1 => "a", 2 => "b"}}
json = Protox.json_encode!(msg, json_library: Protox.Poison)
json = Protox.json_encode!(msg, json_library: Poison)

assert json == [
"{",
Expand All @@ -418,7 +418,7 @@ defmodule Protox.JsonEncodeTest do
invalid_field = %ProtobufTestMessages.Proto3.TestAllTypesProto3{optional_int32: make_ref()}

assert_raise Protox.JsonEncodingError, fn ->
Protox.json_encode!(invalid_field, json_library: Protox.Poison)
Protox.json_encode!(invalid_field, json_library: Poison)
end
end
end
Expand Down

0 comments on commit 0e85717

Please sign in to comment.