Browse Source

Merge branch 'master' of github.com:uwiger/gproc

Conflicts:
	doc/edoc-info
	doc/gproc.md
	doc/gproc_dist.md
	doc/gproc_lib.md
Ulf Wiger 12 years ago
parent
commit
9d3514d8a7
11 changed files with 156 additions and 6 deletions
  1. 1 1
      .gitignore
  2. 1 0
      README.md
  3. 1 0
      doc/README.md
  4. 1 1
      doc/edoc-info
  5. 6 1
      doc/gproc.md
  6. 1 1
      doc/gproc_dist.md
  7. 54 0
      doc/gproc_pt.md
  8. 2 0
      ebin/.gitignore
  9. 8 2
      src/gproc.erl
  10. 57 0
      src/gproc_pt.erl
  11. 24 0
      test/gproc_pt_tests.erl

+ 1 - 1
.gitignore

@@ -1,8 +1,8 @@
 current_counterexample.eqc
 deps/
-ebin/
 .eunit/
 *~
 */*~
+*/#*#
 erl_crash.dump
 gproc_dist*@*

+ 1 - 0
README.md

@@ -115,5 +115,6 @@ Freiburg 2007 ([Paper available here](http://github.com/esl/gproc/blob/master/do
 <tr><td><a href="http://github.com/esl/gproc/blob/master/doc/gproc_monitor.md" class="module">gproc_monitor</a></td></tr>
 <tr><td><a href="http://github.com/esl/gproc/blob/master/doc/gproc_pool.md" class="module">gproc_pool</a></td></tr>
 <tr><td><a href="http://github.com/esl/gproc/blob/master/doc/gproc_ps.md" class="module">gproc_ps</a></td></tr>
+<tr><td><a href="http://github.com/esl/gproc/blob/master/doc/gproc_pt.md" class="module">gproc_pt</a></td></tr>
 <tr><td><a href="http://github.com/esl/gproc/blob/master/doc/gproc_sup.md" class="module">gproc_sup</a></td></tr></table>
 

+ 1 - 0
doc/README.md

@@ -115,5 +115,6 @@ Freiburg 2007 ([Paper available here](erlang07-wiger.pdf)).
 <tr><td><a href="gproc_monitor.md" class="module">gproc_monitor</a></td></tr>
 <tr><td><a href="gproc_pool.md" class="module">gproc_pool</a></td></tr>
 <tr><td><a href="gproc_ps.md" class="module">gproc_ps</a></td></tr>
+<tr><td><a href="gproc_pt.md" class="module">gproc_pt</a></td></tr>
 <tr><td><a href="gproc_sup.md" class="module">gproc_sup</a></td></tr></table>
 

+ 1 - 1
doc/edoc-info

@@ -1,4 +1,4 @@
 {application,gproc}.
 {packages,[]}.
 {modules,[gproc,gproc_app,gproc_bcast,gproc_dist,gproc_info,gproc_init,
-          gproc_lib,gproc_monitor,gproc_pool,gproc_ps,gproc_sup]}.
+          gproc_lib,gproc_monitor,gproc_pool,gproc_ps,gproc_pt,gproc_sup]}.

+ 6 - 1
doc/gproc.md

@@ -1479,7 +1479,7 @@ but the select patterns are transformed appropriately.
 
 
 <pre><code>
-send(Key::<a href="#type-key">key()</a>, Msg::any()) -&gt; Msg
+send(Key::<a href="#type-process">process()</a> | <a href="#type-key">key()</a>, Msg::any()) -&gt; Msg
 </code></pre>
 
 <br></br>
@@ -1489,10 +1489,15 @@ send(Key::<a href="#type-key">key()</a>, Msg::any()) -&gt; Msg
 Sends a message to the process, or processes, corresponding to Key.
 
 
+
 If Key belongs to a unique object (name or aggregated counter), this
 function will send a message to the corresponding process, or fail if there
 is no such process. If Key is for a non-unique object type (counter or
 property), Msg will be send to all processes that have such an object.
+
+
+Key can also be anything that the erlang:send/2, or '!' operator accepts as a process
+identifier, namely a pid(), an atom(), or `{Name::atom(), Node::atom()}`.
 <a name="set_attributes-2"></a>
 
 ### set_attributes/2 ###

+ 1 - 1
doc/gproc_dist.md

@@ -7,7 +7,7 @@
 
 
 Extended process registry.
-__Behaviours:__ [`gen_leader`](/Users/uwiger/FL/git/gen_leader/doc/gen_leader.md).
+__Behaviours:__ [`gen_leader`](gen_leader.md).
 
 __Authors:__ Ulf Wiger ([`ulf@wiger.net`](mailto:ulf@wiger.net)).
 <a name="description"></a>

+ 54 - 0
doc/gproc_pt.md

@@ -0,0 +1,54 @@
+
+
+# Module gproc_pt #
+* [Description](#description)
+* [Function Index](#index)
+* [Function Details](#functions)
+
+
+Parse transform utility for gproc users.
+__Authors:__ Ulf Wiger ([`ulf@wiger.net`](mailto:ulf@wiger.net)), Dmitry Demeshchuk ([`demeshchuk@gmail.com`](mailto:demeshchuk@gmail.com)).
+<a name="description"></a>
+
+## Description ##
+
+
+
+This module provides some closer syntactical integration for
+people who are enthusiastic gproc users.
+
+
+
+Specifically, this module transforms `Pid ! Msg` into
+`gproc:send(Pid, Msg)`, which, apart from accepting any type for
+`Pid` that `!` understands, is also able to handle a gproc "triple",
+e.g. `{n, l, Name}` or even `{p, l, Prop}` (in the latter case, the
+message may be delivered to multiple recipients).
+
+
+
+Users should be aware that parse transforms may be confusing to
+the casual reader, since they extend the semantics of possibly
+ubiquitous constructs (as is the case with this transform). Therefore,
+you should document clearly that this is happening.
+
+
+Original suggestion by Dimitry Demeschuk.<a name="index"></a>
+
+## Function Index ##
+
+
+<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#parse_transform-2">parse_transform/2</a></td><td></td></tr></table>
+
+
+<a name="functions"></a>
+
+## Function Details ##
+
+<a name="parse_transform-2"></a>
+
+### parse_transform/2 ###
+
+`parse_transform(Forms, Options) -> any()`
+
+

+ 2 - 0
ebin/.gitignore

@@ -0,0 +1,2 @@
+*
+!.gitignore

+ 8 - 2
src/gproc.erl

@@ -1709,7 +1709,7 @@ give_away1({_,g,_} = Key, To) ->
 goodbye() ->
     process_is_down(self()).
 
-%% @spec (Key::key(), Msg::any()) -> Msg
+%% @spec (Key::process() | key(), Msg::any()) -> Msg
 %%
 %% @doc Sends a message to the process, or processes, corresponding to Key.
 %%
@@ -1717,8 +1717,15 @@ goodbye() ->
 %% function will send a message to the corresponding process, or fail if there
 %% is no such process. If Key is for a non-unique object type (counter or
 %% property), Msg will be send to all processes that have such an object.
+%%
+%% Key can also be anything that the erlang:send/2, or '!' operator accepts as a process
+%% identifier, namely a pid(), an atom(), or `{Name::atom(), Node::atom()}'.
 %% @end
 %%
+send(P, Msg) when is_pid(P); is_atom(P) ->
+    P ! Msg;
+send({Name, Node} = P, Msg) when is_atom(Node), is_atom(Name) ->
+    P ! Msg;
 send(Key, Msg) ->
     ?CATCH_GPROC_ERROR(send1(Key, Msg), [Key, Msg]).
 
@@ -1771,7 +1778,6 @@ bcast1(Ns, {T,l,_} = Key, Msg) when T==p; T==a; T==c; T==n; T==p ->
     gen_server:abcast(Ns -- [node()], gproc_bcast, {send, Key, Msg}),
     Msg.
 
-
 %% @spec (Context :: context()) -> key() | '$end_of_table'
 %%
 %% @doc Behaves as ets:first(Tab) for a given type of registration.

+ 57 - 0
src/gproc_pt.erl

@@ -0,0 +1,57 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+%% AB. All Rights Reserved.''
+%%
+%% @author Ulf Wiger <ulf@wiger.net>
+%% @author Dmitry Demeshchuk <demeshchuk@gmail.com>
+%%
+%% @doc Parse transform utility for gproc users.
+%%
+%% This module provides some closer syntactical integration for
+%% people who are enthusiastic gproc users.
+%%
+%% Specifically, this module transforms `Pid ! Msg' into
+%% `gproc:send(Pid, Msg)', which, apart from accepting any type for
+%% `Pid' that `!' understands, is also able to handle a gproc "triple",
+%% e.g. `{n, l, Name}' or even `{p, l, Prop}' (in the latter case, the
+%% message may be delivered to multiple recipients).
+%%
+%% Users should be aware that parse transforms may be confusing to
+%% the casual reader, since they extend the semantics of possibly
+%% ubiquitous constructs (as is the case with this transform). Therefore,
+%% you should document clearly that this is happening.
+%%
+%% Original suggestion by Dimitry Demeschuk.
+%% @end
+%%
+-module(gproc_pt).
+
+-export([parse_transform/2]).
+
+parse_transform(Forms, _Options) ->
+    do_transform(Forms).
+
+do_transform([{op, L, '!', Lhs, Rhs}|Fs]) ->
+    [NewLhs] = do_transform([Lhs]),
+    [NewRhs] = do_transform([Rhs]),
+    [{call, L, {remote, L, {atom, L, gproc}, {atom, L, send}},
+        [NewLhs, NewRhs]} | do_transform(Fs)];
+do_transform([]) ->
+    [];
+do_transform([F|Fs]) when is_tuple(F) ->
+    [list_to_tuple(do_transform(tuple_to_list(F))) | do_transform(Fs)];
+do_transform([F|Fs]) ->
+    [do_transform(F) | do_transform(Fs)];
+do_transform(F) ->
+    F.

+ 24 - 0
test/gproc_pt_tests.erl

@@ -0,0 +1,24 @@
+-module(gproc_pt_tests).
+
+-include_lib("eunit/include/eunit.hrl").
+
+-compile({parse_transform, gproc_pt}).
+
+reg_and_send_test_() ->
+    {setup,
+        fun() -> application:start(gproc) end,
+        fun(_) -> application:stop(gproc) end,
+        [{"gproc", fun gproc/0}]
+    }.
+
+gproc() ->
+    gproc:reg({n, l, <<"test">>}),
+
+    Msg = random:uniform(1000),
+    {n, l, <<"test">>} ! Msg,
+
+    Echo = receive
+        V -> V
+    end,
+
+    ?assertEqual(Echo, Msg).