Skip to content

Commit

Permalink
Move generic module wrangling functions to new module
Browse files Browse the repository at this point in the history
  • Loading branch information
eproxus committed May 23, 2011
1 parent b411111 commit 6680628
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 51 deletions.
57 changes: 6 additions & 51 deletions src/meck.erl
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ init([Mod, Options]) ->
Original = backup_original(Mod),
process_flag(trap_exit, true),
Expects = init_expects(Mod, Options),
compile_forms(to_forms(Mod, Expects)),
meck_mod:compile_and_load_forms(to_forms(Mod, Expects)),
{ok, #state{mod = Mod, expects = Expects, original = Original}}.

%% @hidden
Expand Down Expand Up @@ -362,7 +362,7 @@ change_expects(Op, Mod, Func, Value, Expects) ->
% only recompile if function was added or arity was changed
case interface_equal(NewExpects, Expects) of
true -> ok;
false -> compile_forms(to_forms(Mod, NewExpects))
false -> meck_mod:compile_and_load_forms(to_forms(Mod, NewExpects))
end,
NewExpects.

Expand Down Expand Up @@ -474,9 +474,10 @@ is_mock_exception(Fun) -> is_local_function(Fun).
backup_original(Module) ->
Cover = get_cover_state(Module),
try
Forms = abstract_code(beam_file(Module)),
Forms = meck_mod:abstract_code(meck_mod:beam_file(Module)),
NewName = original_name(Module),
compile_forms(rename_module(Forms, NewName), compile_options(Module))
meck_mod:compile_and_load_forms(meck_mod:rename_module(Forms, NewName),
meck_mod:compile_options(Module))
catch
throw:{object_code_not_found, _Module} -> ok; % TODO: What to do here?
throw:no_abstract_code -> ok % TODO: What to do here?
Expand All @@ -503,7 +504,7 @@ get_cover_state(Module, {file, File}) ->
ok = cover:export(Data, Module),
CompileOptions =
try
compile_options(beam_file(Module))
meck_mod:compile_options(meck_mod:beam_file(Module))
catch
throw:{object_code_not_found, _Module} -> []
end,
Expand All @@ -518,52 +519,6 @@ exports(Module) ->
[ FA || FA <- Module:module_info(exports),
FA /= {module_info, 0}, FA /= {module_info, 1}].

compile_forms(AbsCode) -> compile_forms(AbsCode, []).

compile_forms(AbsCode, Opts) ->
case compile:forms(AbsCode, Opts) of
{ok, ModName, Binary} ->
load_binary(ModName, Binary);
{ok, ModName, Binary, _Warnings} ->
load_binary(ModName, Binary)
end.

load_binary(Name, Binary) ->
case code:load_binary(Name, "", Binary) of
{module, Name} -> ok;
{error, Reason} -> exit({error_loading_module, Name, Reason})
end.

beam_file(Module) ->
% code:which/1 cannot be used for cover_compiled modules
case code:get_object_code(Module) of
{_, Binary, _Filename} -> Binary;
error -> throw({object_code_not_found, Module})
end.

abstract_code(BeamFile) ->
case beam_lib:chunks(BeamFile, [abstract_code]) of
{ok, {_, [{abstract_code, {raw_abstract_v1, Forms}}]}} ->
Forms;
{ok, {_, [{abstract_code, no_abstract_code}]}} ->
throw(no_abstract_code)
end.

compile_options(BeamFile) when is_binary(BeamFile) ->
case beam_lib:chunks(BeamFile, [compile_info]) of
{ok, {_, [{compile_info, Info}]}} ->
proplists:get_value(options, Info);
_ ->
[]
end;
compile_options(Module) ->
proplists:get_value(options, Module:module_info(compile)).

rename_module([{attribute, Line, module, _OldName}|T], NewName) ->
[{attribute, Line, module, NewName}|T];
rename_module([H|T], NewName) ->
[H|rename_module(T, NewName)].

cleanup(Mod) ->
code:purge(Mod),
code:delete(Mod),
Expand Down
93 changes: 93 additions & 0 deletions src/meck_mod.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
%%==============================================================================
%% Copyright 2011 Adam Lindberg & Erlang Solutions Ltd.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%==============================================================================

%% @author Adam Lindberg <eproxus@gmail.com>
%% @copyright 2011, Adam Lindberg & Erlang Solutions Ltd
%% @doc Module wrangling helper functions.

-module(meck_mod).

%% Interface exports
-export([abstract_code/1]).
-export([beam_file/1]).
-export([compile_and_load_forms/1]).
-export([compile_and_load_forms/2]).
-export([compile_options/1]).
-export([rename_module/2]).

%% Types
-type erlang_form() :: term().
-type compile_options() :: [term()].

%%==============================================================================
%% Interface exports
%%==============================================================================

-spec abstract_code(binary()) -> erlang_form().
abstract_code(BeamFile) ->
case beam_lib:chunks(BeamFile, [abstract_code]) of
{ok, {_, [{abstract_code, {raw_abstract_v1, Forms}}]}} ->
Forms;
{ok, {_, [{abstract_code, no_abstract_code}]}} ->
throw(no_abstract_code)
end.

-spec beam_file(module()) -> binary().
beam_file(Module) ->
% code:which/1 cannot be used for cover_compiled modules
case code:get_object_code(Module) of
{_, Binary, _Filename} -> Binary;
error -> throw({object_code_not_found, Module})
end.

-spec compile_and_load_forms(erlang_form()) -> ok.
compile_and_load_forms(AbsCode) -> compile_and_load_forms(AbsCode, []).

-spec compile_and_load_forms(erlang_form(), compile_options()) -> ok.
compile_and_load_forms(AbsCode, Opts) ->
case compile:forms(AbsCode, Opts) of
{ok, ModName, Binary} ->
load_binary(ModName, Binary);
{ok, ModName, Binary, _Warnings} ->
load_binary(ModName, Binary)
end.

-spec compile_options(binary() | module()) -> compile_options().
compile_options(BeamFile) when is_binary(BeamFile) ->
case beam_lib:chunks(BeamFile, [compile_info]) of
{ok, {_, [{compile_info, Info}]}} ->
proplists:get_value(options, Info);
_ ->
[]
end;
compile_options(Module) ->
proplists:get_value(options, Module:module_info(compile)).

-spec rename_module(erlang_form(), module()) -> erlang_form().
rename_module([{attribute, Line, module, _OldName}|T], NewName) ->
[{attribute, Line, module, NewName}|T];
rename_module([H|T], NewName) ->
[H|rename_module(T, NewName)].

%%==============================================================================
%% Internal functions
%%==============================================================================

load_binary(Name, Binary) ->
case code:load_binary(Name, "", Binary) of
{module, Name} -> ok;
{error, Reason} -> exit({error_loading_module, Name, Reason})
end.

0 comments on commit 6680628

Please sign in to comment.