Module smerl

Smerl: Simple Metaprogramming for Erlang.

Copyright © Yariv Sadan 2006-2007

Authors: Yariv Sadan (yarivsblog@gmail.com) [web site: http://yarivsblog.com].

Description

Smerl: Simple Metaprogramming for Erlang

Smerl is an Erlang library that simplifies the creation and manipulation of Erlang modules in runtime.

You don't need to know Smerl in order to use ErlyWeb; Smerl is included in ErlyWeb because ErlyWeb uses it internally.

Smerl uses Erlang's capabilities for hot code swapping and abstract syntax tree transformations to do its magic. Smerl is inspired by the rdbms_codegen.erl module in the RDBMS application written by Ulf Wiger. RDBMS is part of Jungerl (http://jungerl.sf.net).

Here's a quick example illustrating how to use Smerl:
   test_smerl() ->
     M1 = smerl:new(foo),
     {ok, M2} = smerl:add_func(M1, "bar() -> 1 + 1."),
     smerl:compile(M2),
     foo:bar(),   % returns 2``
     smerl:has_func(M2, bar, 0). % returns true

New functions can be expressed either as strings of Erlang code or as abstract forms. For more information, read the Abstract Format section in the ERTS User's guide (http://erlang.org/doc/doc-5.5/erts-5.5/doc/html/absform.html#4).

Using the abstract format, the 3rd line of the above example would be written as
      {ok,M2} = smerl:add_func(M1, {function,1,bar,0,
                               [{clause,1,[],[],
                                [{op,1,'+',{integer,1,1},{integer,1,1}}]}]).

The abstact format may look more verbose in this example, but it's also easier to manipulate in code.

Data Types

func_form()

abstract datatype: func_form()

The abstract form for the function, as described in the ERTS Users' manual.

meta_mod()

abstract datatype: meta_mod()

A data structure holding the abstract representation for a module.

Function Index

add_func/2Add a new function to the meta_mod and return the resulting meta_mod.
add_func/3Add a new function to the meta_mod and return the new MetaMod record.
compile/1Compile the module represented by the meta_mod and load the resulting BEAM into the emulator.
compile/2Compile the module represented by the meta_mod and load the resulting BEAM into the emulator.
curry/2Get the curried form for the function and parameter(s).
curry/4Curry the function from the module with the given param(s).
curry/5Curry the function from the module or meta_mod with the param(s), and return its renamed form.
curry_add/3Add the curried form of the function in the meta_mod with its curried form.
curry_add/4Add the curried form of the function in the meta_mod with its curried form.
curry_add/5Curry the function form from the meta_mod, then add it to the other meta_mod with a new name.
curry_add/6Curry the function in the module, rename the curried form, and add it to the meta_mod.
curry_replace/3Replace the function in the meta_mod with its curried form.
curry_replace/4Replace the function in the meta_mod with its curried form.
embed_all/2Apply the embed_params function with the list of {Name, Value} pairs to all forms in the meta_mod.
embed_params/2This function takes a function form and list of name/value pairs, and replaces all the function's parameters that whose names match an element from the list with the predefined value.
embed_params/4Apply embed_params/2 to a function from the meta_mod and add the resulting function to the meta_mod, and return the resulting meta_mod.
embed_params/5Apply embed_params/2 to the function from the meta_mod and add the resulting function to the meta_mod after renaming the function.
extend/2extend/2 Add all the parent module's functions that are missing from the child module to the child module.
extend/3Similar to extend/2, with the addition of the 'ArityDiff' parameter, which indicates the difference in arities Smerl should use when figuring out which functions to generate based on the modules' exports.
extend/4
for_file/1Equivalent to for_file(SrcFilePath, []).
for_file/2Equivalent to for_file(SrcFilePath, IncludePaths, []).
for_file/3Create a meta_mod for a module from its source file.
for_module/1Equivalent to for_module(ModuleName, []).
for_module/2Equivalent to for_module(ModuleName, IncludePaths, []).
for_module/3Create a meta_mod tuple for an existing module.
get_attribute/2Get the value a the module's attribute.
get_export_all/1Get the export_all value for the module.
get_exports/1Return the list of exports in the meta_mod.
get_forms/1Return the list of function forms in the meta_mod.
get_func/3Get the form for the function with the specified arity in the meta_mod.
get_module/1Return the module name for the meta_mod.
has_func/3Check whether the meta_mod has a function with the given name and arity.
new/1Create a new meta_mod for a module with the given name.
remove_export/3Remove the export from the list of exports in the meta_mod.
remove_func/3Try to remove the function from the meta_mod.
rename/2Change the name of the function represented by the form.
replace_func/2 Replace an existing function with the new one.
set_export_all/2Set the export_all value for the module.
set_exports/2Set the meta_mod's export list to the new list.
set_forms/2
set_module/2Set the meta_mod's module name.
to_src/1Return the pretty-printed source code for the module.
to_src/2Write the pretty printed source code for the module to the file with the given file name.

Function Details

add_func/2

add_func(MetaMod :: meta_mod(), Form :: func_form() | string()) ->
            {ok, NewMod :: meta_mod()} | {error, parse_error}

Add a new function to the meta_mod and return the resulting meta_mod. This function calls add_func(MetaMod, Form, true).

add_func/3

add_func(MetaMod :: meta_mod(),
         Func :: func_form() | string(),
         Export :: boolean()) ->
            {ok, NewMod :: meta_mod()} | {error, parse_error}

Add a new function to the meta_mod and return the new MetaMod record. Export is a boolean variable indicating if the function should be added to the module's exports.

compile/1

compile(MetaMod :: meta_mod()) -> ok | {error, Error}

Compile the module represented by the meta_mod and load the resulting BEAM into the emulator. This function calls compile(MetaMod, [report_errors, report_warnings]).

compile/2

compile(MetaMod :: meta_mod(), Options :: [term()]) ->
           ok | {error, Error}

Compile the module represented by the meta_mod and load the resulting BEAM into the emulator. 'Options' is a list of options as described in the 'compile' module in the Erlang documentation.

If the 'outdir' option is provided, the .beam file is written to the destination directory.

curry/2

curry(Form :: func_form(), Param :: term() | [term()]) ->
         {ok, NewForm :: func_form()} | {error, Err}

Get the curried form for the function and parameter(s). Currying involves replacing one or more of the function's leading parameters with predefined values.

curry/4

curry(ModName :: atom(),
      Name :: atom(),
      Arity :: integer(),
      Params :: term() | [term()]) ->
         {ok, NewForm} | {error, Err}

Curry the function from the module with the given param(s)

curry/5

curry(Module :: atom() | meta_mod(),
      Name :: atom(),
      Arity :: integer(),
      Params :: term() | [terms()],
      NewName :: atom()) ->
         {ok, NewForm} | {error, Err}

Curry the function from the module or meta_mod with the param(s), and return its renamed form.

curry_add/3

curry_add(MetaMod :: meta_mod(),
          Form :: func_form(),
          Params :: term() | [term()]) ->
             {ok, NewMetaMod :: meta_mod()} | {error, Err}

Add the curried form of the function in the meta_mod with its curried form.

curry_add/4

curry_add(MetaMod :: meta_mod(),
          Name :: atom(),
          Arity :: integer(),
          Params :: term() | [term()]) ->
             {ok, NewMetaMod :: meta_mod()} | {error, Err}

Add the curried form of the function in the meta_mod with its curried form.

curry_add/5

curry_add(MetaMod :: meta_mod(),
          Name :: atom(),
          Arity :: integer(),
          Params :: [term()],
          NewName :: atom()) ->
             {ok, NewMod :: meta_mod()} | {error, Err}

Curry the function form from the meta_mod, then add it to the other meta_mod with a new name.

curry_add/6

curry_add(MetaMod :: meta_mod(),
          Module :: atom() | meta_mod(),
          Name :: atom(),
          Arity :: integer(),
          Params :: term() | [term()],
          NewName :: atom()) ->
             {ok, NewMod :: meta_mod()} | {error, Error}

Curry the function in the module, rename the curried form, and add it to the meta_mod.

curry_replace/3

curry_replace(MetaMod :: meta_mod(),
              Form :: func_form(),
              Params :: term() | [term()]) ->
                 {ok, NewMetaMod :: meta_mod()} | {error, Err}

Replace the function in the meta_mod with its curried form.

curry_replace/4

curry_replace(MetaMod :: meta_mod(),
              Name :: atom(),
              Arity :: integer(),
              Params :: term() | list()) ->
                 {ok, NewMetaMod :: meta_mod()} | {error, Err}

Replace the function in the meta_mod with its curried form.

embed_all/2

embed_all(MetaMod :: meta_mod(),
          Vals :: [{Name :: atom(), Value :: term()}]) ->
             NewMetaMod :: meta_mod()

Apply the embed_params function with the list of {Name, Value} pairs to all forms in the meta_mod. Exports for functions whose arities change due to the embedding are preserved.

embed_params/2

embed_params(Func :: func_form(),
             Vals :: [{Name :: atom(), Value :: term()}]) ->
                NewForm :: func_form()

This function takes a function form and list of name/value pairs, and replaces all the function's parameters that whose names match an element from the list with the predefined value.

embed_params/4

embed_params(MetaMod :: meta_mod(),
             Name :: atom(),
             Arity :: integer(),
             Values :: proplist()) ->
                {ok, NewMetaMod :: meta_mod()} | {error, Err}

Apply embed_params/2 to a function from the meta_mod and add the resulting function to the meta_mod, and return the resulting meta_mod.

embed_params/5

embed_params(MetaMod :: meta_mod(),
             Name :: atom(),
             Arity :: integer(),
             Values :: proplist(),
             NewName :: atom()) ->
                {ok, NewMetaMod :: meta_mod()} | {error, Err}

Apply embed_params/2 to the function from the meta_mod and add the resulting function to the meta_mod after renaming the function.

extend/2

extend(Parent :: atom() | meta_mod(),
       Child :: atom() | meta_mod()) ->
          NewChildMod :: meta_mod()

extend/2 Add all the parent module's functions that are missing from the child module to the child module. The new functions in the child module are shallow: they have the name and arity as their corresponding functions in the parent meta_mod, but instead of implementing their logic they call the parent module's functions.

extend/3

extend(Parent :: atom() | meta_mod(),
       Child :: atom() | meta_mod(),
       ArityDiff :: integer()) ->
          NewChildMod :: meta_mod()

Similar to extend/2, with the addition of the 'ArityDiff' parameter, which indicates the difference in arities Smerl should use when figuring out which functions to generate based on the modules' exports. This is sometimes useful when calling extend() followed by embed_all().

extend/4

extend(Parent, Child, ArityDiff, Options) -> any()

for_file/1

for_file(SrcFilePath) -> any()

Equivalent to for_file(SrcFilePath, []).

for_file/2

for_file(SrcFilePath, IncludePaths) -> any()

Equivalent to for_file(SrcFilePath, IncludePaths, []).

for_file/3

for_file(SrcFilePath :: string(),
         IncludePaths :: [string()],
         Macros :: [{atom(), term()}]) ->
            {ok, meta_mod()} | {error, invalid_module}

Create a meta_mod for a module from its source file.

for_module/1

for_module(ModuleName) -> any()

Equivalent to for_module(ModuleName, []).

for_module/2

for_module(ModuleName, IncludePaths) -> any()

Equivalent to for_module(ModuleName, IncludePaths, []).

for_module/3

for_module(ModuleName :: atom() | string(),
           IncludePaths :: [string()],
           Macros :: [{atom(), term()}]) ->
              {ok, meta_mod()} | {error, Error}

Create a meta_mod tuple for an existing module. If ModuleName is a string, it is interpreted as a file name (this is the same as calling {link smerl:for_file}). If ModuleName is an atom, Smerl attempts to find its abstract represtation either from its source file or from its .beam file directly (if it has been compiled with debug_info). If the abstract representation can't be found, this function returns an error.

The IncludePaths parameter is used when 'ModuleName' is a file name.

get_attribute/2

get_attribute(MetaMod :: meta_mod(), AttName :: atom()) ->
                 {ok, Val} | error

Get the value a the module's attribute.

get_export_all/1

get_export_all(MetaMod :: meta_mod) -> true | false

Get the export_all value for the module.

get_exports/1

get_exports(MetaMod :: meta_mod()) ->
               [{FuncName :: atom(), Arity :: integer()}]

Return the list of exports in the meta_mod.

get_forms/1

get_forms(MetaMod :: meta_mod()) -> [Form]

Return the list of function forms in the meta_mod.

get_func/3

get_func(MetaMod :: meta_mod() | atom(),
         FuncName :: atom(),
         Arity :: integer()) ->
            {ok, func_form()} | {error, Err}

Get the form for the function with the specified arity in the meta_mod.

get_module/1

get_module(MetaMod) -> any()

Return the module name for the meta_mod.

has_func/3

has_func(MetaMod :: meta_mod(),
         FuncName :: atom(),
         Arity :: integer()) ->
            bool()

Check whether the meta_mod has a function with the given name and arity.

new/1

new(Module :: atom()) -> meta_mod()

Create a new meta_mod for a module with the given name.

remove_export/3

remove_export(MetaMod :: meta_mod(),
              FuncName :: atom(),
              Arity :: integer()) ->
                 NewMod :: meta_mod()

Remove the export from the list of exports in the meta_mod.

remove_func/3

remove_func(MetaMod :: meta_mod(),
            FuncName :: string(),
            Arity :: integer()) ->
               NewMod :: meta_mod()

Try to remove the function from the meta_mod. If the function exists, the new meta_mod is returned. Otherwise, original meta_mod is returned.

rename/2

rename(Form :: func_form(), NewName :: atom()) ->
          {ok, NewForm :: func_form()} | {error, Err}

Change the name of the function represented by the form.

replace_func/2

replace_func(MetaMod :: meta_mod(),
             Function :: string() | func_form()) ->
                {ok, NewMod :: meta_mod()} | {error, Error}

Replace an existing function with the new one. If the function doesn't exist the new function is added to the meta_mod. This is tantamount to calling smerl:remove_func followed by smerl:add_func.

set_export_all/2

set_export_all(MetaMod :: meta_mod(), Val :: true | false) ->
                  NewMetaMod :: meta_mod()

Set the export_all value for the module.

set_exports/2

set_exports(MetaMod :: meta_mod(),
            Exports :: [{FuncName :: atom(), Arity :: integer()}]) ->
               NewMod :: meta_mod()

Set the meta_mod's export list to the new list.

set_forms/2

set_forms(MetaMod, Forms) -> any()

set_module/2

set_module(MetaMod :: meta_mod(), NewName :: atom()) ->
              NewMod :: meta_mod()

Set the meta_mod's module name.

to_src/1

to_src(MetaMod :: meta_mod()) -> string()

Return the pretty-printed source code for the module.

to_src/2

to_src(MetaMod :: meta_mod(), FileName :: string()) ->
          ok | {error, Error}

Write the pretty printed source code for the module to the file with the given file name.


Generated by EDoc