Skip to content

Commit

Permalink
🎨 Improve Elixir coding practices
Browse files Browse the repository at this point in the history
  • Loading branch information
ImNotAVirus committed Sep 3, 2019
1 parent 5e738cd commit 12b3cb9
Show file tree
Hide file tree
Showing 27 changed files with 154 additions and 132 deletions.
6 changes: 3 additions & 3 deletions config/.credo.exs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
{Credo.Check.Readability.AliasOrder, []},
{Credo.Check.Readability.FunctionNames, []},
{Credo.Check.Readability.LargeNumbers, []},
{Credo.Check.Readability.MaxLineLength, [priority: :low, max_length: 100]},
{Credo.Check.Readability.MaxLineLength, [max_length: 98]},
{Credo.Check.Readability.ModuleAttributeNames, []},
{Credo.Check.Readability.ModuleDoc, []},
{Credo.Check.Readability.ModuleNames, []},
Expand All @@ -102,7 +102,7 @@
{Credo.Check.Refactor.CyclomaticComplexity, []},
{Credo.Check.Refactor.FunctionArity, []},
{Credo.Check.Refactor.LongQuoteBlocks, []},
{Credo.Check.Refactor.MapInto, []},
{Credo.Check.Refactor.MapInto, false},
{Credo.Check.Refactor.MatchInCondition, []},
{Credo.Check.Refactor.NegatedConditionsInUnless, []},
{Credo.Check.Refactor.NegatedConditionsWithElse, []},
Expand All @@ -121,7 +121,7 @@
{Credo.Check.Warning.ExpensiveEmptyEnumCheck, []},
{Credo.Check.Warning.IExPry, []},
{Credo.Check.Warning.IoInspect, []},
{Credo.Check.Warning.LazyLogging, []},
{Credo.Check.Warning.LazyLogging, false},
{Credo.Check.Warning.OperationOnSameValues, []},
{Credo.Check.Warning.OperationWithConstantResult, []},
{Credo.Check.Warning.RaiseInsideRescue, []},
Expand Down
4 changes: 2 additions & 2 deletions guides/introduction/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ defmodule LoginServer.Auth.Actions do
# Send the response to the client
Client.send(client, render)

# We continue to receive packets from the client
# We continue to receive packages from the client
{:cont, client}
end

Expand Down Expand Up @@ -295,7 +295,7 @@ SUCCESS 127.0.0.1:1234 # Client response
```

```
# Back to terminal 1, we also received several messages due to the application logs
#Back to terminal 1, we also received several messages due to the application logs
XX:XX:XX.XX [info] Login server started on port 3000
XX:XX:XX.XX [info] New connection: 226167fe-493f-47ea-ae81-5f94e0e728ed
XX:XX:XX.XX [info] New message from 226167fe-493f-47ea-ae81-5f94e0e728ed (len: 5)
Expand Down
2 changes: 1 addition & 1 deletion lib/elven_gard.ex
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
defmodule ElvenGard do
@moduledoc """
Documentation for ElvenGard.
Documentation for ElvenGard
"""
end
22 changes: 19 additions & 3 deletions lib/elven_gard/exceptions.ex
Original file line number Diff line number Diff line change
@@ -1,19 +1,35 @@
defmodule ElvenGard.TypeOptionError do
@moduledoc """
Raised when wrong options are given to `c:ElvenGard.Type.encode/2` or `c:ElvenGard.Type.decode/2`
Exception raised when wrong options are given to `c:ElvenGard.Type.encode/2` or `c:ElvenGard.Type.decode/2`
"""

defexception [:message]
end

defmodule ElvenGard.UnknownViewError do
@moduledoc """
Raised when a view is not found
Exception raised when a view is not found
"""

defexception [:parent, :type]

@impl true
def message(%{parent: parent, type: type}) do
"unable to find the `render/2` function with the '#{inspect(type)}' key " <>
"Unable to find the `render/2` function with the '#{inspect(type)}' key " <>
"(from #{inspect(parent)})"
end
end

defmodule ElvenGard.FieldTypeError do
@moduledoc """
Exception raised when the type of a protocol field is not defined
"""

defexception [:field_name, :field_type, :packet_name]

@impl true
def message(%{field_name: field_name, field_type: field_type, packet_name: packet_name}) do
"invalid type #{inspect(field_type)} for the field #{inspect(field_name)} " <>
"(packet: #{inspect(packet_name)})"
end
end
11 changes: 5 additions & 6 deletions lib/elven_gard/frontend.ex
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,20 @@ defmodule ElvenGard.Frontend do

# Check is there is any protocol
unless protocol do
raise "Please, specify a packet_protocol for #{caller}"
raise "please, specify a packet_protocol for #{caller}"
end

# Check is there is any handler
unless handler do
raise "Please, specify a packet_handler for #{caller}"
raise "please, specify a packet_handler for #{caller}"
end

quote do
alias ElvenGard.Structures.Client

@behaviour unquote(parent)
@behaviour :ranch_protocol

# TODO: Use `Application.get_env` inside function for a live update
alias ElvenGard.Structures.Client

@timeout Application.get_env(:elven_gard, :response_timeout, 2000)

@doc false
Expand Down Expand Up @@ -169,7 +168,7 @@ defmodule ElvenGard.Frontend do

defp do_handle_packet(x, _client) do
raise """
Unable to handle packet #{inspect(x)}.
unable to handle packet #{inspect(x)}.
Please check that your protocol returns a tuple in the form of {header, \
%{param1: :val1, param2: :val2, ...} or a list of tuples
"""
Expand Down
5 changes: 3 additions & 2 deletions lib/elven_gard/packet.ex
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ defmodule ElvenGard.Packet do
)

quote do
require Logger
import unquote(parent)

require Logger

@before_compile unquote(parent)
@desc nil
end
Expand All @@ -43,7 +44,7 @@ defmodule ElvenGard.Packet do
{:cont, client}
end

def fetch_definitions() do
def get_packet_definitions() do
@elven_packet_definitions
end
end
Expand Down
5 changes: 3 additions & 2 deletions lib/elven_gard/protocol.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule ElvenGard.Protocol do
@moduledoc """
Transform a raw packet (packet received by a client) into a packet that can be
pattern match by a PacketHandler.
pattern match by a PacketHandler
/!\\ No side effect: Cannot change or modify the current `ElvenGard.Structures.Client`
Expand Down Expand Up @@ -66,10 +66,11 @@ defmodule ElvenGard.Protocol do

quote do
@behaviour unquote(parent)
@before_compile unquote(parent)

alias ElvenGard.Structures.Client

@before_compile unquote(parent)

@doc """
Successively applies functions `pre_encode`, `encode` and `post_encode`
"""
Expand Down
8 changes: 4 additions & 4 deletions lib/elven_gard/protocol/binary.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defmodule ElvenGard.Protocol.Binary do
TODO: Documentation for ElvenGard.Protocol.Binary
"""

alias ElvenGard.FieldTypeError
alias ElvenGard.Structures.{Client, PacketDefinition}

@aliases [
Expand All @@ -17,7 +18,7 @@ defmodule ElvenGard.Protocol.Binary do
@doc false
defmacro __using__(model: model) do
expanded_model = Macro.expand(model, __CALLER__)
defs = expanded_model.fetch_definitions()
defs = expanded_model.get_packet_definitions()

:ok = check_types!(defs)

Expand All @@ -39,7 +40,7 @@ defmodule ElvenGard.Protocol.Binary do
end

## Define sub decoders
Enum.each(unquote(model).fetch_definitions(), fn packet ->
Enum.each(unquote(model).get_packet_definitions(), fn packet ->
name = packet.name
fields = Macro.escape(packet.fields)

Expand Down Expand Up @@ -89,8 +90,7 @@ defmodule ElvenGard.Protocol.Binary do
@spec check_type!(atom, atom, term) :: term
defp check_type!(type, name, def_name) do
unless Keyword.has_key?(type.__info__(:functions), :decode) do
raise "Invalid type '#{inspect(type)}' for '#{inspect(name)}' " <>
"for packet '#{inspect(def_name)}'"
raise FieldTypeError, field_type: type, field_name: name, packet_name: def_name
end
end
end
2 changes: 1 addition & 1 deletion lib/elven_gard/protocol/binary/padding_type.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ defmodule ElvenGard.Protocol.Binary.PaddingType do
bytes = Keyword.get(opts, :bytes)

if bits == nil and bytes == nil and fill == nil do
raise TypeOptionError, message: "You must specify a size (bytes/bits/fill) for a padding"
raise TypeOptionError, "you must specify a size (bytes/bits/fill) for a padding"
end

case {fill, bits, bytes} do
Expand Down
2 changes: 1 addition & 1 deletion lib/elven_gard/protocol/binary/string_type.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ defmodule ElvenGard.Protocol.Binary.StringType do
bytes = Keyword.get(opts, :bytes)

if bits == nil and bytes == nil do
raise TypeOptionError, message: "You must specify a size in bytes/bits for a string"
raise TypeOptionError, "you must specify a size in bytes/bits for a string"
end

size = if bits != nil, do: Kernel.trunc(bits / 8), else: bytes
Expand Down
8 changes: 4 additions & 4 deletions lib/elven_gard/protocol/textual.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defmodule ElvenGard.Protocol.Textual do
TODO: Documentation for ElvenGard.Protocol.Textual
"""

alias ElvenGard.FieldTypeError
alias ElvenGard.Structures.{Client, PacketDefinition}

@aliases [
Expand All @@ -14,7 +15,7 @@ defmodule ElvenGard.Protocol.Textual do
@doc false
defmacro __using__(model: model, separator: separator) do
expanded_model = Macro.expand(model, __CALLER__)
defs = expanded_model.fetch_definitions()
defs = expanded_model.get_packet_definitions()

check_types!(defs)

Expand Down Expand Up @@ -43,7 +44,7 @@ defmodule ElvenGard.Protocol.Textual do
defp pre_textual_decode(x) when is_list(x), do: Enum.map(x, &textual_decode/1)

## Define sub decoders
Enum.each(unquote(model).fetch_definitions(), fn packet ->
Enum.each(unquote(model).get_packet_definitions(), fn packet ->
name = packet.name
fields = Macro.escape(packet.fields)
sep = unquote(separator) |> Macro.escape()
Expand Down Expand Up @@ -112,8 +113,7 @@ defmodule ElvenGard.Protocol.Textual do
@spec check_type!(atom, atom, term) :: term
defp check_type!(type, name, def_name) do
unless Keyword.has_key?(type.__info__(:functions), :decode) do
raise "Invalid type '#{inspect(type)}' for '#{inspect(name)}' " <>
"for packet '#{inspect(def_name)}'"
raise FieldTypeError, field_type: type, field_name: name, packet_name: def_name
end
end
end
6 changes: 4 additions & 2 deletions lib/elven_gard/structures/client.ex
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
defmodule ElvenGard.Structures.Client do
@moduledoc """
Manage a socket.
Manage a socket
You can store some metadata on this structure.
"""

@keys [:id, :socket, :transport, :metadata]
@enforce_keys @keys
defstruct @keys ++ [protocol: nil]

defstruct @keys ++ [:protocol]

@type t :: %__MODULE__{}
@type metadata_key :: [term, ...] | term
Expand Down
1 change: 1 addition & 0 deletions lib/elven_gard/structures/field_definition.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ defmodule ElvenGard.Structures.FieldDefinition do

@keys [:name, :type, :description, :opts]
@enforce_keys @keys

defstruct @keys

@type t :: %__MODULE__{}
Expand Down
5 changes: 3 additions & 2 deletions lib/elven_gard/structures/packet_definition.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ defmodule ElvenGard.Structures.PacketDefinition do
Structure for a packet's definition
"""

alias ElvenGard.Structures.FieldDefinition

@keys [:name, :description, :fields, :tags]
@enforce_keys @keys
defstruct @keys

alias ElvenGard.Structures.FieldDefinition
defstruct @keys

@type t :: %__MODULE__{}
@type empty_string :: String.t() | nil
Expand Down
2 changes: 1 addition & 1 deletion lib/elven_gard/type.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ defmodule ElvenGard.Type do
@callback encode(decoded_term, opts :: list) :: term

@doc """
Transforms a packet received by a client into a term that can be used by `ElvenGard.Protocol`
Transforms a packet received by a client into a term that can be used by a protocol
NOTE: The result of this function will then be used by `c:ElvenGard.Protocol.decode/1`
"""
Expand Down
5 changes: 3 additions & 2 deletions lib/elven_gard/view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@ defmodule ElvenGard.View do

alias ElvenGard.UnknownViewError

@anno if :erlang.system_info(:otp_release) >= '19', do: [generated: true], else: [line: -1]

@doc """
Build a packet to send to the client
"""
@callback render(type :: atom, opts :: map) :: term

@anno if :erlang.system_info(:otp_release) >= '19', do: [generated: true], else: [line: -1]

@doc false
defmacro __using__(_) do
parent = __MODULE__

quote do
@behaviour unquote(parent)

@before_compile unquote(parent)
end
end
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ defmodule ElvenGard.MixProject do
end

defp extras() do
["README.md": [title: "Overview"]] ++ Path.wildcard("guides/**/*.md")
["README.md": [title: "Project Description"]] ++ Path.wildcard("guides/**/*.md")
end

defp groups_for_extras() do
Expand Down
Loading

0 comments on commit 12b3cb9

Please sign in to comment.