Permalink
Browse files

doc additions, inherit by name, init_arg

  • Loading branch information...
1 parent 9c505d4 commit af14ad2230735801b9176bf4b53792d05444cc8b Ulf Wiger committed Apr 26, 2011
Showing with 177 additions and 16 deletions.
  1. +46 −2 README.md
  2. +46 −2 doc/README.md
  3. +15 −5 doc/gproc.md
  4. +24 −2 doc/overview.edoc
  5. +24 −4 src/gproc.erl
  6. +22 −1 test/gproc_tests.erl
View
@@ -12,7 +12,7 @@ Extended process dictionary
-<h3><a name="Introduction">Introduction</a></h3>
+<h2>Introduction</h2>
@@ -43,6 +43,26 @@ Gproc is a process dictionary for Erlang, which provides a number of useful feat
+<h3>Use case: System inspection</h3>
+
+
+
+
+
+Gproc was designed to work as a central index for "process metadata", i.e.
+properties that describe the role and characteristics of each process. Having
+a single registry that is flexible enough to hold important types of property
+makes it easier to (a) find processes of a certain type, and (b) query and
+browse key data in a running system.
+
+
+
+<h3>Use case: Pub/Sub patterns</h3>
+
+
+
+
+
An interesting application of gproc is building publish/subscribe patterns.
Example:
@@ -58,6 +78,30 @@ notify(EventType, Msg) ->
+<h3>Use case: Environment handling</h3>
+
+
+
+
+
+Gproc provides a set of functions to read environment variables, possibly from
+alternative sources, and cache them for efficient lookup. Caching also provides
+a way to see which processes rely on certain configuration values, as well as
+which values they actually ended up using.
+
+
+
+See [`gproc:get_env/4`](http://github.com/esl/gproc/blob/env_vars/doc/gproc.md#get_env-4), [`gproc:get_set_env/4`](http://github.com/esl/gproc/blob/env_vars/doc/gproc.md#get_set_env-4) and
+[`gproc:set_env/5`](http://github.com/esl/gproc/blob/env_vars/doc/gproc.md#set_env-5) for details.
+
+
+
+<h2>Testing</h2>
+
+
+
+
+
Gproc has a QuickCheck test suite, covering a fairly large part of the local
gproc functionality, although none of the global registry. It requires a
commercial EQC license, but rebar is smart enough to detect whether EQC is
@@ -70,7 +114,7 @@ global gproc.
-<h3><a name="Building_Edoc">Building Edoc</a></h3>
+<h2>Building Edoc</h2>
View
@@ -12,7 +12,7 @@ Extended process dictionary
-<h3><a name="Introduction">Introduction</a></h3>
+<h2>Introduction</h2>
@@ -43,6 +43,26 @@ Gproc is a process dictionary for Erlang, which provides a number of useful feat
+<h3>Use case: System inspection</h3>
+
+
+
+
+
+Gproc was designed to work as a central index for "process metadata", i.e.
+properties that describe the role and characteristics of each process. Having
+a single registry that is flexible enough to hold important types of property
+makes it easier to (a) find processes of a certain type, and (b) query and
+browse key data in a running system.
+
+
+
+<h3>Use case: Pub/Sub patterns</h3>
+
+
+
+
+
An interesting application of gproc is building publish/subscribe patterns.
Example:
@@ -58,6 +78,30 @@ notify(EventType, Msg) ->
+<h3>Use case: Environment handling</h3>
+
+
+
+
+
+Gproc provides a set of functions to read environment variables, possibly from
+alternative sources, and cache them for efficient lookup. Caching also provides
+a way to see which processes rely on certain configuration values, as well as
+which values they actually ended up using.
+
+
+
+See [`gproc:get_env/4`](gproc.md#get_env-4), [`gproc:get_set_env/4`](gproc.md#get_set_env-4) and
+[`gproc:set_env/5`](gproc.md#set_env-5) for details.
+
+
+
+<h2>Testing</h2>
+
+
+
+
+
Gproc has a QuickCheck test suite, covering a fairly large part of the local
gproc functionality, although none of the global registry. It requires a
commercial EQC license, but rebar is smart enough to detect whether EQC is
@@ -70,7 +114,7 @@ global gproc.
-<h3><a name="Building_Edoc">Building Edoc</a></h3>
+<h2>Building Edoc</h2>
View
@@ -384,15 +384,21 @@ uppercase string
* `{os_env, ENV}` - try `os:getenv(ENV)`
* `inherit` - inherit the cached value, if any, held by the (proc_lib) parent.
* `{inherit, Pid}` - inherit the cached value, if any, held by `Pid`.
+* `{inherit, Name}` - inherit the cached value, if any, held by the process
+registered in `gproc` as `Name`.
+* `init_arg` - try `init:get_argument(Key)`; expects a single value, if any.
+* `{mnesia, ActivityType, Oid, Pos}` - try
+`mnesia:activity(ActivityType, fun() -> mnesia:read(Oid) end)`; retrieve the
+value in position `Pos` if object found.
* `{default, Value}` - set a default value to return once alternatives have been
exhausted; if not set, `undefined` will be returned.
* `error` - raise an exception, `erlang:error(gproc_env, [App, Key, Scope])`.
While any alternative can occur more than once, the only one that might make
-sense to repeat is `{default, Value}`. The last instance will be the one that
-determines the return value.
+sense to repeat is `{default, Value}`.
+The last instance will be the one that determines the return value.
The `error` option can be used to assert that a value has been previously
cached. Alternatively, it can be used to assert that a value is either cached
@@ -424,12 +430,16 @@ Equivalent to [`get_set_env(Scope, App, Key, [app_env])`](#get_set_env-4).<a nam
-Fetch and cache an environment value, if not already cached.
-__See also:__ [This function does the same thing as [`get_env/4`](#get_env-4), but also updates the
+Fetch and cache an environment value, if not already cached.
+
+This function does the same thing as [`get_env/4`](#get_env-4), but also updates the
cache. Note that the cache will be updated even if the result of the lookup
-is `undefined`.](#get_env-4).<a name="get_value-1"></a>
+is `undefined`.
+
+
+__See also:__ [get_env/4](#get_env-4).<a name="get_value-1"></a>
<h3>get_value/1</h3>
View
@@ -3,7 +3,7 @@
@doc Extended process dictionary
-== Introduction ==
+<h2>Introduction</h2>
Gproc is a process dictionary for Erlang, which provides a number of useful features beyond what the built-in dictionary has:
@@ -20,6 +20,16 @@ Gproc is a process dictionary for Erlang, which provides a number of useful feat
<li>Global registry, with all the above functions applied to a network of nodes</li>
</ul>
+<h3>Use case: System inspection</h3>
+
+Gproc was designed to work as a central index for "process metadata", i.e.
+properties that describe the role and characteristics of each process. Having
+a single registry that is flexible enough to hold important types of property
+makes it easier to (a) find processes of a certain type, and (b) query and
+browse key data in a running system.
+
+<h3>Use case: Pub/Sub patterns</h3>
+
An interesting application of gproc is building publish/subscribe patterns.
Example:
@@ -33,6 +43,18 @@ notify(EventType, Msg) ->
gproc:send({p, l, Key}, {self(), Key, Msg}).
</pre>
+<h3>Use case: Environment handling</h3>
+
+Gproc provides a set of functions to read environment variables, possibly from
+alternative sources, and cache them for efficient lookup. Caching also provides
+a way to see which processes rely on certain configuration values, as well as
+which values they actually ended up using.
+
+See {@link gproc:get_env/4}, {@link gproc:get_set_env/4} and
+{@link gproc:set_env/5} for details.
+
+<h2>Testing</h2>
+
Gproc has a QuickCheck test suite, covering a fairly large part of the local
gproc functionality, although none of the global registry. It requires a
commercial EQC license, but rebar is smart enough to detect whether EQC is
@@ -41,7 +63,7 @@ available, and if it isn't, the code in gproc_eqc.erl will be "defined away".
There is also an eunit suite, covering the basic operations for local and
global gproc.
-== Building Edoc ==
+<h2>Building Edoc</h2>
By default, `./rebar doc` generates Github-flavored Markdown files.
If you want to change this, remove the `edoc_opts' line from `rebar.config'.
View
@@ -299,13 +299,19 @@ get_env(Scope, App, Key) ->
%% * `{os_env, ENV}' - try `os:getenv(ENV)'
%% * `inherit' - inherit the cached value, if any, held by the (proc_lib) parent.
%% * `{inherit, Pid}' - inherit the cached value, if any, held by `Pid'.
+%% * `{inherit, Name}' - inherit the cached value, if any, held by the process
+%% registered in `gproc' as `Name'.
+%% * `init_arg' - try `init:get_argument(Key)'; expects a single value, if any.
+%% * `{mnesia, ActivityType, Oid, Pos}' - try
+%% `mnesia:activity(ActivityType, fun() -> mnesia:read(Oid) end)'; retrieve the
+%% value in position `Pos' if object found.
%% * `{default, Value}' - set a default value to return once alternatives have been
%% exhausted; if not set, `undefined' will be returned.
%% * `error' - raise an exception, `erlang:error(gproc_env, [App, Key, Scope])'.
%%
%% While any alternative can occur more than once, the only one that might make
-%% sense to repeat is `{default, Value}'. The last instance will be the one that
-%% determines the return value.
+%% sense to repeat is `{default, Value}'.
+%% The last instance will be the one that determines the return value.
%%
%% The `error' option can be used to assert that a value has been previously
%% cached. Alternatively, it can be used to assert that a value is either cached
@@ -324,10 +330,11 @@ get_set_env(Scope, App, Key) ->
%% @spec get_set_env(Scope::scope(), App::atom(), Key::atom(), Strategy) -> Value
%% @doc Fetch and cache an environment value, if not already cached.
%%
-%% @see get_env/4.
%% This function does the same thing as {@link get_env/4}, but also updates the
%% cache. Note that the cache will be updated even if the result of the lookup
%% is `undefined'.
+%%
+%% @see get_env/4.
%% @end
%%
get_set_env(Scope, App, Key, Strategy)
@@ -398,8 +405,14 @@ try_alternative(inherit, App, Key, Scope) ->
_ ->
undefined
end;
-try_alternative({inherit, P}, App, Key, Scope) ->
+try_alternative({inherit, P}, App, Key, Scope) when is_pid(P) ->
lookup_env(Scope, App, Key, P);
+try_alternative({inherit, P}, App, Key, Scope) ->
+ case where(P) of
+ undefined -> undefined;
+ Pid when is_pid(Pid) ->
+ lookup_env(Scope, App, Key, Pid)
+ end;
try_alternative(app_env, App, Key, _Scope) ->
case application:get_env(App, Key) of
undefined -> undefined;
@@ -416,6 +429,13 @@ try_alternative({os_env, Key}, _, _, _) ->
"" -> undefined;
Val -> {ok, Val}
end;
+try_alternative(init_arg, _, Key, _) ->
+ case init:get_argument(Key) of
+ {ok, [[Value]]} ->
+ {ok, Value};
+ error ->
+ undefined
+ end;
try_alternative({mnesia,Type,Key,Pos}, _, _, _) ->
case mnesia:activity(Type, fun() -> mnesia:read(Key) end) of
[] -> undefined;
View
@@ -63,6 +63,8 @@ reg_test_() ->
, ?_test(t_is_clean())
, {spawn, ?_test(t_set_env())}
, ?_test(t_is_clean())
+ , {spawn, ?_test(t_get_env_inherit())}
+ , ?_test(t_is_clean())
]}.
t_simple_reg() ->
@@ -286,11 +288,19 @@ t_get_env() ->
?assertEqual(true, os:putenv("TTTT", "s3")),
?assertEqual(ok, application:set_env(gproc, aaaa, a)),
?assertEqual(undefined, gproc:get_env(l, gproc, ssss, [])),
+ %%
?assertEqual("s1", gproc:get_env(l, gproc, ssss, [app_env])),
?assertEqual("s2", gproc:get_env(l, gproc, ssss, [os_env])),
?assertEqual("s1", gproc:get_env(l, gproc, ssss, [app_env, os_env])),
?assertEqual("s3", gproc:get_env(l, gproc, ssss, [{os_env,"TTTT"}])),
- ?assertEqual("s4", gproc:get_env(l, gproc, ssss, [{default,"s4"}])).
+ ?assertEqual("s4", gproc:get_env(l, gproc, ssss, [{default,"s4"}])),
+ %%
+ ?assertEqual(ok, application:start(mnesia)),
+ ?assertEqual({atomic,ok}, mnesia:create_table(t, [{ram_copies, [node()]}])),
+ ?assertEqual(ok, mnesia:dirty_write({t, foo, bar})),
+ ?assertEqual(bar, gproc:get_env(l, gproc, some_env, [{mnesia,transaction,
+ {t, foo}, 3}])),
+ ?assertEqual("erl", gproc:get_env(l, gproc, progname, [init_arg])).
t_get_set_env() ->
?assertEqual(ok, application:set_env(gproc, aaaa, a)),
@@ -313,6 +323,17 @@ t_set_env() ->
?assertEqual([{self(),"s1"}],
gproc:lookup_values({p,l,{gproc_env,gproc,ssss}})).
+t_get_env_inherit() ->
+ P = spawn_link(fun() ->
+ ?assertEqual(bar, gproc:set_env(l,gproc,foo,bar,[])),
+ gproc:reg({n,l,get_env_p}),
+ t_loop()
+ end),
+ ?assertEqual({P,undefined}, gproc:await({n,l,get_env_p},1000)),
+ ?assertEqual(bar, gproc:get_env(l, gproc, foo, [{inherit, P}])),
+ ?assertEqual(bar, gproc:get_env(l, gproc, foo, [{inherit, {n,l,get_env_p}}])),
+ ?assertEqual(ok, t_call(P, die)).
+
t_loop() ->
receive
{From, {give_away, Key}} ->

0 comments on commit af14ad2

Please sign in to comment.