wiki:ScriptableInterface

Scriptable RefactorErl interface

ris is similar to ri, with the following basic ideas:

  • results are always returned via the function return value.
  • no mandatory standard output.
  • function arguments are as general as possible and may contain semantic queries (which are evaluated first).
  • you can also input a semantic query via atoms instead of strings to ease escaping.
  • operations are composable (i.e., continue one where another has left off) - queries and refactorings can go back and forth.
  • you can perform a series of batch refactorings in a single step by selecting multiple entities at once.

Duplicated code analysis

Functions

  • clone_identifierl/0: uses the default values of properties
  • clone_identifierl/1: takes a proplist as described above

The default output format in this interface is the nodes, because for scripting nodes is the proper output format. However, any of the available output formats can be requested.

  • nodes: Returns the internal identifiers of the found clone groups. It is a good choice if you wish to further process the result by scripting using the ris interface.

Command: ris:clone_identifierl([{algorithm,sw_metrics}, {files,[ucl_alg_dm]}, {format,nodes}]).

[[[{entity,{'$gn',form,2}}],[{entity,{'$gn',form,3}}]]]

Result query functions

  • show_dupcode/1
  • show_dupcode/2
  • show_dupcode_group/2
  • show_dupcode_group/3

To find more information about these functions and their parameters please visit ErlangShellInterface.

The result of the duplicated code detection can be used for scripting.

Example

We want to get every function that calls a duplicated code function.

Clones = ris:clone_identifierl([{algorithm,sw_metrics}]).
Calls = ris:q([lists:flatten(Clones),".called_by"]).
ris:print(Calls).

File manipulations

% Here an entity is returned, which can be used later.
Added = ris:add_byname("path/to/mymod.erl").
...
% Readd the file.
ReAdded = ris:add(Added).

It is possible to drop files from the database:

ris:drop('mods[name==mymod]').

% or

% 'Added' is the previous entity.
ris:drop(Added).

Refactorings

Transformations are listed in refactoring functionalities. Here is the list of transformations that you can use via this interface:

% Move every unexported function to another_module and move it back:
ris:move(
    ris:move("mods[name=='mymod']
                  .fun[exported==false]",
             "other_mod"),
    "mymod").
ris:rename("mods[name=='mymod'].fun[name=='Colour']", "Color").

Operators

The result of the queries can be combined with the following set operators:

  • intersect: The following example takes the intersection of the files included by the two modules.
ris:q({"mods[name==mod1].includes", intersect,
       "mods[name==mod2].includes"}).
  • union: The union set operation. (Example: same as above, just substitute 'intersect' with 'union')
  • minus: The substraction set operation. (Example: same as above, just substitute 'intersect' with 'minus')
  • Sequence: Queries can be sequenced to continue a query from where another has left off. The execution works on arbitrarily long starting and continuation sequences (i.e., not just a single element). The following examples are correct, and can be used from ris:
% Language elements can be written via atoms or via strings. The dot is optional.
ris:q([mods, funs]).
ris:q([mods, .funs]).
ris:q(["mods", "funs"]).

% Filters can be sequenced.
ris:q(['mods', '[name==a]']).

% Statistics can be sequenced.
ris:q(['mods', '.fun', '.arity', ':sum']).
ris:q(["mods", "funs", "arity", ":avg"]).

Sequences can be constructed not only between queries parts, but between a basic ris command and query parts, too. This example first adds the module from file 'mymodule.erl'. The add call returns the entities loaded. A semantic query aggregate of a list works by executing the first query (or in this case, specifying a starting entity), and then running the next query in the chain (in this case getting the name of files included by the add call).

ris:q([ris:add_byname("mymodule.erl"),".includes.name"]).

Textual display

Use ris:show/1 to stringify entities. ris:show/2 does the same while accepting additional options already known for ri:q/3. Use the respective ris:print/1 and ris:print/2 functions for screen and file output.

ris:print(ris:q("mods.fun")).

The following gives the same result set, but written to the given file and annotated with line numbers. (Note that you could also manually write the output of ris:show/1 to a file.)

ris:print(ris:q("mods.fun"),
          [{out,"funs.txt"}, linenum]).
Last modified 10 years ago Last modified on Sep 17, 2014, 4:04:59 PM