Skip to content

Commit

Permalink
added data model for nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
mrkaspa committed Mar 4, 2016
0 parents commit d68bef5
Show file tree
Hide file tree
Showing 9 changed files with 254 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/_build
/cover
/deps
erl_crash.dump
*.ez
*.beam
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Exstreme

**TODO: Add description**

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed as:

1. Add exstreme to your list of dependencies in `mix.exs`:

def deps do
[{:exstreme, "~> 0.0.1"}]
end

2. Ensure exstreme is started before your application:

def application do
[applications: [:exstreme]]
end

30 changes: 30 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This file is responsible for configuring your application
# and its dependencies with the aid of the Mix.Config module.
use Mix.Config

# This configuration is loaded before any dependency and is restricted
# to this project. If another project depends on this project, this
# file won't be loaded nor affect the parent project. For this reason,
# if you want to provide default values for your application for
# 3rd-party users, it should be done in your "mix.exs" file.

# You can configure for your application as:
#
# config :exstreme, key: :value
#
# And access this configuration in your application as:
#
# Application.get_env(:exstreme, :key)
#
# Or configure a 3rd-party app:
#
# config :logger, level: :info
#

# It is also possible to import configuration files, relative to this
# directory. For example, you can emulate configuration per environment
# by uncommenting the line below and defining dev.exs, test.exs and such.
# Configuration from the imported file will override the ones defined
# here (which is why it is important to import them last).
#
# import_config "#{Mix.env}.exs"
2 changes: 2 additions & 0 deletions lib/exstreme.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
defmodule Exstreme do
end
96 changes: 96 additions & 0 deletions lib/exstreme/stream_graph.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
defmodule Exstreme.StreamGraph do
@moduledoc """
"""
defmodule Graph do
defstruct params: [], nodes: %{}, connections: []
end

@doc """
"""
def create_graph(params \\ []), do: %Graph{params: params}

@doc """
"""
def create_node(graph = %Graph{nodes: nodes}, params \\ []) do
key = next_node_key(nodes)
new_graph = update_in(graph.nodes, &(Map.put(&1, key, params)))
{new_graph, key}
end

@doc """
"""
def add_connection(graph = %Graph{nodes: nodes}, start, finish) when start != finish do
if Map.has_key?(nodes, start) and Map.has_key?(nodes, finish) do
update_in(graph.connections, store_connection_fn(start, finish))
else
raise ArgumentError, message: "nodes not found"
end
end

#private

defp store_connection_fn(start, finish) do
fn(connections) ->
connections
|> validate_repeated(start, finish)
|> validate_repeated(finish, start)
|> validate_position(start, :start)
|> validate_position(finish, :end)
|> Keyword.put(start, finish)
end
end

def validate_repeated(connections, start, finish) do
if connections |> Enum.any?(&(&1 == {start, finish})) do
raise ArgumentError, message: "there is already a connection like that"
else
connections
end
end

defp validate_position(connections, node, position) do
case node|> Atom.to_string |> String.first do
"n" -> validate_position_node(connections, node, position)
# "b" ->
# "f" ->
_ -> raise ArgumentError, message: "invalid node"
end
end

defp validate_position_node(connections, node, :start) do
exist =
connections
|> Keyword.has_key?(node)
if exist do
raise ArgumentError, message: "the node can't be twice at start position"
else
connections
end
end

defp validate_position_node(connections, node, :end) do
exist =
connections
|> Keyword.values
|> Enum.member?(node)
if exist do
raise ArgumentError, message: "the node can't be twice at end position"
else
connections
end
end

defp next_node_key(nodes) do
next_key(nodes, "n")
end

defp next_key(map, letter) do
count =
map
|> Map.keys
|> Enum.map(&Atom.to_string/1)
|> Enum.filter(fn(str) -> String.starts_with?(str, letter) end)
|> Enum.count
String.to_atom("#{letter}#{count + 1}")
end
end
32 changes: 32 additions & 0 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
defmodule Exstreme.Mixfile do
use Mix.Project

def project do
[app: :exstreme,
version: "0.0.1",
elixir: "~> 1.2",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
deps: deps]
end

# Configuration for the OTP application
#
# Type "mix help compile.app" for more information
def application do
[applications: [:logger]]
end

# Dependencies can be Hex packages:
#
# {:mydep, "~> 0.3.0"}
#
# Or git/path repositories:
#
# {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"}
#
# Type "mix help deps" for more examples and options
defp deps do
[]
end
end
59 changes: 59 additions & 0 deletions test/exstreme/stream_graph_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
defmodule Exstreme.StreamGraphTest do
use ExUnit.Case
alias Exstreme.StreamGraph
alias Exstreme.StreamGraph.Graph
doctest Exstreme.StreamGraph

def params, do: []

def create_graph do
graph = StreamGraph.create_graph(params)

{graph, n1} = graph |> StreamGraph.create_node(params)
{graph, n2} = graph |> StreamGraph.create_node(params)

graph
|> StreamGraph.add_connection(n1, n2)
end

test "creates a valid graph struct" do
graph = %Graph{
nodes: %{n1: [], n2: []},
connections: [{:n1, :n2}]
}
assert create_graph == graph
end

test "throws an error when adding again the relation" do
assert_raise ArgumentError, fn ->
create_graph
|> StreamGraph.add_connection(:n1, :n2)
end
end

test "throws an error when adding again a self relation" do
assert_raise FunctionClauseError, fn ->
create_graph
|> StreamGraph.add_connection(:n1, :n1)
end
end

test "throws an error when adding a cicle relation" do
assert_raise ArgumentError, "there is already a connection like that", fn ->
create_graph
|> StreamGraph.add_connection(:n2, :n1)
end
end

test "can create n3 and add a relatio between n2 and n3" do
graph = %Graph{
nodes: %{n1: [], n2: []},
connections: [{:n1, :n2}]
}

{new_graph, _} = create_graph |> StreamGraph.create_node(params)
new_graph =
new_graph
|> StreamGraph.add_connection(:n2, :n3)
end
end
8 changes: 8 additions & 0 deletions test/exstreme_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
defmodule ExstremeTest do
use ExUnit.Case
doctest Exstreme

test "the truth" do
assert 1 + 1 == 2
end
end
1 change: 1 addition & 0 deletions test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ExUnit.start()

0 comments on commit d68bef5

Please sign in to comment.