= Managing your files and applications = == Adding files and directories == You can add files to the !RefactorErl database by calling the add function with either a filename as a string or a module name as an atom. Note that in the latter case, "ri" defaults to the current working directory (which you may work around by including a path in your singe-quoted atom). If you specify a directory instead of a regular filename, then it will be recursively traversed. You may just as well give a list of atoms or strings to add more files at once. All of the following example commands would add the same file: {{{ #!erlang cd(dir), ri:add(modname). ri:add('dir/modname'). ri:add(['dir/modname']). ri:add("dir/modname.erl"). ri:add("/current/dir/modname.erl"). ri:add("path_to_dir/dir"). }}} Usually, Erlang source files (having the extension .erl) are loaded into !RefactorErl. In addition, !RefactorErl is also capable of loading compiled .beam files. {{{ #!erlang ri:add("compiled.beam"). }}} Note that this feature is applicable only to those .beam files that were compiled with the debug_info option. Also note that the resulting file will be pretty printed by !RefactorErl. == Dropping files and directories == The module displays the progression of loading. Removing files from the database is similarly easy and also recursive. The following will equally work: {{{ #!erlang ri:drop(modname). ri:drop([modname]). ri:drop("dir/modname.erl"). ri:drop("/current/dir/modname.erl"). ri:drop("path_to_dir/dir"). }}} == Adding applications == Modules can be loaded as applications, but some configurations has to be made before. The configurations can be done manually by setting the enviromental nodes, or can be done automatically by using the [http://www.erlang.org/doc/man/make.html Emakefile] handling functions (beta version) of the tool. === Adding applications by manual configuration === The manually configuration can be done by using the {{{ri}}} or the {{{ris}}} module. Modules can be loaded as applications, but the base of your library has to be set before: {{{ #!erlang ri:addenv(appbase, "path/to/my/applib"). }}} If the application has additional include directories, then these directories has to be also set in advance: {{{ #!erlang ri:addenv(include, "path/to/my/incldir"). }}} If the application build process contains compile-time macros, then these macros also can be set: {{{ #!erlang %if it is only used in ifdef forms. ri:addenv(def, 'my_macro'). ri:addenv(def, {'my_macro', my_macro_value}). }}} If the include forms of the application contain OS based enviromental nodes, then these nodes can be set: {{{ #!erlang ri:addenv(env_var, {os_env_name, "os_env_path"}). }}} Let's see an example: The Emakefile has the following contents: {{{ #!erlang {"/home/user/dev/lib/app1/src/*", [{i,"/home/user/dev/lib/"}, {d,'MY_MACRO', "ITS_VALUE"}, {outdir,"/home/user/dev/lib/app1/ebin"}]}. {"/home/user/dev/lib/app2/src/*", [{i,"/home/user/dev/lib/"}, {d,'MY_MACRO', "ITS_VALUE"}, {outdir,"/home/user/dev/lib/app2/ebin"}]}. {"/home/user/dev/lib/app3/src/*", [{i,"/home/user/dev/lib/share/include/"}, {i,"/home/user/dev/lib/"}, {outdir,"/home/user/dev/lib/app3/ebin"}]}. }}} To add {{{app1}}}, {{{app2}}}, {{{app3}}} to !RefactorErl you should do the followings: {{{ #!erlang % add app1, app2 with the same configuration ri:addenv(appbase, "/home/user/dev/lib/"), ri:addenv(def, {'MY_MACRO', "ITS_VALUE"}), Apps = [app1, app2], [ri:add(home, App) || App <- Apps]. % add app3 after the configuration has been modified ri:delenv(def), ri:addenv(include, "/home/user/dev/lib/share/include/"), ri:add(home, app3). }}} You can check the already given application base directories by listing all of the enviromental nodes: {{{ #!erlang ri:envs(). }}} It is possible to delete the defined environment variables: {{{ #!erlang ri:delenv(include). }}} Or you can set an environmental variable to another value: {{{ #!erlang ri:setenv(env_name, "path/to/new_value"). }}} The following enviromental nodes can be set via the {{{ri}}} module: {{{output}}}: Where does !RefactorErl write changes in? {{{appbase}}}: The list of the used application based directories. {{{include}}}: The list of the used include directories. {{{def}}}: The list of the compile-time macros. {{{env_var}}}: The list of the OS based enviromental nodes. === Adding applications using the Emakefile handling functions === Applications with their proper configurations (such as include paths, macros), or only the configurations, which are defined in an Emakefile, can be added by executing only one command. The given Emakefile is parsed then the configurations and the adding procedure are handled automatically by the tool. The functionality is available in the ri module and also available in the ris module. By executing one of the following commands: {{{ #!erlang EmakeFilePath = "/absolute_path_to_the_emakefile", ri:add_by_emakefile(EmakefilePath). % whether a list of Emakefiles are present. EmakeFiles = ["/absolute_path_to_the_emakefile1", "/absolute_path_to_the_emakefile2"], ri:add_by_emakefile(EmakeFiles). }}} the applications which are defined in the given Emakefile(s) are loaded into the database. Please note, that * the configurations, which are defined in the Emakefile, only stored temporary, while the adding procedure has not been finished; * if the Emakefile contains relative path, then it will be converted absolute by using the path of the Emakefile as base. If your apllications have been loaded by using {{{ri:add_by_emakefile/1}}} and any of the applications uses irregular include path or compile-time macro, then these applications should be updated by using {{{ri:add_by_emakefile/1}}}, or by loading the configuration {{{ri:load_configuration/1}}} then by executing {{{ri:database_synchronization/0}}}.\\ If the loaded configuration is not needed further then it may be unloaded by executing {{{ri:unload_configuration/1}}}. Applications can be dropped from the database in the same way as the normal files. === Adding applications using unified build tools ri:add_app(1|2) === The main goal of this approach to make the application loading method simpler to the end user. The loading of files are simplified to the ri:add_app(1|2) interface that is extensible and can support various build tools. Control flow details {{{#!erlang ri:add_app(1|2) ==> reflib_ui_router:request/2 ==> reflib_ui:add_app/3 ==> ==> refcore_apploader:add_app/3 ==> refcore_confparser:parser/2 ==> refcore_$(parser):parse/2 + refcore_apploader:add_files $(parser) : [rebar, emakefile, erlang_mk, makefile] }}} The confparser tries to recognize the parser primarily by the name of the file if the passed path is a regular file (rebar, Emakefile, erlang.mk, Makefile). When the passed path is a directory the following priority takes place in detecting the appropriate parser : rebar, rebar.config, Emakefile, erlang.mk, Makefile. See the configuration of various parsers below: see [#point1 Rebar Parser] see [#point2 Emakefile Parser] see [#point3 erlang_mk Parser] see [#point4 Makefile Parse] [=#point1] ==== Rebar Parser ==== The application directory layout must follow the Rebar and OTP conventions (src, priv, include, ebin), for further details please refer to https://github.com/rebar/rebar/wiki. The rebar parser reads recursively the directories and the rebar.config files. The subdirectories inhert the the rebar.config options from the parent directories the rebar.config options from the actual directory may overrides them. Interface options refcore_rebar_parser:parse/2 * BaseDirectoryOrRebarPath - Application base dir or the path including the rebar.config file * UserOptions - user properties [{rebar_load_tests, true}] The parser extracts the following options from rebar.config file: * lib_dirs - additional library directories to add to the code path * erl_first_files - rrlang files to compile before the rest * erl_opts - erlang compiler options * sub_dirs - subdirectories * deps_dir - location of dependencies. * deps - dependencies When the user property rebar_load_tests is set to true the tests related options are also loaded: * ct_dir - test SUITEs location * ct_extra_params - option to pass extra parameters when launching Common Test (-dir, -include, -spec ) * eunit_first_files - same as erl_first_files, but used only when running 'eunit' * eunit_compile_opts - additional compile options for eunit. erl_opts is also used (-dir, -include, -spec ), * qc_first_files - same as erl_first_files, but used only when running 'qc' * qc_compile_opts - additional compile options for qc. erl_opts is also used (-dir, -include, -spec ) Further details and a more complete example of the rebar.config file is available at: https://github.com/rebar/rebar/blob/master/rebar.config.sample [=#point2 ] ==== Emakefile Parser ==== The Emakefile Parser consults the given Emakefile and extracts the files and other information (appbase,def). Example Emakefile: {{{#!erlang {'src/hello', [debug_info, {i,"include"}, {outdir, "ebin"} ] }. {'src/*', [debug_info] }. }}} Further reading: http://www.erlang.org/doc/man/make.html. refcore_emakefile_parser:parse/2 * DirectoryOrEmakefilePath - Path to the Emakefile or to the application directory * _ - second argument is ignored during the Emakefile parsing. [=#point3 ] ==== erlang_mk Parser ==== Further reading: https://github.com/ninenines/erlang.mk [=#point4 ] ==== Makefile Parser ==== Further reading: http://www.gnu.org/software/make/manual/make.html == Refreshing your database == If your files has been changed in the disk, since the last load, then these files may be re-added to the database to gather fresh information about the files from the tool. This can be easily done, by executing one of the following commands: {{{ #!erlang ri:database_synchronization(). ris:database_synchronization(). }}} == Gathering information about your database == For convenience, both the filenames and the directory names can be given as atoms as well as strings. The list of loaded files can be obtained by calling {{{ #!erlang ri:ls(). }}} This call also displays the status of the loaded files (error or no_error). If the module m is loaded, {{{ #!erlang ri:ls(m). }}} will give information about the functions, records and macros in the file. The contents of a file can be listed by {{{ #!erlang ri:cat(ModFile). }}} The content of a function can be listed by {{{ #!erlang ri:cat(ModFile, {FunName,Arity}). }}}