Build list of predicates that can be exported from a module

When creating a module and needing to create the exports list for use with module/2,3 it would be nice to have a simple predicate do the heavy lifting.

build_export(M,Exports) :-
    current_module(M), !,
    (
        setof(Predicate_indicator,local_predicate_generator(M:Predicate_indicator),Exports), !
    ;
        Exports = []
    ).
build_export(M,_) :-
    format(string(Lines),'Module `~w'' not loaded.~nPlease use consult/1 or use_module/1 to load the module.~n',[M]),
    print_message_lines(user_error,kind(error),[Lines]).

local_predicate_generator(PI) :-
    current_predicate(M:Name/Arity),
    local_predicate(M:Name/Arity),
    dcg_indicator(M:Name/Arity,PI).

local_predicate(M:Name/Arity) :-
    compound_name_arity(Head,Name,Arity),
    \+ predicate_property(M:Head,imported_from(_)).

dcg_indicator(M:Name/Arity0,PI) :-
    compound_name_arity(Head,Name,Arity0),
    (
        predicate_property(M:Head,non_terminal)
    ->
        Arity is Arity0 - 2,
        PI = M:Name//Arity
    ;
        PI = M:Name/Arity0
    ).

Example usage

Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.4-11-g1db629e24)

?- working_directory(_,'C:/Users/Groot/Documents').
true.

?- [module_exports].
true.

?- build_export(dcg_basics,Exports);true.
ERROR: Module `dcg_basics' not loaded.
Please use consult/1 or use_module/1 to load the module.

true ;
true.

?- consult(library(dcg/basics)).
true.

?- build_export(dcg_basics,Exports);true.
Exports = [mkval/3, mkval/4, alpha_to_lower//1, atom//1, blank//0, blanks//0, blanks_to_nl//0, digit//1, ... // ...|...] [write]
Exports = [mkval/3, mkval/4, alpha_to_lower//1, atom//1, blank//0, blanks//0, blanks_to_nl//0, digit//1, digits//1, dot//0, eos//0, exp//0, float//1, int_codes//1, integer//1, list_string_without//2, nonblank//1, nonblanks//1, number//1, prolog_id_cont//1, prolog_var_name//1, remainder//1, sign//1, string//1, string_without//2, white//0, whites//0, xdigit//1, xdigits//1, xinteger//1] ;
true.

Variation for names of unit tests.

build_test_names(M,Test_names) :-
    current_module(M), !,
    (
        setof(Name,test_name_generator(M,Name),Test_names), !
    ;
        Test_names = []
    ).

build_test_names(M,_) :-
    format(string(Lines),'Module `~w'' not loaded.~nPlease use consult/1 or use_module/1 to load the module.~n',[M]),
    print_message_lines(user_error,kind(error),[Lines]).

test_name_generator(M,Name) :-
    current_module(M), !,
    current_predicate(M:'unit test'/4),
    clause(M:'unit test'(Name,_,_,_),_).

Notes

Original code is from this post.

For the use of ;true added to the query see: Help: I want the whole answer

1 Like