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
 current_counterexample.eqc
 deps/
 deps/
-ebin/
 .eunit/
 .eunit/
 *~
 *~
 */*~
 */*~
+*/#*#
 erl_crash.dump
 erl_crash.dump
 gproc_dist*@*
 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_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_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_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>
 <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_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_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_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>
 <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}.
 {application,gproc}.
 {packages,[]}.
 {packages,[]}.
 {modules,[gproc,gproc_app,gproc_bcast,gproc_dist,gproc_info,gproc_init,
 {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>
 <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>
 </code></pre>
 
 
 <br></br>
 <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.
 Sends a message to the process, or processes, corresponding to Key.
 
 
 
 
+
 If Key belongs to a unique object (name or aggregated counter), this
 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
 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
 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.
 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>
 <a name="set_attributes-2"></a>
 
 
 ### set_attributes/2 ###
 ### set_attributes/2 ###

+ 1 - 1
doc/gproc_dist.md

@@ -7,7 +7,7 @@
 
 
 
 
 Extended process registry.
 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)).
 __Authors:__ Ulf Wiger ([`ulf@wiger.net`](mailto:ulf@wiger.net)).
 <a name="description"></a>
 <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() ->
 goodbye() ->
     process_is_down(self()).
     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.
 %% @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
 %% 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
 %% 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.
 %% 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
 %% @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) ->
 send(Key, Msg) ->
     ?CATCH_GPROC_ERROR(send1(Key, Msg), [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}),
     gen_server:abcast(Ns -- [node()], gproc_bcast, {send, Key, Msg}),
     Msg.
     Msg.
 
 
-
 %% @spec (Context :: context()) -> key() | '$end_of_table'
 %% @spec (Context :: context()) -> key() | '$end_of_table'
 %%
 %%
 %% @doc Behaves as ets:first(Tab) for a given type of registration.
 %% @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).