Skip to content

Commit

Permalink
Merge pull request #3 from vesta-merkur/pinned_vars
Browse files Browse the repository at this point in the history
Allow for pinned variables in pattern
  • Loading branch information
lasseebert authored Apr 18, 2017
2 parents 42b3063 + e8d7175 commit c386f38
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 1 deletion.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,24 @@ def handle_info({:hello, name}, state) do
end
```

### Using local variables

Sometimes one wish to subscribe using a pattern involving local variables.
The `subscribe` macro accepts a `bind_quoted` argument, that will replace pinned variables with the given values.

E.g.

```elixir
size = 42
Hub.subscribe("my channel", %{size: ^size}, bind_quoted: [size: size])
```

is equivalent to

```elixir
Hub.subscribe("my channel", %{size: 42})
```

## Examples

Subscribe only once to a message:
Expand Down
28 changes: 27 additions & 1 deletion lib/hub.ex
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ defmodule Hub do
"""
defmacro subscribe(channel, pattern, options \\ []) do
quote do
Hub.subscribe_quoted(unquote(channel), unquote(Macro.escape(pattern)), unquote(options))
{bind_quoted, options} = unquote(options) |> Keyword.pop(:bind_quoted, [])
quoted_pattern = unquote(Macro.escape(pattern)) |> Hub.replace_pins(bind_quoted)

Hub.subscribe_quoted(unquote(channel), quoted_pattern, options)
end
end

Expand Down Expand Up @@ -145,4 +148,27 @@ defmodule Hub do
defp tracker_topic(channel) when is_binary(channel) do
@tracker_topic_prefix <> channel
end

@doc false
def replace_pins({:^, _, [{name, _, _}]} = term, bindings) do
case Keyword.fetch(bindings, name) do
{:ok, value} -> value
:error -> term
end
end
def replace_pins({fun, con, args}, bindings) do
{fun, con, replace_pins(args, bindings)}
end
def replace_pins({term_1, term_2}, bindings) do
{
replace_pins(term_1, bindings),
replace_pins(term_2, bindings)
}
end
def replace_pins(list, bindings) when is_list(list) do
list |> Enum.map(&replace_pins(&1, bindings))
end
def replace_pins(term, _bindings) do
term
end
end
8 changes: 8 additions & 0 deletions test/hub_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,12 @@ defmodule HubTest do
result = Task.await(task)
assert result == ~w(Me You)
end

test "local variables parts of pattern" do
name = "World"
Hub.subscribe("global", {:hello, ^name}, bind_quoted: [name: name])
Hub.publish("global", {:hello, "World"})

assert_received({:hello, "World"})
end
end

0 comments on commit c386f38

Please sign in to comment.