Changes between Version 20 and Version 21 of ErlangShellInterface


Ignore:
Timestamp:
Sep 17, 2012, 2:41:10 PM (12 years ago)
Author:
manualwiki
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • ErlangShellInterface

    v20 v21  
     1{{{#!comment 
     2[[PageOutline]] 
     3 
     4= !RefactorErl Console Interface = 
     5 
     6When running !RefactorErl, you can control the tool via function calls typed into the Erlang shell. !RefactorErl has many features, and is quite a complex system with dozen of functions whose name we do not expect our users to remember. In order to ease and unify the command-level access to all the analysis and refactoring functionality, we have designed a group of Erlang functions that cover the most frequently used features of the tool. The module these functions are located in is called {{{ri}}}, you can use this module to interact easily with the tool. You can add files/directories to the database, run [[SemanticQuery|semantic queries]], create backups, or even do [[RefactoringSteps|transformations]] via this Erlang-level interface. 
     7 
     8== Command-line help == 
     9 
     10Help can be acquired in {{{ri}}} with 
     11 
     12{{{ 
     13#!erlang 
     14ri:help(). 
     15}}} 
     16 
     17or even shorter as 
     18 
     19{{{ 
     20#!erlang 
     21ri:h(). 
     22}}} 
     23 
     24This function lists several topics, on which further help is available by 
     25 
     26{{{ 
     27#!erlang 
     28ri:h(Topic). 
     29}}} 
     30 
     31If you need specific help with a function, simply call it with an {{{_h}}} postfix to the name. For example, help for the function add is available by calling 
     32 
     33{{{ 
     34#!erlang 
     35ri:add_h() 
     36}}} 
     37 
     38 
     39== Compiling the tool == 
     40 
     41The tool can be compiled/recompiled by invoking 
     42 
     43{{{ 
     44#!erlang 
     45ri:build(). 
     46}}} 
     47 
     48You can also specify build parameters, but this feature is mostly applied through the development, so please find the module documentation for the details. Note that this build function tries to compile the [[NifDB|NIF graph representation]] as well, if these have not been compiled yet. If you want to prevent this, you can use the {{{no_nif}}} build parameter. 
     49 
     50== Managing files == 
     51 
     52You can add files to the !RefactorErl database by calling the 
     53add function with either a filename as a string or a module name as an atom. 
     54Note that in the latter case, "ri" defaults to the current working directory 
     55(which you may work around by including a path in your singe-quoted atom). 
     56If you specify a directory instead of a regular filename, then it will be recursively 
     57traversed. You may just as well give a list of atoms or strings to add more files 
     58at once. All of the following example commands would add the same file: 
     59 
     60{{{ 
     61#!erlang 
     62 cd(dir), ri:add(modname). 
     63 ri:add('dir/modname'). 
     64 ri:add(['dir/modname']). 
     65 ri:add("dir/modname.erl"). 
     66 ri:add("/current/dir/modname.erl"). 
     67 ri:add("path_to_dir/dir"). 
     68}}} 
     69 
     70The module displays the progression of loading. 
     71Removing files from the database is similarly easy and also recursive.  
     72The following will equally work: 
     73 
     74{{{ 
     75#!erlang 
     76 ri:drop(modname). 
     77 ri:drop([modname]). 
     78 ri:drop("dir/modname.erl"). 
     79 ri:drop("/current/dir/modname.erl"). 
     80 ri:drop("path_to_dir/dir"). 
     81}}} 
     82 
     83Modules can be loaded as applications, but the base of your library has to 
     84be set before: 
     85 
     86{{{ 
     87#!erlang 
     88ri:addenv(appbase, "path/to/my/applib"). 
     89}}} 
     90 
     91You can check the already given application base directories: 
     92 
     93{{{ 
     94#!erlang 
     95ri:envs(). 
     96}}} 
     97 
     98Let's see an example: 
     99 
     100{{{ 
     101#!erlang 
     102% Here 'appbase' contains 'usr'. 
     103(refactorerl@localhost)18> ri:envs(). 
     104output = original 
     105appbase = "/usr/local/lib/erlang/lib" 
     106 
     107(refactorerl@localhost)19> ri:add(usr, synatx_tools). 
     108Application synatx_tools not found under usr 
     109not_found 
     110 
     111% 'appbase' contains 'usr', so syntax_tools will be loaded from 
     112% '/usr/local/lib/erlang/lib' 
     113(refactorerl@localhost)20> ri:add(usr, syntax_tools). 
     114Adding: /usr/local/lib/erlang/lib/syntax_tools-1.6.7.1/src 
     115... 
     116}}} 
     117 
     118You can also set include directories to your include files using: 
     119 
     120{{{ 
     121#!erlang 
     122ri:addenv(include, "path/to/my/include"). 
     123}}} 
     124 
     125It is possible to delete the defined environment variables: 
     126 
     127{{{ 
     128#!erlang 
     129ri:delenv(include). 
     130}}} 
     131 
     132Or you can set an environmental variable to another value: 
     133{{{ 
     134#!erlang 
     135ri:setenv(env_name, "path/to/new_value"). 
     136}}} 
     137 
     138 
     139For convenience, both the filenames and the directory names can be given 
     140as atoms as well as strings. 
     141The list of loaded files can be obtained by calling 
     142 
     143{{{ 
     144#!erlang 
     145ri:ls(). 
     146}}} 
     147 
     148This call also displays the status of the loaded files (error or no_error). 
     149If the module m is loaded, 
     150 
     151{{{ 
     152#!erlang 
     153ri:ls(m). 
     154}}} 
     155 
     156will give information about the functions, records and macros in the file. 
     157The contents of a file can be listed by 
     158 
     159{{{ 
     160#!erlang 
     161ri:cat(ModFile). 
     162}}} 
     163 
     164The content of a function can be listed by 
     165 
     166{{{ 
     167#!erlang 
     168ri:cat(ModFile, {FunName,Arity}). 
     169}}} 
     170 
     171Usually, Erlang source files (having the extension 
     172.erl) are loaded into !RefactorErl. In addition, !RefactorErl is also capable of 
     173loading compiled .beam files. 
     174 
     175{{{ 
     176#!erlang 
     177ri:add("compiled.beam"). 
     178}}} 
     179 
     180Note that this feature is applicable only to those .beam files that were compiled 
     181with the debug_info option. Also note that the resulting file will be pretty 
     182printed by !RefactorErl. 
     183 
     184== Using transformations == 
     185Transformations can be called using their abbreviated 
     186names, and the list of required parameters. These commands are listed in 
     187[[RefactoringSteps|refactoring functionalities]]. 
     188There is another way to call a transormation. This way let the user to 
     189choose: user wants to specify all of arguments or not. There are lots of cases 
     190when the user can not specify all of the required arguments. In this case the 
     191tool can help the user with interactions. The tool ask questions and the user 
     192has to answer it to specify the missing arguments. The interactions also work if 
     193there are problems with the given arguments. 
     194 
     195== Manipulating the graph == 
     196You can reset the database by invoking 
     197 
     198{{{ 
     199#!erlang 
     200ri:reset(). 
     201}}} 
     202 
     203This will remove all loaded files. This function should be called if the graph 
     204gets corrupted. 
     205You can add a checkpoint and can create a backup using 
     206 
     207{{{ 
     208#!erlang 
     209ri:backup(). 
     210}}} 
     211 
     212If a previous backup is needed to be load, you can load it using 
     213 
     214{{{ 
     215#!erlang 
     216ri:restore(NeededBackup). 
     217}}} 
     218 
     219If the transformations you have performed are not satisfactory, you can go 
     220back to the previous checkpoint using 
     221 
     222{{{ 
     223#!erlang 
     224ri:undo(). 
     225}}} 
     226 
     227Notice, that restore only modify the contents of the database, but undo 
     228modifies the contents of the files on the disk, too. 
     229  
     230If the files, which had been loaded to the database, has been changed on the disk, 
     231then you can reload them to the  database by calling 
     232 
     233{{{ 
     234#!erlang 
     235ri:database_synchronization(). 
     236}}} 
     237 
     238You can initiate the database synchronization from the start up script, too.  
     239See [[StartUp| Starting the tool]] for further details. 
     240 
     241== Inspecting the graph == 
     242You can draw the semantic representation graph of !RefactorErl by calling 
     243 
     244{{{ 
     245#!erlang 
     246ri:graph(). 
     247}}} 
     248 
     249This function produces a .dot file (by default, graph.dot, although this can be 
     250customised), which can be transformed to several visual formats using Graphviz. 
     251One of these transformations is available from !RefactorErl for convenience: 
     252 
     253{{{ 
     254#!erlang 
     255ri:svg(). 
     256}}} 
     257 
     258The representation can be altered: 
     259 
     260{{{ 
     261#!erlang 
     262ri:svg(OutFile, Filter). 
     263}}} 
     264 
     265where Filter is one of the following:\\ 
     266* '''all''': default, all edges except environmental ones are shown.\\ 
     267* '''syn''': only syntactic edges are shown.\\ 
     268* '''sem''': only semantic edges are shown.\\ 
     269* '''lex''': only lexical edges are shown.\\ 
     270* '''all_env''': all edges are shown, no filtering.\\ 
     271* '''ctx''': context related edges are shown.\\ 
     272* '''not_lex''': all edges except lexical ones are shown.\\ 
     273* '''dataflow''': dataflow related edges are shown.\\ 
     274* '''a list of the above''': shows the union of the designated subgraphs.\\ 
     275 
     276== Using queries == 
     277Queries can be invoked by either 
     278 
     279{{{ 
     280#!erlang 
     281ri:q(Query). 
     282}}} 
     283 
     284or 
     285 
     286{{{ 
     287#!erlang 
     288ri:q(Module, Regexp, Query). 
     289}}} 
     290 
     291The former is applicable when a query starts generally, such as 
     292 
     293{{{ 
     294#!erlang 
     295ri:q("mods.funs.name"). 
     296}}} 
     297 
     298For those queries that begin from a selected position (these queries start 
     299with "@" when used from Emacs), the second variant is required. As the console 
     300cannot mark a position, the first and the second component indicate the starting 
     301point for the query. The following example shows how to get all the variables 
     302used in the body of the function '''f/2''' from the module '''m'''. 
     303 
     304{{{ 
     305#!erlang 
     306ri:q(m, "f\\(X, Y\\)", "@fun.var"). 
     307}}} 
     308 
     309Additional options can be given to a [[SemanticQuery|semantic query]] in a proplist as the last 
     310argument. The following arguments are currently recognized:\\ 
     311* '''{out,!FileName}''': write the textual output of a query to a file.\\ 
     312* '''linenum''': prepends match sites with file and line number information.\\ 
     313similar to '''grep -n'''. 
     314The following example outputs all defined functions with line numbers to a 
     315file named result.txt. 
     316 
     317{{{ 
     318#!erlang 
     319ri:q("mods.funs",[linenum,{out,"result.txt"}]). 
     320}}} 
     321 
     322There is a [[SemanticQuery|semantic queries]] page, where you can learn more about this topic. 
     323 
     324Semantic queries may take for a long time. A list of the currently running queries can be queried using  
     325 
     326{{{ 
     327#!erlang 
     328ri:get_running_queries(). 
     329}}} 
     330 
     331A running query can be aborted by calling  
     332 
     333{{{ 
     334#!erlang 
     335ri:kill_query(QueryID). 
     336}}} 
     337 
     338== Analysis == 
     339=== Dependency analysis on function or module level === 
     340There is a [[/wiki/Dependency/Functions|Module and Function Dependencies]] page, where you can learn more about this topic.  
     341 
     342The command-line interface offers two interface functions, which are: 
     343 
     3441. For drawing: 
     345{{{#!erlang 
     346ri:draw_dep/1 
     347}}} 
     3482. For printing the result to stdout: 
     349{{{#!erlang 
     350ri:print_dep/1 
     351}}} 
     352 
     353==== Options ==== 
     354 
     355The parameter of the interface functions is a proplist setting the options of the analysis. The available options are: 
     356 
     357 * {{{level (mod | func)}}} 
     358    The level of the dependency query (module or function). 
     359 * {{{type (all | cycles)}}} 
     360    Whether the investigation should be done on the whole graph, or just on the cyclic part (if exists). When printing out the cycles, type {{{all}}} returns graph nodes, while {{{cycles}}} returns names. 
     361 * {{{otp (true | false)}}} 
     362    Whether Erlang/OTP standard modules should be included in the analysis or not. 
     363 * {{{gnode}}} 
     364    List of entity or entities that should be the starting point of the analysis. Especially at function level, the list is compulsory when the functions are identified by their module, name, arity. 
     365 * exception 
     366    List of entities excluded from the analysis. 
     367 * leaves 
     368    List of those entities which should be included in the analysis, but their children should not (and consequently the children become exceptions). 
     369 * {{{dot}}} 
     370    The file path of the generated {{{.dot}}} graph description. Unless it is a non-existing absolute path, the graph will be placed into the {{{./dep_files}}} directory. This option is only available when using {{{draw_dep}}}. 
     371 
     372You can specify entities either with graph nodes (such as {{{{'$gn', func, 123}}}}) or with their identifier. Modules can be specified with their names as atoms (e.g. 'mnesia'), while functions are specified by their MFA descriptor as a string (e.g. "io:format/2") 
     373 
     374==== Examples for listing results ==== 
     375 
     376* Checking for cycles in module level. 
     377{{{#!erlang 
     378ri:print_dep([{level, mod}, {type, all}]). 
     379}}} 
     380   
     381 
     382* Checking for cycles in function level, and printing out names of the functions (Module:Function/Arity). 
     383{{{#!erlang 
     384ri:print_dep([{level, func}, {type, cycles}]). 
     385}}} 
     386{{{#!erlang 
     387  [['foo:fv4/1','foo:fv4/1'], 
     388  ['test3:p/1','test:fv6/1','test3:p/1'], 
     389  ['cycle4:f4/1','cycle3:f3/1','cycle4:f4/1'], 
     390  ['cycle2:fv2/1','cycle1:fv1/0','cycle2:fv2/1'], 
     391  ['test:fv5/1','test:fv4/2','test:fv5/1'], 
     392  ['cycle4:f5/1','cycle3:f6/1','cycle4:f5/1']] 
     393}}} 
     394 
     395 
     396* Checking for cycles in function level, and printing out the graph nodes of the functions. 
     397{{{#!erlang 
     398ri:print_dep([{level, func}, {type, all}]). 
     399}}} 
     400{{{#!erlang 
     401  {"6 cycle(s)", 
     402  {[[{'$gn',func,28},{'$gn',func,28}],  
     403  [{'$gn',func,29},{'$gn',func,37},{'$gn',func,29}], 
     404  [{'$gn',func,7},{'$gn',func,9},{'$gn',func,7}], 
     405  [{'$gn',func,2},{'$gn',func,1},{'$gn',func,2}], 
     406  [{'$gn',func,36},{'$gn',func,35},{'$gn',func,36}], 
     407  [{'$gn',func,8},{'$gn',func,6},{'$gn',func,8}]]} 
     408}}} 
     409 
     410* Checking for cycles in module level from a given node 
     411{{{#!erlang 
     412ri:print_dep([{level, mod}, {gnode, {'$gn', module, 24}}]).  
     413}}} 
     414{{{#!erlang 
     415  {true,[[{'$gn',module,24}, 
     416          {'$gn',module,25}, 
     417          {'$gn',module,24}]]} 
     418}}} 
     419 
     420* Checking for cycles in function level from a node given with its identifier 
     421{{{#!erlang 
     422ri:print_dep([{level, func}, {gnode, ["cycle4:f5/1"]}]). 
     423}}} 
     424 
     425=== Function block dependencies === 
     426In large systems, sets of applications (which themselves consist of several modules) are organised into bigger units; keeping in line with Ericsson terminology, we shall call these function blocks. We also seek dependencies between them, which is conceptually similar to dependencies between modules: a function block FB1 is dependent on a function block FB2 if a module from FB1 is dependent on one from FB2. This examination is also available from the command-line interface. You can read about the usage and about the topic on [[/wiki/Dependency/FunctionBlocks|Function blocks]] page.  
     427 
     428=== Logical layers analysis === 
     429In large program systems, groups of compilation units (in the case of Erlang, modules) usually form logical layers. A desired property of such systems is that code in one layer should only use the layer immediately below it, and conversely, provide functionality only for the layer immediately above it. If you would like to check whether a system observes this rule, you should visit the [[InterfaceLayers|Interface Layers]] page, which show you how to check it. 
     430 
     431=== Duplicated code analysis === 
     432In large program systems often occure duplicated code, which is a computer programming term for a sequence of source code that occurs more than once. There are two ways in which two code sequences can be duplicates of each other: syntactically and functionally. This new feature can detect the syntactically similar duplicates. You can learn more about this topic and about the usage, especially about the command-line usage,  on [[DuplicateCodeAnalysis| Duplicate code analysis]] page. 
     433 
     434== Server management command list == 
     435 
     436Here's the list of supported server management commands:\\ 
     437* '''add(FDML)''': add a module, file, directory or a list of these to the database. \\ 
     438* '''drop(FDML)''': drop a module from the database. \\ 
     439* '''ls()''': list files that are in the database. \\ 
     440* '''backup()''': update the backup (checkpoint). \\ 
     441* '''restore(!Backup)''': restore the given backup. \\ 
     442* '''undo()''': undo the transformation (rollback, only one step). \\ 
     443* '''clean()''': clean backups (delete all checkpoints). \\ 
     444* '''reset()''': reset the database to an empty state, but valid schema. \\ 
     445* '''database_synchronization()''': Synchronize the contents of the database with the contents of the disc. \\ 
     446* '''graph(Target)''': assume no options and call one of the next two. \\ 
     447* '''graph(Atom,Options)''': assume ".dot" extension and call the one below. \\ 
     448* '''graph(File,Options)''': draw the graph with the given options. \\ 
     449* '''svg()''': draw the graph to graph.svg and call Graphviz. \\ 
     450* '''svg(File)''' \\ 
     451* '''svg(File, Options)''' \\ 
     452The additional/modied commands, that you can use, if you use the [[NifDB|NIF database engine]]:\\ 
     453* '''backup()''': creates a backup. \\ 
     454* '''backup(!CommitLog)''': creates a backup as '''ri:backup/0''', but here the user can attach a commit log to the backup file. \\ 
     455* '''ls_backups()''': returns a lists of backups, that has been created before with '''ri:backup/0''' or '''ri:backup/1'''. \\ 
     456* '''backup_info(Backup)''': returns information about the given backup. \\ 
     457* '''create_graph(Name)''': creates a graph with the given name. \\ 
     458* '''rename_graph(!OldName, !NewName)''': renames a graph that has the given !OldName, with the given !NewName. \\ 
     459* '''ls_graphs()''': returns a list of the created graphs. \\ 
     460* '''actual_graph()''': returns the actual graph's name. \\ 
     461* '''load_graph(Name)''': loads the given graph. \\ 
     462* '''delete_graph(Name)''': removes the given graph. \\ 
     463* '''delete_all_graphs()''': removes all graphs. \\ 
     464 
     465}}} 
    1466[[PageOutline]] 
    2467