Browse Source

doc additions, inherit by name, init_arg

Ulf Wiger 14 years ago
parent
commit
af14ad2230
6 changed files 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

+ 46 - 2
README.md

@@ -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.
 An interesting application of gproc is building publish/subscribe patterns.
 Example:
 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 has a QuickCheck test suite, covering a fairly large part of the local 
 gproc functionality, although none of the global registry. It requires a 
 gproc functionality, although none of the global registry. It requires a 
 commercial EQC license, but rebar is smart enough to detect whether EQC is 
 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>
 
 
 
 
 
 

+ 46 - 2
doc/README.md

@@ -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.
 An interesting application of gproc is building publish/subscribe patterns.
 Example:
 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 has a QuickCheck test suite, covering a fairly large part of the local 
 gproc functionality, although none of the global registry. It requires a 
 gproc functionality, although none of the global registry. It requires a 
 commercial EQC license, but rebar is smart enough to detect whether EQC is 
 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>
 
 
 
 
 
 

+ 15 - 5
doc/gproc.md

@@ -384,6 +384,12 @@ uppercase string
 * `{os_env, ENV}` - try `os:getenv(ENV)`
 * `{os_env, ENV}` - try `os:getenv(ENV)`
 * `inherit` - inherit the cached value, if any, held by the (proc_lib) parent.
 * `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, 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
 * `{default, Value}` - set a default value to return once alternatives have been
 exhausted; if not set, `undefined` will be returned.
 exhausted; if not set, `undefined` will be returned.
 * `error` - raise an exception, `erlang:error(gproc_env, [App, Key, Scope])`.
 * `error` - raise an exception, `erlang:error(gproc_env, [App, Key, Scope])`.
@@ -391,8 +397,8 @@ exhausted; if not set, `undefined` will be returned.
 
 
 
 
 While any alternative can occur more than once, the only one that might make
 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  
+sense to repeat is `{default, Value}`.  
-determines the return 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
 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
 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
 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>
 <h3>get_value/1</h3>
 
 

+ 24 - 2
doc/overview.edoc

@@ -3,7 +3,7 @@
 
 
 @doc Extended process dictionary
 @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:
 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>
 <li>Global registry, with all the above functions applied to a network of nodes</li>
 </ul>
 </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.
 An interesting application of gproc is building publish/subscribe patterns.
 Example:
 Example:
 
 
@@ -33,6 +43,18 @@ notify(EventType, Msg) ->
     gproc:send({p, l, Key}, {self(), Key, Msg}).
     gproc:send({p, l, Key}, {self(), Key, Msg}).
 </pre>
 </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 has a QuickCheck test suite, covering a fairly large part of the local 
 gproc functionality, although none of the global registry. It requires a 
 gproc functionality, although none of the global registry. It requires a 
 commercial EQC license, but rebar is smart enough to detect whether EQC is 
 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 
 There is also an eunit suite, covering the basic operations for local and 
 global gproc.
 global gproc.
 
 
-== Building Edoc ==
+<h2>Building Edoc</h2>
 By default, `./rebar doc` generates Github-flavored Markdown files.
 By default, `./rebar doc` generates Github-flavored Markdown files.
 If you want to change this, remove the `edoc_opts' line from `rebar.config'.
 If you want to change this, remove the `edoc_opts' line from `rebar.config'.
 
 

+ 24 - 4
src/gproc.erl

@@ -299,13 +299,19 @@ get_env(Scope, App, Key) ->
 %% * `{os_env, ENV}' - try `os:getenv(ENV)'
 %% * `{os_env, ENV}' - try `os:getenv(ENV)'
 %% * `inherit' - inherit the cached value, if any, held by the (proc_lib) parent.
 %% * `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, 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
 %% * `{default, Value}' - set a default value to return once alternatives have been
 %%    exhausted; if not set, `undefined' will be returned.
 %%    exhausted; if not set, `undefined' will be returned.
 %% * `error' - raise an exception, `erlang:error(gproc_env, [App, Key, Scope])'.
 %% * `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 
 %% 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 
+%% sense to repeat is `{default, Value}'. 
-%% determines the return 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 
 %% 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
 %% 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
 %% @spec get_set_env(Scope::scope(), App::atom(), Key::atom(), Strategy) -> Value
 %% @doc Fetch and cache an environment value, if not already cached.
 %% @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 
 %% 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
 %% cache. Note that the cache will be updated even if the result of the lookup
 %% is `undefined'.
 %% is `undefined'.
+%%
+%% @see get_env/4.
 %% @end
 %% @end
 %%
 %%
 get_set_env(Scope, App, Key, Strategy)
 get_set_env(Scope, App, Key, Strategy)
@@ -398,8 +405,14 @@ try_alternative(inherit, App, Key, Scope) ->
 	_ ->
 	_ ->
 	    undefined
 	    undefined
     end;
     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);
     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) ->
 try_alternative(app_env, App, Key, _Scope) ->
     case application:get_env(App, Key) of
     case application:get_env(App, Key) of
 	undefined       -> undefined;
 	undefined       -> undefined;
@@ -416,6 +429,13 @@ try_alternative({os_env, Key}, _, _, _) ->
 	""  -> undefined;
 	""  -> undefined;
 	Val -> {ok, Val}
 	Val -> {ok, Val}
     end;
     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}, _, _, _) ->
 try_alternative({mnesia,Type,Key,Pos}, _, _, _) ->
     case mnesia:activity(Type, fun() -> mnesia:read(Key) end) of
     case mnesia:activity(Type, fun() -> mnesia:read(Key) end) of
 	[] -> undefined;
 	[] -> undefined;

+ 22 - 1
test/gproc_tests.erl

@@ -63,6 +63,8 @@ reg_test_() ->
       , ?_test(t_is_clean())
       , ?_test(t_is_clean())
       , {spawn, ?_test(t_set_env())}
       , {spawn, ?_test(t_set_env())}
       , ?_test(t_is_clean())
       , ?_test(t_is_clean())
+      , {spawn, ?_test(t_get_env_inherit())}
+      , ?_test(t_is_clean())
      ]}.
      ]}.
 
 
 t_simple_reg() ->
 t_simple_reg() ->
@@ -286,11 +288,19 @@ t_get_env() ->
     ?assertEqual(true, os:putenv("TTTT", "s3")),
     ?assertEqual(true, os:putenv("TTTT", "s3")),
     ?assertEqual(ok, application:set_env(gproc, aaaa, a)),
     ?assertEqual(ok, application:set_env(gproc, aaaa, a)),
     ?assertEqual(undefined, gproc:get_env(l, gproc, ssss, [])),
     ?assertEqual(undefined, gproc:get_env(l, gproc, ssss, [])),
+    %%
     ?assertEqual("s1", gproc:get_env(l, gproc, ssss, [app_env])),
     ?assertEqual("s1", gproc:get_env(l, gproc, ssss, [app_env])),
     ?assertEqual("s2", gproc:get_env(l, gproc, ssss, [os_env])),
     ?assertEqual("s2", gproc:get_env(l, gproc, ssss, [os_env])),
     ?assertEqual("s1", gproc:get_env(l, gproc, ssss, [app_env, 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("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() ->
 t_get_set_env() ->
     ?assertEqual(ok, application:set_env(gproc, aaaa, a)),
     ?assertEqual(ok, application:set_env(gproc, aaaa, a)),
@@ -313,6 +323,17 @@ t_set_env() ->
     ?assertEqual([{self(),"s1"}],
     ?assertEqual([{self(),"s1"}],
 		 gproc:lookup_values({p,l,{gproc_env,gproc,ssss}})).
 		 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() ->
 t_loop() ->
     receive
     receive
 	{From, {give_away, Key}} ->
 	{From, {give_away, Key}} ->