wiki:ScriptableInterface

Version 9 (modified by manualwiki, 12 years ago) (diff)

--

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.

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]).