Skip to content

Commit

Permalink
Merge pull request #47 from otobus/mustafaturan/type_doc_and_arity_en…
Browse files Browse the repository at this point in the history
…hancements

Add public high-level types for each function to prevent misusage of …
  • Loading branch information
Mustafa TURAN authored Aug 5, 2018
2 parents 77811a8 + 88d1c21 commit c07d2a6
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 76 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [1.4.X]

- Add public types to main module to increase type safety and readability
- Remove allowence of passing string on topic registration/deregistration
- Allow passing `event_shadow` to `mark_as_completed/1` and `mark_as_skipped/1`

## [1.3.X]

- Set default transaction to the id
Expand Down
24 changes: 17 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ EventBus.fetch_event_data({topic, id})
listener = MyEventListener
# If your listener has config then pass tuple
listener = {MyEventListener, config}
EventBus.mark_as_completed({listener, :bye_received, id})
EventBus.mark_as_completed({listener, {:bye_received, id}})
> :ok
```

Expand All @@ -246,7 +246,7 @@ EventBus.mark_as_completed({listener, :bye_received, id})
listener = MyEventListener
# If your listener has config then pass tuple
listener = {MyEventListener, config}
EventBus.mark_as_skipped({listener, :bye_received, id})
EventBus.mark_as_skipped({listener, {:bye_received, id}})
> :ok
```

Expand Down Expand Up @@ -362,27 +362,37 @@ defmodule MyEventListener do


# if your listener does not have a config
def handle_cast({:bye_received, id}, state) do
event = EventBus.fetch_event({:bye_received, id})
def handle_cast({:bye_received, id} = event_shadow, state) do
event = EventBus.fetch_event(event_shadow)
# do sth with event

# update the watcher!
# version >= 1.4.0
EventBus.mark_as_completed({__MODULE__, event_shadow})
# all versions
EventBus.mark_as_completed({__MODULE__, :bye_received, id})
...
{:noreply, state}
end

def handle_cast({:hello_received, id}, state) do
def handle_cast({:hello_received, id} = event_shadow, state) do
event = EventBus.fetch_event({:hello_received, id})
# do sth with EventBus.Model.Event

# update the watcher!
# version >= 1.4.0
EventBus.mark_as_completed({__MODULE__, event_shadow})
# all versions
EventBus.mark_as_completed({__MODULE__, :hello_received, id})
...
{:noreply, state}
end

def handle_cast({topic, id}, state) do
def handle_cast({topic, id} = event_shadow, state) do
# version >= 1.4.0
EventBus.mark_as_skipped({__MODULE__, event_shadow})

# all versions
EventBus.mark_as_skipped({__MODULE__, topic, id})
{:noreply, state}
end
Expand Down Expand Up @@ -464,7 +474,7 @@ defmodule MyDataStore do
event = EventBus.fetch_event({topic, id})
# write your logic to save event_data to a persistant store

EventBus.mark_as_completed({__MODULE__, topic, id})
EventBus.mark_as_completed({__MODULE__, {topic, id}})
{:noreply, state}
end
end
Expand Down
108 changes: 80 additions & 28 deletions lib/event_bus.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,55 @@ defmodule EventBus do

alias EventBus.Model.Event

@typedoc "EventBus.Model.Event struct"
@type event :: Event.t()

@typedoc "Event id"
@type event_id :: String.t() | integer()

@typedoc "Tuple of topic name and event id"
@type event_shadow :: {topic(), event_id()}

@typedoc "Event listener/subscriber/consumer"
@type listener :: {listener_without_config() | listener_with_config()}

@typedoc "Listener configuration"
@type listener_config :: any()

@typedoc "List of event listeners/subscribers/consumers"
@type listener_list :: list(listener())

@typedoc "Event listener/subscriber/consumer with config"
@type listener_with_config :: {module(), listener_config()}

@typedoc "Tuple of listener and event reference"
@type listener_with_event_ref ::
listener_with_event_shadow() | listener_with_topic_and_event_id()

@typedoc "Tuple of listener and event shadow"
@type listener_with_event_shadow :: {listener(), event_shadow()}

@typedoc "Tuple of listener, topic and event id"
@type listener_with_topic_and_event_id :: {listener(), topic(), event_id()}

@typedoc "Tuple of listener and list of topic patterns"
@type listener_with_topic_patterns :: {listener(), topic_pattern_list()}

@typedoc "Event listener/subscriber/consumer without config"
@type listener_without_config :: module()

@typedoc "Topic name"
@type topic :: atom()

@typedoc "List of topic names"
@type topic_list :: list(topic())

@typedoc "Regex pattern to match topic name"
@type topic_pattern :: String.t()

@typedoc "List of topic patterns"
@type topic_pattern_list :: list(topic_pattern())

@doc """
Send event to all subscribers(listeners).
Expand All @@ -25,8 +74,8 @@ defmodule EventBus do
:ok
"""
@spec notify(Event.t()) :: :ok
defdelegate notify(topic),
@spec notify(event()) :: :ok
defdelegate notify(event),
to: Notification,
as: :notify

Expand All @@ -39,7 +88,7 @@ defmodule EventBus do
true
"""
@spec topic_exist?(String.t() | atom()) :: boolean()
@spec topic_exist?(topic()) :: boolean()
defdelegate topic_exist?(topic),
to: Topic,
as: :exist?
Expand All @@ -52,7 +101,7 @@ defmodule EventBus do
EventBus.topics()
[:metrics_summed]
"""
@spec topics() :: list(atom())
@spec topics() :: topic_list()
defdelegate topics,
to: Topic,
as: :all
Expand All @@ -66,7 +115,7 @@ defmodule EventBus do
:ok
"""
@spec register_topic(String.t() | atom()) :: :ok
@spec register_topic(topic()) :: :ok
defdelegate register_topic(topic),
to: Topic,
as: :register
Expand All @@ -80,7 +129,7 @@ defmodule EventBus do
:ok
"""
@spec unregister_topic(String.t() | atom()) :: :ok
@spec unregister_topic(topic()) :: :ok
defdelegate unregister_topic(topic),
to: Topic,
as: :unregister
Expand All @@ -99,8 +148,8 @@ defmodule EventBus do
:ok
"""
@spec subscribe(tuple()) :: :ok
defdelegate subscribe(listener_with_topics),
@spec subscribe(listener_with_topic_patterns()) :: :ok
defdelegate subscribe(listener_with_topic_patterns),
to: Subscription,
as: :subscribe

Expand All @@ -114,17 +163,17 @@ defmodule EventBus do
# For configurable listeners you must pass tuple of listener and config
my_config = %{}
EventBus.unsubscribe({{OtherListener, my_config}})
EventBus.unsubscribe({OtherListener, my_config})
:ok
"""
@spec unsubscribe({tuple() | module()}) :: :ok
@spec unsubscribe(listener()) :: :ok
defdelegate unsubscribe(listener),
to: Subscription,
as: :unsubscribe

@doc """
Is given listener subscribed to the bus for the given topics?
Is given listener subscribed to the bus for the given topic patterns?
## Examples
Expand All @@ -141,8 +190,8 @@ defmodule EventBus do
false
"""
@spec subscribed?(tuple()) :: boolean()
defdelegate subscribed?(listener_with_topics),
@spec subscribed?(listener_with_topic_patterns()) :: boolean()
defdelegate subscribed?(listener_with_topic_patterns),
to: Subscription,
as: :subscribed?

Expand All @@ -159,7 +208,7 @@ defmodule EventBus do
[MyEventListener, {OtherListener, %{}}]
"""
@spec subscribers() :: list(any())
@spec subscribers() :: listener_list()
defdelegate subscribers,
to: Subscription,
as: :subscribers
Expand Down Expand Up @@ -190,7 +239,7 @@ defmodule EventBus do
%EventBus.Model.Model{}
"""
@spec fetch_event({atom(), String.t() | integer()}) :: Event.t()
@spec fetch_event(event_shadow()) :: event()
defdelegate fetch_event(event_shadow),
to: Store,
as: :fetch
Expand All @@ -203,7 +252,7 @@ defmodule EventBus do
EventBus.fetch_event_data({:hello_received, "123"})
"""
@spec fetch_event_data({atom(), String.t() | integer()}) :: any()
@spec fetch_event_data(event_shadow()) :: any()
defdelegate fetch_event_data(event_shadow),
to: Store,
as: :fetch_data
Expand All @@ -212,19 +261,23 @@ defmodule EventBus do
Send the event processing completed to the Observation Manager
## Examples
topic = :hello_received
event_id = "124"
event_shadow = {topic, event_id}
EventBus.mark_as_completed({MyEventListener, :hello_received, "123"})
# For regular listeners
EventBus.mark_as_completed({MyEventListener, event_shadow})
# For configurable listeners you must pass tuple of listener and config
my_config = %{}
listener = {OtherListener, my_config}
EventBus.mark_as_completed({listener, :hello_received, "124"})
listener = {OtherListener, my_config}
EventBus.mark_as_completed({listener, event_shadow})
:ok
"""
@spec mark_as_completed({tuple() | module(), atom(), String.t() | integer()}) ::
no_return()
defdelegate mark_as_completed(listener_with_event_shadow),
@spec mark_as_completed(listener_with_event_ref()) :: no_return()
defdelegate mark_as_completed(listener_with_event_ref),
to: Observation,
as: :mark_as_completed

Expand All @@ -233,18 +286,17 @@ defmodule EventBus do
## Examples
EventBus.mark_as_skipped({MyEventListener, :unmatched_occurred, "124"})
EventBus.mark_as_skipped({MyEventListener, {:unmatched_occurred, "124"}})
# For configurable listeners you must pass tuple of listener and config
my_config = %{}
listener = {OtherListener, my_config}
EventBus.mark_as_skipped({listener, :unmatched_occurred, "124"})
listener = {OtherListener, my_config}
EventBus.mark_as_skipped({listener, {:unmatched_occurred, "124"}})
:ok
"""
@spec mark_as_skipped({tuple() | module(), atom(), String.t() | integer()}) ::
no_return()
defdelegate mark_as_skipped(listener_with_event_shadow),
@spec mark_as_skipped(listener_with_event_ref()) :: no_return()
defdelegate mark_as_skipped(listener_with_event_ref),
to: Observation,
as: :mark_as_skipped
end
22 changes: 15 additions & 7 deletions lib/event_bus/managers/observation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -55,22 +55,30 @@ defmodule EventBus.Manager.Observation do
"""
@spec mark_as_completed(tuple()) :: no_return()
def mark_as_completed({listener, topic, id}) do
GenServer.cast(__MODULE__, {:mark_as_completed, {listener, topic, id}})
GenServer.cast(__MODULE__, {:mark_as_completed, {listener, {topic, id}}})
end

def mark_as_completed({listener, {topic, id}}) do
GenServer.cast(__MODULE__, {:mark_as_completed, {listener, {topic, id}}})
end

@doc """
Mark event as skipped on the watcher
"""
@spec mark_as_skipped(tuple()) :: no_return()
def mark_as_skipped({listener, topic, id}) do
GenServer.cast(__MODULE__, {:mark_as_skipped, {listener, topic, id}})
GenServer.cast(__MODULE__, {:mark_as_skipped, {listener, {topic, id}}})
end

def mark_as_skipped({listener, {topic, id}}) do
GenServer.cast(__MODULE__, {:mark_as_skipped, {listener, {topic, id}}})
end

@doc """
Create an watcher
"""
@spec create(tuple()) :: no_return()
def create({listeners, topic, id}) do
def create({listeners, {topic, id}}) do
GenServer.call(__MODULE__, {:save, {topic, id}, {listeners, [], []}})
end

Expand Down Expand Up @@ -122,15 +130,15 @@ defmodule EventBus.Manager.Observation do

@doc false
@spec handle_cast({:mark_as_completed, tuple()}, term()) :: no_return()
def handle_cast({:mark_as_completed, {listener, topic, id}}, state) do
@backend.mark_as_completed({listener, topic, id})
def handle_cast({:mark_as_completed, {listener, {topic, id}}}, state) do
@backend.mark_as_completed({listener, {topic, id}})
{:noreply, state}
end

@doc false
@spec handle_cast({:mark_as_skipped, tuple()}, term()) :: no_return()
def handle_cast({:mark_as_skipped, {listener, topic, id}}, state) do
@backend.mark_as_skipped({listener, topic, id})
def handle_cast({:mark_as_skipped, {listener, {topic, id}}}, state) do
@backend.mark_as_skipped({listener, {topic, id}})
{:noreply, state}
end
end
16 changes: 8 additions & 8 deletions lib/event_bus/managers/subscription.ex
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@ defmodule EventBus.Manager.Subscription do
end

@doc """
Subscribe the listener to topics
Does the listener subscribe to topic_patterns?
"""
@spec subscribed?({tuple() | module(), list()}) :: no_return()
def subscribed?({_listener, _topics} = subscriber) do
@spec subscribed?({tuple() | module(), list()}) :: boolean()
def subscribed?({_listener, _topic_patterns} = subscriber) do
GenServer.call(__MODULE__, {:subscribed?, subscriber})
end

@doc """
Subscribe the listener to topics
Subscribe the listener to topic_patterns
"""
@spec subscribe({tuple() | module(), list()}) :: no_return()
def subscribe({listener, topics}) do
GenServer.cast(__MODULE__, {:subscribe, {listener, topics}})
def subscribe({listener, topic_patterns}) do
GenServer.cast(__MODULE__, {:subscribe, {listener, topic_patterns}})
end

@doc """
Expand Down Expand Up @@ -94,8 +94,8 @@ defmodule EventBus.Manager.Subscription do

@doc false
@spec handle_cast({:subscribe, tuple()}, term()) :: no_return()
def handle_cast({:subscribe, {listener, topics}}, state) do
@backend.subscribe({listener, topics})
def handle_cast({:subscribe, {listener, topic_patterns}}, state) do
@backend.subscribe({listener, topic_patterns})
{:noreply, state}
end

Expand Down
Loading

0 comments on commit c07d2a6

Please sign in to comment.