Skip to content

Commit

Permalink
code improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
mrkaspa committed Jul 7, 2016
1 parent 6c73ad3 commit 8d64ab7
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 80 deletions.
7 changes: 4 additions & 3 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ x- Named nodes with graph name
x- Add documentation
x- Use nid to connect
X- Get nid for a node
- A node must have a function
- The function in Broadcast and Funnel nodes can be optional
X- A node must have a function
X- The function in Broadcast and Funnel nodes can be optional
- Add Supervisors functionality
- Use counters for stats
x- Improve test
- Improve API

Future
- Improve API
- Update to GenStage
60 changes: 33 additions & 27 deletions lib/exstreme/graph.ex
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ defmodule Exstreme.Graph do
end

@doc """
Gets the starting node
Gets the starting gnode
"""
@spec find_start_node(t) :: [atom]
def find_start_node(%Graph{nodes: nodes, connections: connections}) do
is_first? =
fn(node) ->
at_first?(connections, node) and not(at_last?(connections, node))
fn(gnode) ->
at_first?(connections, gnode) and not(at_last?(connections, gnode))
end

nodes
Expand All @@ -64,8 +64,8 @@ defmodule Exstreme.Graph do
@spec find_last_node(t) :: [atom]
def find_last_node(%Graph{nodes: nodes, connections: connections}) do
is_last? =
fn(node) ->
not(at_first?(connections, node)) and at_last?(connections, node)
fn(gnode) ->
not(at_first?(connections, gnode)) and at_last?(connections, gnode)
end

nodes
Expand All @@ -77,37 +77,43 @@ defmodule Exstreme.Graph do
Gets the nodes before the current one
"""
@spec get_before_nodes(t, atom) :: [atom]
def get_before_nodes(%Graph{connections: connections}, node) do
def get_before_nodes(%Graph{connections: connections}, gnode) do
compare_func =
fn(current_node, {from, to}) ->
{current_node == to, from}
end
Enum.reduce(connections, [], fn(connection, res) ->
List.flatten(get_nodes_func(node, connection, res, compare_func), res)
end) |> Enum.uniq

connections
|> Enum.reduce([], fn(connection, res) ->
List.flatten(get_nodes_func(gnode, connection, res, compare_func), res)
end)
|> Enum.uniq
end

@doc """
Gets the nodes after the current one
"""
@spec get_after_nodes(t, atom) :: [atom]
def get_after_nodes(%Graph{connections: connections}, node) do
def get_after_nodes(%Graph{connections: connections}, gnode) do
compare_func =
fn(current_node, {from, to}) ->
{current_node == from, to}
end
Enum.reduce(connections, [], fn(connection, res) ->
res ++ get_nodes_func(node, connection, res, compare_func)
end) |> Enum.uniq

connections
|> Enum.reduce([], fn(connection, res) ->
res ++ get_nodes_func(gnode, connection, res, compare_func)
end)
|> Enum.uniq
end

@doc """
Gets the name in the Graph for one node
Gets the name in the Graph for one gnode
"""
@spec nid(t, atom) :: atom
def nid(%Graph{name: name}, node) do
def nid(%Graph{name: name}, gnode) do
[char, rest] =
node
gnode
|> Atom.to_string
|> String.codepoints
String.to_atom("#{char}_#{name}_#{rest}")
Expand All @@ -119,8 +125,8 @@ defmodule Exstreme.Graph do
@spec map_to_connections(t) :: [atom]
defp map_to_connections(%Graph{nodes: nodes, connections: connections}) do
to_connections =
fn(node) ->
case {at_first?(connections, node), at_last?(connections, node)} do
fn(gnode) ->
case {at_first?(connections, gnode), at_last?(connections, gnode)} do
{true, true} -> :connected
{true, false} -> :begin
{false, true} -> :end
Expand All @@ -133,34 +139,34 @@ defmodule Exstreme.Graph do
|> Enum.map(to_connections)
end

# Checks if a node is the first position of a connection
# Checks if a gnode is the first position of a connection
@spec at_first?(%{key: atom}, atom) :: boolean
defp at_first?(connections, node) do
Map.has_key?(connections, node)
defp at_first?(connections, gnode) do
Map.has_key?(connections, gnode)
end

# Checks if a node is the last position of a connection
# Checks if a gnode is the last position of a connection
@spec at_last?(%{key: atom}, atom) :: boolean
defp at_last?(connections, node) do
defp at_last?(connections, gnode) do
connections
|> Map.values
|> List.flatten
|> Enum.member?(node)
|> Enum.member?(gnode)
end

@spec get_nodes_func(atom, {atom, atom}, [atom], ((atom, {atom, atom}) -> boolean)) :: [atom]
defp get_nodes_func(node, {from, to} = pair, res, func) do
defp get_nodes_func(gnode, {from, to} = pair, res, func) do
case to do
to when is_atom(to) ->
{ok, add_node} = func.(node, pair)
{ok, add_node} = func.(gnode, pair)
if ok do
[add_node | res]
else
res
end
to when is_list(to) ->
Enum.reduce(to, res, fn(current_to, new_res) ->
List.flatten(get_nodes_func(node, {from, current_to}, new_res, func), new_res)
List.flatten(get_nodes_func(gnode, {from, current_to}, new_res, func), new_res)
end)
end
end
Expand Down
19 changes: 10 additions & 9 deletions lib/exstreme/graph_builder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ defmodule Exstreme.GraphBuilder do
@spec update_nodes_relations(Graph.t) :: Graph.t
defp update_nodes_relations(graph) do
update_node_func =
fn({node, params}) ->
fn({gnode, params}) ->
new_params =
params
|> Keyword.put(:before_nodes, Graph.get_before_nodes(graph, node))
|> Keyword.put(:after_nodes, Graph.get_after_nodes(graph, node))
|> Keyword.put(:before_nodes, Graph.get_before_nodes(graph, gnode))
|> Keyword.put(:after_nodes, Graph.get_after_nodes(graph, gnode))

{node, new_params}
{gnode, new_params}
end

update_in(graph.nodes, &(&1 |> Enum.map(update_node_func) |> Map.new))
Expand All @@ -49,21 +49,21 @@ defmodule Exstreme.GraphBuilder do
end)
end

# Starts a node
# Starts a gnode
@spec start_node({atom, [term: any]}) :: {atom, [key: any]}
defp start_node({node, params}) do
defp start_node({gnode, params}) do
type = Keyword.get(params, :type)
params =
params
|> Keyword.put(:nid, node)
|> Keyword.put(:nid, gnode)
|> Keyword.put_new(:func, fn(data, _) -> {:ok, data} end)
{:ok, _} =
case type do
:broadcast -> Broadcast.start_link(params)
:funnel -> Funnel.start_link(params)
_ -> Common.start_link(params)
end
{node, params}
{gnode, params}
end

# Connects all nodes
Expand All @@ -76,7 +76,8 @@ defmodule Exstreme.GraphBuilder do
# Connects two nodes
@spec connect_pair({atom, [atom]}, %{key: [key: term]}) :: no_return
defp connect_pair({from, to}, nodes) when is_list(to) do
Enum.map(1..Enum.count(to), fn(_) -> from end)
1..Enum.count(to)
|> Enum.map(fn(_) -> from end)
|> Enum.zip(to)
|> Enum.each(&(connect_pair(&1, nodes)))
end
Expand Down
69 changes: 35 additions & 34 deletions lib/exstreme/graph_creator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ defmodule Exstreme.GraphCreator do
@spec create_graph([key: term]) :: Graph.t
def create_graph(params) do
name =
:crypto.strong_rand_bytes(@default_length_name)
@default_length_name
|> :crypto.strong_rand_bytes
|> Base.url_encode64
|> binary_part(0, @default_length_name)
create_graph(name, params)
Expand All @@ -30,7 +31,7 @@ defmodule Exstreme.GraphCreator do
def create_graph(name, params), do: %Graph{name: name, params: params}

@doc """
Creates a simple node
Creates a simple gnode
"""
@spec create_node(Graph.t, [key: term]) :: {Graph.t, atom}
def create_node(graph = %Graph{nodes: nodes}, params \\ []) do
Expand All @@ -41,7 +42,7 @@ defmodule Exstreme.GraphCreator do
end

@doc """
Creates a broadcast node
Creates a broadcast gnode
"""
@spec create_broadcast(Graph.t, [key: term]) :: {Graph.t, atom}
def create_broadcast(graph = %Graph{nodes: nodes}, params \\ []) do
Expand All @@ -52,7 +53,7 @@ defmodule Exstreme.GraphCreator do
end

@doc """
Creates a funnel node
Creates a funnel gnode
"""
@spec create_funnel(Graph.t, [key: term]) :: {Graph.t, atom}
def create_funnel(graph = %Graph{nodes: nodes}, params \\ []) do
Expand All @@ -72,7 +73,7 @@ defmodule Exstreme.GraphCreator do
update_in(graph.connections, store_connection_fn(start, finish))
end
else
raise ArgumentError, message: "You can't connect to the same node"
raise ArgumentError, message: "You can't connect to the same gnode"
end
end

Expand Down Expand Up @@ -101,7 +102,7 @@ defmodule Exstreme.GraphCreator do
end
end

# validations before adding a node
# validations before adding a gnode

# Validates when a relation already exists
@spec validate_repeated(%{key: atom}, atom, atom) :: %{key: atom}
Expand All @@ -120,52 +121,52 @@ defmodule Exstreme.GraphCreator do
end
end

# Validates the node position
# Validates the gnode position
@spec validate_position(%{key: atom}, atom, :start | :end) :: %{key: atom}
defp validate_position(connections, node, position) do
case node |> Atom.to_string |> String.first do
"n" -> validate_position_node(connections, node, position)
"b" -> validate_position_broadcast(connections, node, position)
"f" -> validate_position_funnel(connections, node, position)
_ -> raise ArgumentError, message: "invalid node"
defp validate_position(connections, gnode, position) do
case gnode |> Atom.to_string |> String.first do
"n" -> validate_position_node(connections, gnode, position)
"b" -> validate_position_broadcast(connections, gnode, position)
"f" -> validate_position_funnel(connections, gnode, position)
_ -> raise ArgumentError, message: "invalid gnode"
end
end

# Validates if a normal node can be at the beginning of the relation
# Validates if a normal gnode can be at the beginning of the relation
@spec validate_position_node(%{key: atom}, atom, :start) :: %{key: atom}
defp validate_position_node(connections, node, :start) do
validate_position_start(connections, node,"the node can't be twice at start position #{node}")
defp validate_position_node(connections, gnode, :start) do
validate_position_start(connections, gnode,"the gnode can't be twice at start position #{gnode}")
end

# Validates if a normal node can be at the end of the relation
# Validates if a normal gnode can be at the end of the relation
@spec validate_position_node(%{key: atom}, atom, :end) :: %{key: atom}
defp validate_position_node(connections, node, :end) do
validate_position_end(connections, node,"the node can't be twice at end position")
defp validate_position_node(connections, gnode, :end) do
validate_position_end(connections, gnode,"the gnode can't be twice at end position")
end

# Validates if a broadcast node can be at the beginning of the relation
# Validates if a broadcast gnode can be at the beginning of the relation
@spec validate_position_broadcast(%{key: atom}, atom, :start) :: %{key: atom}
defp validate_position_broadcast(connections, _node, :start), do: connections

# Validates if a broadcast node can be at the end of the relation
# Validates if a broadcast gnode can be at the end of the relation
@spec validate_position_broadcast(%{key: atom}, atom, :end) :: %{key: atom}
defp validate_position_broadcast(connections, bct, :end) do
validate_position_end(connections, bct, "the broadcast can't be twice at end position")
end

# Validates if a funnel node can be at the beginning of the relation
# Validates if a funnel gnode can be at the beginning of the relation
@spec validate_position_funnel(%{key: atom}, atom, :start) :: %{key: atom}
defp validate_position_funnel(connections, node, :start) do
validate_position_start(connections, node,"the funnel can't be twice at start position #{node}")
defp validate_position_funnel(connections, gnode, :start) do
validate_position_start(connections, gnode,"the funnel can't be twice at start position #{gnode}")
end

# Validates if a funnel node can be at the normal of the relation
# Validates if a funnel gnode can be at the normal of the relation
@spec validate_position_funnel(%{key: atom}, atom, :end) :: %{key: atom}
defp validate_position_funnel(connections, _node, :end), do: connections

@spec validate_position_start(%{key: atom}, atom, String.t) :: %{key: atom}
defp validate_position_start(connections, node, msg) do
exist = Map.has_key?(connections, node)
defp validate_position_start(connections, gnode, msg) do
exist = Map.has_key?(connections, gnode)
if exist do
raise ArgumentError, message: msg
else
Expand All @@ -174,29 +175,29 @@ defmodule Exstreme.GraphCreator do
end

@spec validate_position_end(%{key: atom}, atom, String.t) :: %{key: atom}
defp validate_position_end(connections, node, msg) do
defp validate_position_end(connections, gnode, msg) do
exist =
connections
|> Map.values
|> Enum.member?(node)
|> Enum.member?(gnode)
if exist do
raise ArgumentError, message: msg
else
connections
end
end

# Validates the node exist on the graph
# Validates the gnode exist on the graph
@spec validate_node_exist(%{key: [key: term]}, atom) :: true
defp validate_node_exist(nodes, node) do
if Map.has_key?(nodes, node) do
defp validate_node_exist(nodes, gnode) do
if Map.has_key?(nodes, gnode) do
true
else
raise ArgumentError, message: "node #{node} not found"
raise ArgumentError, message: "gnode #{gnode} not found"
end
end

# Gets the next key for the node, these begin with the 'n' letter
# Gets the next key for the gnode, these begin with the 'n' letter
@spec next_node_key(Graph.t, %{key: atom}) :: atom
defp next_node_key(graph, nodes) do
next_key(graph, nodes, "n")
Expand Down
3 changes: 2 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ defmodule Exstreme.Mixfile do
# Type "mix help deps" for more examples and options
defp deps do
[
{:dialyxir, "~> 0.3", only: [:dev]}
{:dialyxir, "~> 0.3", only: [:dev]},
{:credo, "~> 0.4", only: [:dev, :test]}
]
end
end
4 changes: 3 additions & 1 deletion mix.lock
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
%{"dialyxir": {:hex, :dialyxir, "0.3.3", "2f8bb8ab4e17acf4086cae847bd385c0f89296d3e3448dc304c26bfbe4b46cb4", [:mix], []}}
%{"bunt": {:hex, :bunt, "0.1.6", "5d95a6882f73f3b9969fdfd1953798046664e6f77ec4e486e6fafc7caad97c6f", [:mix], []},
"credo": {:hex, :credo, "0.4.5", "5c5daaf50a2a96068c0f21b6fbd382d206702efa8836a946eeab0b8ac25f5f22", [:mix], [{:bunt, "~> 0.1.6", [hex: :bunt, optional: false]}]},
"dialyxir": {:hex, :dialyxir, "0.3.3", "2f8bb8ab4e17acf4086cae847bd385c0f89296d3e3448dc304c26bfbe4b46cb4", [:mix], []}}
2 changes: 1 addition & 1 deletion test/exstreme/graph_creator_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ defmodule Exstreme.GraphCreatorTest do
end

test "throws an error when adding again a self relation", %{graph: graph, n1: n1} do
assert_raise ArgumentError, "You can't connect to the same node", fn ->
assert_raise ArgumentError, "You can't connect to the same gnode", fn ->
graph
|> GraphCreator.add_connection(n1, n1)
end
Expand Down
Loading

0 comments on commit 8d64ab7

Please sign in to comment.