mutator 0.0.4

  • README.md
  • CHANGELOG.md
  • Installing
  • Versions
  • 0

mutator

A dart language helper tool for pre-compile/transform time refactoring. A potential alternative for Macro or inline function in desperate times.

##Status: Alpha Type detection currently relies on a solution I improvised without a proper design or abstraction and it is neither fast or exhaustively tested. Skip type detection by passing skip_type_check:true to mutate_t method for safety and speed if possible;see usage example1 for more details.

Usage

A simple usage example: Refactoring math.max(5,9) into (){int t = 5;t = t<9?9:t;return t;}();.

import 'package:mutator/mutator.dart';
String alias = 'math';
String pattern = 'math\\.max\\([0-9,\\w\\s_]+\\)';
//path needs to be set properly if there are relative file imports or part files.
String file_path = '';//leaving empty as neither is the case.

String src = """
      import 'dart:math' as math;
      main() async{
        int m = math.max(5,94,8,3,5,7,4);
      }
      """;

///main  should transform the value of
///src into the code below.
///
///   import 'dart:math' as math;
///   main() async{
///     int m = () {
///       int t = 5;
///       t = t < 94 ? 94 : t;
///       t = t < 8 ? 8 : t;
///       t = t < 3 ? 3 : t;
///       t = t < 5 ? 5 : t;
///       t = t < 7 ? 7 : t;
///       t = t < 4 ? 4 : t;
///       return t;
///     }();
///}
main() async{
  replacer(MethodInvocation e){
    String generate_code_for_getting_larger(
        String variable_name,
        String value1,
        String value2){
      return '${variable_name} = '
          '${value1.trim()}<${value2.trim()}?'
          '${value2.trim()}:${value1.trim()};';
    }
    String s = e.toString();
    s = s.substring(9,s.length-1);//removing `math.max(` and `)`
    var l = s.split(',');

    List f = ['(){int t = ${l[0]};'];

    for(String v in l.sublist(1))
      f.add(generate_code_for_getting_larger('t','t',v));

    f.add('return t;}()');
    return f.join();
  }
  var m = new Mutator<MethodInvocation>(
      '', pattern, replacer,alias_name: alias);
  print(await m.mutate_t(file_path,code:src,skip_type_check:true));
}

Refactoring r.nextInt(5) into a random number. Leaving r2.nextInt(5) unchanged as r2 is not an instance of math.Random.

import 'dart:math' as math;
import 'package:mutator/mutator.dart';

String pattern = '[\\w0-9_]+\\.nextInt\\([0-9]+\\)';
String klass_name = 'Random';
String path = '';//dummy path
String src = """
    import 'dart:math' as math;
    main() async{
    var r = new math.Random(5);
    print(r.nextInt(600));
    var r2 = new Random();
    print(r2.nextInt(600));
    }
    class Random{
        nextInt(int n){
          return n +5;
        }
    }
    """;
/// main should transform the value of src into
/// the code below and print it:
///
///import 'dart:math' as math;
///
///main() async{
///  var r = new math.Random(5);
///  print(88);//Changed
///  var r2 = new Random();
///  print(r2.nextInt(600));//Not changed
///}
///
///class Random {
///  nextInt(int n) {
///    return n + 5;
///  }
///}
///
main() async{
  int random_num;
  var r = new math.Random(5);
  replacer(MethodInvocation e){
    String s = e.toString();
    random_num = r.nextInt( int.parse(new RegExp('[0-9]+')
        .firstMatch(s).group(0)));
    return random_num.toString();
  }
  var m = new Mutator<MethodInvocation>(
      klass_name, pattern, replacer,alias_name: 'math');
  print(await m.mutate_t(path,code:src));
}

Refactoring d.on(o).hi = ()=>print('hi'); into d.on(o).set('hi',()=>print('hi'));

import 'package:mutator/mutator.dart';
String code = """
import 'package:mistletoe';
var d = new Dynamism(expert:true);
main() async{
    var o = new Object();
    d.on(o).hi = ()=>print('hi');
}
""";
const String klass_name = 'Dynamism';
const String pattern =
    '^[a-z.A-Z_0-9]+\\.on\\'
    '([a-z.A-Z_0-9]+\\)\\.[a-z.A-Z_0-9]+';
String file_path = '';
main() async{
    replacer(e){
        String s = e.toString();
        List l  = s.split('=');
        var invocation = l.removeAt(0).split('.');
        String name = invocation.removeLast().trim();
        invocation = invocation.join('.') +
            '.set(\'${name}\', ${l.join('=').trim()})';
        return invocation;
    }
    var m = new Mutator<AssignmentExpression>(
      klass_name, pattern, replacer);
    print(await m.mutate_t(file_path,code:code));
}

Features and bugs

Please file feature requests and bugs at the https://github.com/TastyCatFood/mutator/issues.

Limitations

  • No type detection available when the type is not statically defined. e.g.

      f(e){ return e.nextInt(4);}
    
  • Function's return type is ignored. e.g.

     math.Random f(){new math.Random(501);}
     main(){
         f().nextInt(7);
     }
    
  • Type information within conditional statement are ignored. e.g.

      f(e){
         if(e is math.Random){
          return e.nextInt(2);
         }
      }
    

Does not detect the type of variables defined in a file that has been imported as a package or a part of dart-sdk.

e.g.

    import 'package:example_code.dart' as eg;
    main(){
    // Mutator does not look into the package to find the type of [a].
        print(eg.a);
    }

The type of [a] is available when example_code.dart is imported relatively; import './example_code.dart'; or as a part file.

Changelog

0.0.1

  • Initial version

0.0.2

  • A bug fixed

0.0.3

  • mutate and mutate_t are now async methods. This change has been made as sometimes barback attempts to transform a part file before library's main file. Now, mutate_t only completes when dependencies are resolved.

0.0.4

  • time_out_in_seconds option added to mutate_t and mutate. mutator function hangs when a part file is passed to mutate never its main library file is never passed; dependencies cannot be resolved. time_out_in_seconds is added to throw a warning when such occurs.

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  mutator: ^0.0.4

2. Install it

You can install packages from the command line:

with pub:


$ pub get

Alternatively, your editor might support pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:mutator/mutator.dart';
  
Version Uploaded Documentation Archive
0.0.4 Apr 28, 2016 Go to the documentation of mutator 0.0.4 Download mutator 0.0.4 archive
0.0.3 Apr 26, 2016 Go to the documentation of mutator 0.0.3 Download mutator 0.0.3 archive
0.0.2 Apr 16, 2016 Go to the documentation of mutator 0.0.2 Download mutator 0.0.2 archive
0.0.1 Apr 16, 2016 Go to the documentation of mutator 0.0.1 Download mutator 0.0.1 archive
Popularity:
Describes how popular the package is relative to other packages. [more]
0
Health:
Code health derived from static analysis. [more]
0
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
0
Overall:
Weighted score of the above. [more]
0
Learn more about scoring.

The package version is not analyzed, because it does not support Dart 2. Until this is resolved, the package will receive a health and maintenance score of 0.

Issues and suggestions

Support Dart 2 in pubspec.yaml.

The SDK constraint in pubspec.yaml doesn't allow the Dart 2.0.0 release. For information about upgrading it to be Dart 2 compatible, please see https://www.dartlang.org/dart-2#migration.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=1.0.0 <2.0.0