Skip to content
Browse files

e_dict supports unlimited deep structures

  • Loading branch information...
1 parent 5b6a440 commit 130de891d85c0bbc5a928c801a2da1e6bb596522 Michal Ptaszek committed Oct 26, 2009
Showing with 221 additions and 108 deletions.
  1. +1 −0 Emakefile
  2. +2 −0 bin/start.erl
  3. +2 −0 bin/test.erl
  4. +78 −80 lib/eptic-1.3/src/e_dict.erl
  5. +136 −0 lib/eptic-1.3/test/e_dict_test.erl
  6. +2 −28 lib/ewts-1.0/src/ewts.erl
View
1 Emakefile
@@ -49,3 +49,4 @@
debug_info,
strict_record_tests,
netload]}.
+
View
2 bin/start.erl
@@ -636,6 +636,8 @@ copy_escripts(RootDir) ->
{ok, _} ->
Files = [filename:join(["bin", "compile.erl"]),
filename:join(["bin", "add.erl"]),
+ filename:join(["bin", "generate.erl"]),
+ filename:join(["bin", "test.erl"]),
filename:join(["bin", "e_component.erl"])],
case filelib:is_file("Emakefile") of
View
2 bin/test.erl
@@ -43,6 +43,8 @@ start_interactive_mode_node(ReportDir) ->
print_output(Port).
compile() ->
+ [code:add_path(Dir) || Dir <- filelib:wildcard(filename:join(["lib", "*", "test"]))],
+ [code:add_path(Dir) || Dir <- filelib:wildcard(filename:join(["lib", "*", "ebin"]))],
lists:foreach(fun(App) ->
FilesTest = filelib:wildcard(filename:join(["lib", App, "test", "*erl"])),
make:files(FilesTest, [{outdir, filename:join(["lib", App, "test"])},
View
158 lib/eptic-1.3/src/e_dict.erl
@@ -15,24 +15,22 @@
%%%-------------------------------------------------------------------
%%% File : e_dict.erl
-%%% @author Martin Carlson <martin@erlang-consulting.com>
+%%% @author Michal Ptaszek <michal.ptaszek@erlang-consulting.com>
%%% @doc Module responsible for managing the request dictionary.
%%% @end
%%%-------------------------------------------------------------------
-module(e_dict).
%% API
-export([init_state/1, terminate_state/0, get_state/0]).
--export([fset/2, fset/3, fget/1, fget/2, fget/3, finsert/3]).
+-export([fset/2, fset/3, fget/1, fget/2, fget0/2, fget/3, finsert/3]).
-export([fdelete/1, fdelete/2]).
-export([start_link/0]).
-export([init/1, terminate/2]).
-export([handle_call/3, handle_cast/2, handle_info/2]).
-export([code_change/3]).
--record(state, {}).
-
%%====================================================================
%% Exported functions
%%====================================================================
@@ -41,13 +39,13 @@ start_link() ->
gen_server:start_link(?MODULE, [], []).
%% @hidden
-init_state(Dict) when is_list(Dict) ->
- ets:insert(?MODULE, {self(), dict:from_list(Dict)});
-init_state(Dict) ->
- ets:insert(?MODULE, {self(), Dict}).
+init_state(List) when is_list(List) ->
+ ets:insert(?MODULE, {self(), List});
+init_state(Dict) when is_tuple(Dict) ->
+ ets:insert(?MODULE, {self(), dict:to_list(Dict)}).
%% @hidden
--spec(get_state/0 :: () -> {ok, term()} | undefined).
+-spec(get_state/0 :: () -> {ok, list()} | undefined).
get_state() ->
case ets:lookup(?MODULE, self()) of
[{_, Dict}] ->
@@ -61,18 +59,15 @@ terminate_state() ->
ets:delete(?MODULE, self()).
%%
-%% @spec fset(Key :: term(), Value :: term()) -> true
+%% @spec fset(Key :: string(), Value :: term()) -> true
%% @doc Inserts the <i>Value</i> under the specified <i>Key</i> in the request dictionary.
%%
--spec(fset/2 :: (term(), term()) -> true).
+-spec(fset/2 :: (string(), term()) -> true).
fset(Key, Value) ->
- case ets:lookup(?MODULE, self()) of
- [{_, Dict}] -> ets:insert(?MODULE, {self(), dict:store(Key, Value, Dict)});
- [] -> exit(no_dict_attached)
- end.
+ fset0(string:tokens(Key, [$:]), Value).
%%
-%% @spec fset(List :: term(), Key :: term(), Value :: term()) -> true
+%% @spec fset(List :: string(), Key :: string(), Value :: term()) -> true
%% @doc Appends the <i>Value</i> into the <i>List</i> under the <i>Key</i> in the request dictionary.
%% <i>List</i> is the top-level key to the proplist in the dictionary.
%% If there is no list, the new one is created - the call is equivalent to:
@@ -82,25 +77,30 @@ fset(Key, Value) ->
%% Otherwise, the <i>{Key, Value}</i> is appended to the list and the list is then
%% stored in the request dictionary.
%%
--spec(fset/3 :: (term(), term(), term()) -> true).
+-spec(fset/3 :: (string(), string(), term()) -> true).
fset(List, Key, Value) ->
+ fset0([List, Key], Value).
+
+-spec(fset0/2 :: (list(string()), term()) -> true).
+fset0(Keys, Value) ->
case ets:lookup(?MODULE, self()) of
[{_, Dict}] ->
- Current = dict_fetch(List, Dict),
- check_store({Key, Value},Current,List,Dict);
- [] ->
+ ets:insert(?MODULE, {self(), fset0(Keys, Value, Dict)});
+ [] ->
exit(no_dict_attached)
end.
-check_store(T, undefined, List, Dict) ->
- ets:insert(?MODULE, {self(), dict:store(List,[T], Dict)});
-
-check_store(T, Current, List, Dict) ->
- New = case lists:member(T,Current) of
- true -> Current;
- false -> [T|Current]
- end,
- ets:insert(?MODULE, {self(), dict:store(List, New, Dict)}).
+-spec(fset0/3 :: (list(string()), term(), tuple()) -> tuple()).
+fset0([Key], Value, Dict) ->
+ lists:keystore(Key, 1, Dict, {Key, Value});
+fset0([Key | Rest], Value, Dict) ->
+ SubDict = case proplists:get_value(Key, Dict) of
+ undefined ->
+ [];
+ S ->
+ S
+ end,
+ lists:keystore(Key, 1, Dict, {Key, fset0(Rest, Value, SubDict)}).
%%
%% @spec finsert(List :: term(), Key :: term(), Value :: term()) -> true
@@ -113,49 +113,50 @@ check_store(T, Current, List, Dict) ->
%%
-spec(finsert/3 :: (term(), term(), term()) -> true).
finsert(List, Key, Value) ->
- case ets:lookup(?MODULE, self()) of
- [{_, Dict}] ->
- Current = dict_fetch(List, Dict),
- New = case lists:keysearch(Key,1,Current) of
- {value, _} -> lists:keyreplace(Key,1,Current,{Key,Value});
- false -> [{Key,Value}|Current]
- end,
- ets:insert(?MODULE, {self(), dict:store(List, New, Dict)});
- [] -> exit(no_dict_attached)
- end.
-
+ fset0([List, Key], Value).
+
%%
-%% @spec fget(Key :: term()) -> Value :: term() | undefined
+%% @spec fget(Key :: string()) -> Value :: term() | undefined
%% @doc Fetches the element kept in the request dictionary under the <i>Key</i>.
%% If there is no element under <i>Key</i> inside the request dictionary,
%% <i>undefined</i> is returned.
%%
--spec(fget/1 :: (term()) -> term()).
-fget(Key) ->
+-spec(fget/1 :: (string()) -> term()).
+fget(Key0) ->
+ Key = string:tokens(Key0, [$:]),
case ets:lookup(?MODULE, self()) of
- [{_, Dict}] -> dict_fetch(Key, Dict);
- [] -> exit(no_dict_attached)
+ [{_, Dict}] ->
+ fget0(Key, Dict);
+ [] ->
+ exit(no_dict_attached)
end.
%%
-%% @spec fget(List :: term(), Key :: term()) -> term() | undefined
+%% @spec fget(List :: string(), Key :: string()) -> term() | undefined
%% @doc Fetches the element kept in the <i>List</i> in the dictionary under the <i>Key</i>.
%% <i>List</i> is top-level key to the container stored in the request dictionary.
%% The values kept in the container under the <i>Key</i> are returned.
%% If there is no values under <i>Key</i> or there is no <i>List</i>
%% in the request dictionary, the <i>undefined</i> is returned.
%%
--spec(fget/2 :: (term(), term()) -> term()).
+-spec(fget/2 :: (string(), string()) -> term()).
fget(List, Key) ->
- case fget(List) of
- PropList when is_list(PropList) ->
- case proplists:get_all_values(Key, PropList) of
- [] -> undefined;
- [Value] -> Value;
- Values -> Values
- end;
- Result ->
- Result
+ case ets:lookup(?MODULE, self()) of
+ [{_, Dict}] ->
+ fget0([List, Key], Dict);
+ [] ->
+ exit(no_dict_attached)
+ end.
+
+-spec(fget0/2 :: (list(string()), tuple()) -> term()).
+fget0([Key], Dict) ->
+ proplists:get_value(Key, Dict);
+fget0([Key | Rest], Dict) ->
+ case proplists:get_value(Key, Dict) of
+ undefined ->
+ undefined;
+ SubDict ->
+ fget0(Rest, SubDict)
end.
%% @hidden
@@ -175,10 +176,11 @@ fget(List, Key, Validator) ->
%% pernamently.
%%
-spec(fdelete/1 :: (term()) -> true).
-fdelete(Key) ->
+fdelete(Key0) ->
+ Key = string:tokens(Key0, [$:]),
case ets:lookup(?MODULE, self()) of
[{_, Dict}] ->
- ets:insert(?MODULE, {self(), dict:erase(Key, Dict)});
+ fdelete0(Key, Dict);
[] ->
exit(no_dict_attached)
end.
@@ -194,28 +196,33 @@ fdelete(Key) ->
fdelete(List, Key) ->
case ets:lookup(?MODULE, self()) of
[{_, Dict}] ->
- case dict:find(List, Dict) of
- {ok, Proplist} ->
- case lists:keydelete(Key, 1, Proplist) of
- [] ->
- ets:insert(?MODULE, {self(), dict:erase(List, Dict)});
- NewProplist ->
- ets:insert(?MODULE, {self(), dict:store(List, NewProplist, Dict)})
- end;
- error ->
- true
- end;
- [] ->
+ fdelete0([List, Key], Dict);
+ [] ->
exit(no_dict_attached)
end.
+-spec(fdelete0/2 :: (list(string()), tuple()) -> true).
+fdelete0(Keys, Dict) ->
+ ets:insert(?MODULE, {self(), fdelete1(Keys, Dict)}).
+
+-spec(fdelete1/2 :: (list(string()), tuple()) -> tuple()).
+fdelete1([Key], Dict) ->
+ lists:keydelete(Key, 1, Dict);
+fdelete1([Key | Rest], Dict) ->
+ case proplists:get_value(Key, Dict) of
+ undefined ->
+ Dict;
+ SubDict ->
+ lists:keystore(Key, 1, Dict, {Key, fdelete1(Rest, SubDict)})
+ end.
+
%%====================================================================
%% Server functions
%%====================================================================
%% @hidden
init([]) ->
ets:new(?MODULE, [named_table, public]),
- {ok, #state{}}.
+ {ok, not_used}.
%% @hidden
handle_call(_Req, _From, State) ->
@@ -237,12 +244,3 @@ terminate(_Reason, _State) ->
%% @hidden
code_change(_VSN, State, _Extra) ->
{ok, State}.
-
-%%====================================================================
-%% Internal functions
-%%====================================================================
-dict_fetch(Key, Dict) ->
- case dict:find(Key, Dict) of
- {ok, Value} -> Value;
- error -> undefined
- end.
View
136 lib/eptic-1.3/test/e_dict_test.erl
@@ -0,0 +1,136 @@
+%% The contents of this file are subject to the Erlang Web Public License,
+%% Version 1.0, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Web Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang-consulting.com/.
+%%
+%% 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 Erlang Training & Consulting
+%% Ltd. Portions created by Erlang Training & Consulting Ltd are Copyright 2009,
+%% Erlang Training & Consulting Ltd. All Rights Reserved.
+
+%%%-------------------------------------------------------------------
+%%% File : e_dict_test.erl
+%%% Author : Michal Ptaszek <michal.ptaszek@erlang-consulting.com>
+%%% Description :
+%%%
+%%% Created : 26 Oct 2009 by michalptaszek <michalptaszek@coltrane.erlangsystems.com>
+%%%-------------------------------------------------------------------
+-module(e_dict_test).
+
+-compile(export_all).
+
+-include_lib("eunit/include/eunit.hrl").
+-include_lib("ewts/include/request.hrl").
+
+single_level_store_test() ->
+ e_dict:init_state([]),
+ ?assert(e_dict:fset("test", "test")),
+ ?assert(e_dict:fset("abc", 123)),
+ ?assert(e_dict:fset("aaa", {this, is, a, test})),
+
+ {ok, Dict} = e_dict:get_state(),
+ ?assertEqual(lists:sort(Dict),
+ lists:sort([{"test", "test"},
+ {"abc", 123},
+ {"aaa", {this, is, a, test}}])).
+
+double_level_store_test() ->
+ e_dict:init_state([]),
+ ?assert(e_dict:fset("test", "test")),
+ ?assert(e_dict:fset("abc", 123)),
+ ?assert(e_dict:fset("aaa", {this, is, a, test})),
+ ?assert(e_dict:fset("1:2", second_level)),
+ ?assert(e_dict:fset("1:3", third_level)),
+ ?assert(e_dict:fset("test2:wow", 0)),
+
+ {ok, Dict} = e_dict:get_state(),
+ ?assertEqual(lists:sort(Dict),
+ lists:sort([{"test", "test"},
+ {"abc", 123},
+ {"aaa", {this, is, a, test}},
+ {"1", [{"2", second_level},
+ {"3", third_level}]},
+ {"test2", [{"wow", 0}]}])).
+
+multi_level_store_test() ->
+ e_dict:init_state([]),
+ ?assert(e_dict:fset("test", "test")),
+ ?assert(e_dict:fset("abc", 123)),
+ ?assert(e_dict:fset("aaa", {this, is, a, test})),
+ ?assert(e_dict:fset("1:2", second_level)),
+ ?assert(e_dict:fset("1:3", third_level)),
+ ?assert(e_dict:fset("test2:wow", 0)),
+ ?assert(e_dict:fset("a:b:c:d:e", f)),
+
+ {ok, Dict} = e_dict:get_state(),
+ ?assertEqual(lists:sort(Dict),
+ lists:sort([{"test", "test"},
+ {"abc", 123},
+ {"a", [{"b",
+ [{"c",
+ [{"d",
+ [{"e", f}]}]}]}]},
+ {"aaa", {this, is, a, test}},
+ {"1", [{"2", second_level},
+ {"3", third_level}]},
+ {"test2", [{"wow", 0}]}])).
+
+get_test() ->
+ e_dict:init_state([]),
+ ?assert(e_dict:fset("test", "test")),
+ ?assert(e_dict:fset("abc", 123)),
+ ?assert(e_dict:fset("aaa", {this, is, a, test})),
+ ?assert(e_dict:fset("1:2", second_level)),
+ ?assert(e_dict:fset("1:3", third_level)),
+ ?assert(e_dict:fset("test2:wow", 0)),
+ ?assert(e_dict:fset("a:b:c:d:e", f)),
+
+ {ok, Dict} = e_dict:get_state(),
+ ?assertEqual(lists:sort(Dict),
+ lists:sort([{"test", "test"},
+ {"abc", 123},
+ {"a", [{"b",
+ [{"c",
+ [{"d",
+ [{"e", f}]}]}]}]},
+ {"aaa", {this, is, a, test}},
+ {"1", [{"2", second_level},
+ {"3", third_level}]},
+ {"test2", [{"wow", 0}]}])),
+
+ ?assertEqual("test", e_dict:fget("test")),
+ ?assertEqual(123, e_dict:fget("abc")),
+ ?assertEqual({this, is, a, test}, e_dict:fget("aaa")),
+ ?assertEqual([{"2", second_level}, {"3", third_level}], e_dict:fget("1")),
+ ?assertEqual(second_level, e_dict:fget("1:2")),
+ ?assertEqual(third_level, e_dict:fget("1:3")),
+ ?assertEqual(f, e_dict:fget("a:b:c:d:e")).
+
+delete_test() ->
+ e_dict:init_state([]),
+ ?assert(e_dict:fset("test", "test")),
+ ?assert(e_dict:fset("abc", 123)),
+ ?assert(e_dict:fset("aaa", {this, is, a, test})),
+ ?assert(e_dict:fset("1:2", second_level)),
+ ?assert(e_dict:fset("1:3", third_level)),
+ ?assert(e_dict:fset("test2:wow", 0)),
+ ?assert(e_dict:fset("a:b:c:d:e", f)),
+ ?assert(e_dict:fdelete("abc")),
+ ?assert(e_dict:fdelete("1:2")),
+ ?assert(e_dict:fdelete("test2")),
+
+ {ok, Dict} = e_dict:get_state(),
+ ?assertEqual(lists:sort(Dict),
+ lists:sort([{"test", "test"},
+ {"a", [{"b",
+ [{"c",
+ [{"d",
+ [{"e", f}]}]}]}]},
+ {"aaa", {this, is, a, test}},
+ {"1", [{"3", third_level}]}])).
+
View
30 lib/ewts-1.0/src/ewts.erl
@@ -82,34 +82,8 @@ start_tests(Outdir) ->
-spec(fget/2 :: (string(), term()) -> undefined | term()).
fget(Key0, Dict) ->
- case string:tokens(Key0, ":") of
- [List, Key] ->
- fget0(List, Key, Dict);
- [Key] ->
- fget0(Key, Dict)
- end.
-
--spec(fget0/2 :: (string(), term()) -> undefined | term()).
-fget0(Key, Dict) ->
- case dict:find(Key, Dict) of
- {ok, Val} ->
- Val;
- error ->
- undefined
- end.
-
--spec(fget0/3 :: (string(), string(), term()) -> undefined | term()).
-fget0(List, Key, Dict) ->
- case fget0(List, Dict) of
- PropList when is_list(PropList) ->
- case proplists:get_all_values(Key, PropList) of
- [] -> undefined;
- [Value] -> Value;
- Values -> Values
- end;
- Result ->
- Result
- end.
+ Key = string:tokens(Key0, ":"),
+ e_dict:fget0(Key, Dict).
-spec(get_apps/0 :: () -> (list(string()))).
get_apps() ->

0 comments on commit 130de89

Please sign in to comment.
Something went wrong with that request. Please try again.