PageRenderTime 29ms CodeModel.GetById 21ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

/src/mochiglobal.erl

http://github.com/basho/mochiweb
Erlang | 127 lines | 82 code | 14 blank | 31 comment | 1 complexity | 2e3151aa1c638bafb486e4ccacafce45 MD5 | raw file
  1%% @author Bob Ippolito <bob@mochimedia.com>
  2%% @copyright 2010 Mochi Media, Inc.
  3%%
  4%% Permission is hereby granted, free of charge, to any person obtaining a
  5%% copy of this software and associated documentation files (the "Software"),
  6%% to deal in the Software without restriction, including without limitation
  7%% the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8%% and/or sell copies of the Software, and to permit persons to whom the
  9%% Software is furnished to do so, subject to the following conditions:
 10%%
 11%% The above copyright notice and this permission notice shall be included in
 12%% all copies or substantial portions of the Software.
 13%%
 14%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 17%% THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 19%% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 20%% DEALINGS IN THE SOFTWARE.
 21
 22
 23%% @doc Abuse module constant pools as a "read-only shared heap" (since erts 5.6)
 24%%      <a href="http://www.erlang.org/pipermail/erlang-questions/2009-March/042503.html">[1]</a>.
 25-module(mochiglobal).
 26-author("Bob Ippolito <bob@mochimedia.com>").
 27-export([get/1, get/2, put/2, delete/1]).
 28
 29-spec get(atom()) -> any() | undefined.
 30%% @equiv get(K, undefined)
 31get(K) ->
 32    get(K, undefined).
 33
 34-spec get(atom(), T) -> any() | T.
 35%% @doc Get the term for K or return Default.
 36get(K, Default) ->
 37    get(K, Default, key_to_module(K)).
 38
 39get(_K, Default, Mod) ->
 40    try Mod:term()
 41    catch error:undef ->
 42            Default
 43    end.
 44
 45-spec put(atom(), any()) -> ok.
 46%% @doc Store term V at K, replaces an existing term if present.
 47put(K, V) ->
 48    put(K, V, key_to_module(K)).
 49
 50put(_K, V, Mod) ->
 51    Bin = compile(Mod, V),
 52    code:purge(Mod),
 53    {module, Mod} = code:load_binary(Mod, atom_to_list(Mod) ++ ".erl", Bin),
 54    ok.
 55
 56-spec delete(atom()) -> boolean().
 57%% @doc Delete term stored at K, no-op if non-existent.
 58delete(K) ->
 59    delete(K, key_to_module(K)).
 60
 61delete(_K, Mod) ->
 62    code:purge(Mod),
 63    code:delete(Mod).
 64
 65-spec key_to_module(atom()) -> atom().
 66key_to_module(K) ->
 67    list_to_atom("mochiglobal:" ++ atom_to_list(K)).
 68
 69-spec compile(atom(), any()) -> binary().
 70compile(Module, T) ->
 71    {ok, Module, Bin} = compile:forms(forms(Module, T),
 72                                      [verbose, report_errors]),
 73    Bin.
 74
 75-spec forms(atom(), any()) -> [erl_syntax:syntaxTree()].
 76forms(Module, T) ->
 77    [erl_syntax:revert(X) || X <- term_to_abstract(Module, term, T)].
 78
 79-spec term_to_abstract(atom(), atom(), any()) -> [erl_syntax:syntaxTree()].
 80term_to_abstract(Module, Getter, T) ->
 81    [%% -module(Module).
 82     erl_syntax:attribute(
 83       erl_syntax:atom(module),
 84       [erl_syntax:atom(Module)]),
 85     %% -export([Getter/0]).
 86     erl_syntax:attribute(
 87       erl_syntax:atom(export),
 88       [erl_syntax:list(
 89         [erl_syntax:arity_qualifier(
 90            erl_syntax:atom(Getter),
 91            erl_syntax:integer(0))])]),
 92     %% Getter() -> T.
 93     erl_syntax:function(
 94       erl_syntax:atom(Getter),
 95       [erl_syntax:clause([], none, [erl_syntax:abstract(T)])])].
 96
 97%%
 98%% Tests
 99%%
100-ifdef(TEST).
101-include_lib("eunit/include/eunit.hrl").
102get_put_delete_test() ->
103    K = '$$test$$mochiglobal',
104    delete(K),
105    ?assertEqual(
106       bar,
107       get(K, bar)),
108    try
109        ?MODULE:put(K, baz),
110        ?assertEqual(
111           baz,
112           get(K, bar)),
113        ?MODULE:put(K, wibble),
114        ?assertEqual(
115           wibble,
116           ?MODULE:get(K))
117    after
118        delete(K)
119    end,
120    ?assertEqual(
121       bar,
122       get(K, bar)),
123    ?assertEqual(
124       undefined,
125       ?MODULE:get(K)),
126    ok.
127-endif.