Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/fishcakez/core
Library for selective receive OTP processes
https://github.com/fishcakez/core
Last synced: 29 days ago
JSON representation
Library for selective receive OTP processes
- Host: GitHub
- URL: https://github.com/fishcakez/core
- Owner: fishcakez
- License: apache-2.0
- Created: 2014-03-24T17:51:11.000Z (over 10 years ago)
- Default Branch: master
- Last Pushed: 2014-09-14T21:55:50.000Z (about 10 years ago)
- Last Synced: 2024-11-01T08:34:06.522Z (about 1 month ago)
- Language: Elixir
- Homepage:
- Size: 429 KB
- Stars: 44
- Watchers: 2
- Forks: 5
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- freaking_awesome_elixir - Elixir - Library for selective receive OTP processes. (OTP)
- fucking-awesome-elixir - core - Library for selective receive OTP processes. (OTP)
- awesome-elixir - core - Library for selective receive OTP processes. (OTP)
README
# Core
Library for implementing OTP processes natively in Elixir.Provides utility functions and macros to implement 100% OTP compliant
processes with 100% compatibility with all Erlang/OTP modules and tools.# Installing
```
git clone https://github.com/fishcakez/core.git
cd core
mix do deps.get, docs, compile
```# Hello World
Start a process that prints "Hello World" to `:stdio`.
```elixir
defmodule HelloWorld douse Core
def start_link(), do: Core.start_link(__MODULE__, nil)
def init(_parent, _debug, _args) do
IO.puts("Hello World")
# Core.init_ack/0 will cause start_link/0 to return { :ok, self() }. If this
# function is never called start_link will block until this process exits.
Core.init_ack()
exit(:normal)
endend
```# Features
* Asynchronous and synchronous process initiation (with name registration).
* Automatic logging of un-rescued exceptions.
* System calls that work with any OTP compliant process.
* Receive macro to handle system messages.
* Supports progressive enhancement of OTP features: system message
automatically handled until you want to change the default behaviour.# Basic Ping Server
Starts a process that can be pinged.
```elixir
defmodule PingPong douse Core
@spec ping(Core.t) :: :pong
def ping(process), do: Core.call(process, __MODULE__, :ping, 5000)@spec count(Core.t) :: non_neg_integer
def count(process), do: Core.call(process, __MODULE__, :count, 5000)@spec close(Core.t) :: :ok
def close(process), do: Core.call(process, __MODULE__, :close, 5000)@spec start_link() :: { :ok, pid }
def start_link() do
Core.start_link(__MODULE__, nil)
end# Core api
def init(_parent, _debug, _args) do
Core.init_ack()
loop(0)
end## Internal
defp loop(count) do
receive do
{ __MODULE__, from, :ping } ->
Core.reply(from, :pong)
loop(count + 1)
{ __MODULE__, from, :count } ->
Core.reply(from, count)
loop(count)
{ __MODULE__, from, :close } ->
Core.reply(from, :ok)
terminate(:normal)
end
enddefp terminate(reason) do
exit(reason)
endend
```# Advanced Ping Server
Starts a process that can be pinged, live debugged and live code
upgraded.For example `Core.Sys.set_state(pid, 0)` will reset the `count` to `0`.
```elixirdefmodule PingPong do
use Core.Sys
@spec ping(Core.t) :: :pong
def ping(process), do: Core.call(process, __MODULE__, :ping, 5000)@spec count(Core.t) :: non_neg_integer
def count(process), do: Core.call(process, __MODULE__, :count, 5000)@spec close(Core.t) :: :ok
def close(process), do: Core.call(process, __MODULE__, :close, 5000)# die/1 will print alot of information because the exit reason is abnormal.
@spec die(Core.t) :: :ok
def die(process), do: Core.call(process, __MODULE__, :die, 5000)@spec start_link() :: { :ok, pid }
def start_link() do
Core.start_link(nil, __MODULE__, nil,
[{ :debug, [{ :log, 10 }, { :stats, true }] }])
end## Core api
def init(parent, debug, _args) do
Core.init_ack()
loop(0, parent, debug)
end## Core.Sys (minimal) api
def system_continue(count, parent, debug), do: loop(count, parent, debug)
def system_terminate(count, parent, debug, reason) do
terminate(count, parent, debug, reason)
end## Internal
defp loop(count, parent, debug) do
Core.Sys.receive(__MODULE__, count, parent, debug) do
{ __MODULE__, from, :ping } ->
# It is not required to record events using `Core.Debug.event/1` but is
# a useful debug feature that is compiled to a no-op in production.
debug = Core.Debug.event(debug, { :in, :ping, elem(from, 0) })
Core.reply(from, :pong)
debug = Core.Debug.event(debug, { :out, :pong, elem(from, 0) })
count = count + 1
debug = Core.Debug.event(debug, { :count, count })
loop(count, parent, debug)
{ __MODULE__, from, :count } ->
debug = Core.Debug.event(debug, { :in, :count, elem(from, 0) })
Core.reply(from, count)
debug = Core.Debug.event(debug, { :out, count, elem(from, 0) })
loop(count, parent, debug)
{ __MODULE__, from, :close } ->
debug = Core.Debug.event(debug, { :in, :close, elem(from, 0) })
Core.reply(from, :ok)
debug = Core.Debug.event(debug, { :out, :ok, elem(from, 0) })
terminate(count, parent, debug, :normal)
{ __MODULE__, from, :die } ->
debug = Core.Debug.event(debug, { :in, :die, elem(from, 0) })
Core.reply(from, :ok)
debug = Core.Debug.event(debug, { :out, :ok, elem(from, 0) })
terminate(count, parent, debug, :die)
end
enddefp terminate(count, parent, debug, reason) do
event = { :EXIT, reason }
debug = Core.Debug.event(debug, event)
Core.stop(__MODULE__, count, parent, debug, reason, event)
endend
```