Initial commit with halfway working data structure

parents
# The directory Mix will write compiled artifacts to.
/_build
# If you run "mix test --cover", coverage assets end up here.
/cover
# The directory Mix downloads your dependencies sources to.
/deps
# Where 3rd-party dependencies like ExDoc output generated docs.
/doc
# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch
# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez
# GrainsEngine
**TODO: Add description**
## Installation
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `grains_engine` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[{:grains_engine, "~> 0.1.0"}]
end
```
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at [https://hexdocs.pm/grains_engine](https://hexdocs.pm/grains_engine).
# 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 :grains_engine, key: :value
#
# And access this configuration in your application as:
#
# Application.get_env(:grains_engine, :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"
defmodule GrainsEngine.Grain do
alias GrainsEngine.Parameter
def start_link(param_names) when is_list param_names do
Agent.start_link(fn -> initialize_paramters(param_names) end)
end
defp initialize_paramters(names) do
Enum.reduce(names, %{}, fn(name, grain) ->
key = String.to_atom(name)
{:ok, parameter } = Parameter.start_link(key)
Map.put_new(grain, key, parameter)
end)
end
def get_value(grain, key) when is_atom key do
parameter = Agent.get(grain, fn grain -> grain[key] end)
Parameter.value(parameter)
end
def set_value(grain, key, value) when is_atom key do
parameter = Agent.get(grain, fn grain -> grain[key] end)
Parameter.set_value(parameter, value)
end
def to_string(grain) do
grain_string =
Agent.get(grain, fn state -> state end)
|> Enum.reduce("", fn {k,v}, acc -> "#{acc}, #{k}" end )
"{" <> String.replace_leading(grain_string, ", ", "") <> "}"
end
end
defmodule GrainsEngine do
@moduledoc """
Documentation for GrainsEngine.
"""
@doc """
Hello world.
## Examples
iex> GrainsEngine.hello
:world
"""
def hello do
:world
end
end
defmodule GrainsEngine.Application do
# See http://elixir-lang.org/docs/stable/elixir/Application.html
# for more information on OTP Applications
@moduledoc false
use Application
def start(_type, _args) do
import Supervisor.Spec, warn: false
# Define workers and child supervisors to be supervised
children = [
# Starts a worker by calling: GrainsEngine.Worker.start_link(arg1, arg2, arg3)
# worker(GrainsEngine.Worker, [arg1, arg2, arg3]),
]
# See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: GrainsEngine.Supervisor]
Supervisor.start_link(children, opts)
end
end
defmodule GrainsEngine.Parameter do
defstruct name: :none, value: :none
alias GrainsEngine.Parameter
def start_link(name \\ :none) do
Agent.start_link(fn -> %Parameter{name: name, value: :none} end)
end
def name(parameter) do
Agent.get(parameter, fn state -> state.name end)
end
def value(parameter) do
Agent.get(parameter, fn state -> state.value end)
end
def set?(parameter) do
case Agent.get(parameter, fn state -> state.name end) do
:none -> false
_ -> true
end
end
def set_value(parameter, value) when is_number value do
Agent.update(parameter, fn state -> Map.put(state, :value, value) end)
end
def set_name(parameter, name) do
Agent.update(parameter, fn state -> Map.put(state, :name, name) end)
end
def to_string(parameter) do
"(name:#{name(parameter)}: #{value(parameter)})"
end
end
defmodule GrainsEngine.Performance do
use GenServer
defstruct player: :none
alias GrainsEngine.Performance
alias GrainsEngine.Player
def start_link(name) when is_binary(name) and byte_size(name) > 0 do
GenServer.start_link(__MODULE__, name, name: {:global, "perf:#{name}"})
end
def stop(pid) do
GenServer.cast(pid, :stop)
end
def init(name) do
{:ok, player} = Player.start_link(name)
Player.set_name(player, name)
{:ok, %Performance{player: player}}
end
def handle_cast(:stop, state) do
{:stop, :normal, state}
end
def handle_call(:demo, _from, state) do
{:reply, state, state}
end
def call_demo(pid) do
GenServer.call(pid, :demo)
end
end
defmodule GrainsEngine.Player do
alias GrainsEngine.{Player, Grain, Parameter}
defstruct name: :none, grain: :none
def start_link(name \\ :none) do
{:ok, grain} = Grain.start_link
Agent.start_link(fn -> %Player{name: name,
grain: grain} end)
end
def set_name(player, name) do
Agent.update(player, fn state -> Map.put(state, :name, name) end)
end
def set_grain(player, grain) do
Agent.update(player, fn state -> Map.put(state, :grain, grain) end)
end
def grain(player) do
Agent.get(player, fn state -> state.grain end)
end
def set_params(player, names) when is_list(names) do
params = Enum.map(names, fn name ->
{:ok, param} = Parameter.start_link(name)
param
end)
Agent.update(player, fn state ->
Grain.replace_parameters(state.grain, params)
state
end)
end
def to_string(player) do
"%Player{" <> string_body(player) <> "}"
end
def string_body(player) do
state = Agent.get(player, &(&1))
":name => " <> name_to_string(state.name) <> ",\n" <>
":grain => " <> Grain.to_string(state.grain)
end
defp name_to_string(:none) , do: "none"
defp name_to_string(name), do: name
end
defmodule GrainsEngine.Mixfile do
use Mix.Project
def project do
[app: :grains_engine,
version: "0.1.0",
elixir: "~> 1.4",
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
# Specify extra applications you'll use from Erlang/Elixir
[extra_applications: [:logger],
mod: {GrainsEngine.Application, []}]
end
# Dependencies can be Hex packages:
#
# {:my_dep, "~> 0.3.0"}
#
# Or git/path repositories:
#
# {:my_dep, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
#
# Type "mix help deps" for more examples and options
defp deps do
[]
end
end
defmodule GrainTest do
use ExUnit.Case, async: true
doctest GrainsEngine.Grain
alias GrainsEngine.Grain
describe "populated Grain" do
setup do
{:ok, grain} = Grain.start_link(["foo", "bar"])
{:ok, grain: grain}
end
test "represents string", %{grain: grain} do
assert Grain.to_string(grain) == "{bar, foo}"
end
test "retrieve parameter", %{grain: grain} do
assert Grain.get_value(grain, :foo) == :none
end
test "set parameter", %{grain: grain} do
assert Grain.get_value(grain, :foo) == :none
Grain.set_value(grain, :foo, 63)
assert Grain.get_value(grain, :foo) == 63
end
end
describe "empty Grain" do
setup do
{:ok, grain} = Grain.start_link([])
{:ok, grain: grain}
end
test "represents string", %{grain: grain} do
assert Grain.to_string(grain) == "{}"
end
end
test "the truth" do
assert 1 + 1 == 2
end
end
defmodule GrainsEngineTest do
use ExUnit.Case
doctest GrainsEngine
test "the truth" do
assert 1 + 1 == 2
end
end
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment