string-mutator

0.2.0 • Public • Published

Build Status

Perform mutation operations on text strings (or text files). Useful for (simple) automatic code refactorings f.ex in code generators.

Getting Started

Install the module with: npm install string-mutator

Install with cli command

$ npm install -g string-mutator
$ string-mutator --help
$ string-mutator --version

Browserify

$ npm run-script browser

Documentation

Quick start

var mutators = require('mutators');
var sm = mutators.string; // string mutator
var fm = mutators.file; // file mutator
 
var msg = "Peter has 8 dollars and Jane has 15"
 
// String mutator
sm.last('Jane has 15').remove().on(msg);
 
// using content
sm.content(msg).last(/\d+/g).replaceWith('32');
 
 
// File mutator - performing string mutations
fm.readFile('test/files/test.txt').perform(function() {
    return this.first(/\d+/).prepend('$');
  }).write();
 
console.log('wrote', written, res.lastWritten);
res.write(res.original);

String mutator API

The string mutation API uses chaining. To start a chain, use any of:

  • first(matchExpr)
  • last(matchExpr)
  • content(text)

first and last

The first and last functions each take a matching expression that can be a simple string or a regular expression.

The result can chained with any of:

  • append
  • prepend
  • replaceWith
  • remove

append and prepend

sm.first(matchExpr).append('<FOUND>', target);

chaining

Both append and prepend can be chained with to like this

sm.first(matchExpr).append("\nEND").to(target);

relaceWith and remove

sm.first(matchExpr).remove(target);

chaining

replace and remove can be chained with on like this:

sm.first(matchExpr).replaceWith(something).on(target);

first.prepend

var sm = require('string-mutator');
 
var msg = "Peter has 8 dollars and Jane has 15"
var res = sm.first(/\d+/g).prepend('$', msg);
 
// => "Peter has $8 dollars and Jane has 15"

The following pattern valid for any prepend/append action.

`(text).to(content)*``

append(text).to(content) or prepend(text).to(content)

var sm = require('../lib/string-mutator.js');
 
var msg = "Peter has 8 dollars and Jane has 15"
var res = sm.first(/\d+/g).prepend('$').to(msg);
 
// => "Peter has $8 dollars and Jane has 15"

first.append

var msg = "Peter has 8 dollars and Jane has 15"
var res = sm.first(/\d+/g).append('$', msg);
res = sm.first(/\d+/g).append('$').to(msg);
 
// => "Peter has 8$ dollars and Jane has 15"

last.prepend

var msg = "Peter has 8 dollars and Jane has 15"
var res = sm.last(/\d+/g).prepend('$', msg);
// res = sm.last(/\d+/g).prepend('$').to(msg);
 
// => "Peter has 8 dollars and Jane has $15");

last.append

var msg = "Peter has 8 dollars and Jane has 15$"
var res = sm.last(/\d+/g).append('$', msg);
// res = sm.last(/\d+/g).append('$').to(msg);
 
// => "Peter has 8 dollars and Jane has 15$");

replaceWith

var msg = "Peter has 8 dollars and Jane has 15$"
var res = sm.last(/\d+/g).replaceWith('42', msg);
 
res = sm.first(/\d+/g).replaceWith('42').on(msg);
 
// => "Peter has 8 dollars and Jane has 42");

remove

Replace match with empty content ;)

var msg = "Peter has 8 dollars and Jane has 15"
var res = sm.last('and Jane has 15').remove(msg);
sm.last(/\d+/g).remove().on(msg);
 
// => "Peter has 8 dollars");

Content

An alternative is to start off by wrapping the text in a content object

Content can be chained with any of the following:

  • first
  • last
  • before
  • after
  • between
  • prependTxt
  • appendTxt
var msg = "Peter has 8 dollars and Jane has 15"
sm.content(msg).last('Jane has 15').remove();
 
// => "Peter has 8 dollars");

Before

before is chained on a content object and returns a new content object with the text before a match. Optionally it can take a matcher indicator string, which can be set to 'first' or 'last' (effectively: "before first" or "before last")

var msg = "Peter has 15 dollars, Jane has 15 and Paul has 32"
sm.content(msg).before(/Jane/).last(/\d+/g).replaceWith('20');
 
// => Peter has 20 dollars, Jane has 15 and Paul has 32

chaining prependTxt on before prepends the text before the match.

msg = "Peter have 12 dollars, Paul"
var res = sm.content(msg).before(/Paul/).prependTxt('Tina has 7.').result;
// => Peter have 12 dollars, Tina has 7

Using `mergeRest()``

msg = "Peter have 12 dollars, Paul"
var res = sm.content(msg).before(/Paul/).prependTxt('Tina has 7 and').mergeRest();
// => Peter have 12 dollars, Tina has 7 and Paul

before last

before (and after) also take an options hash for further control. The match: 'last' option can be used to find the last match within the scope.

msg = "Peter have 12 dollars, Paul is here Paul goes back"
var res = sm.content(msg).before(/Paul/, {include: true, match: 'last'}).prependTxt('Tina has 7 and').mergeRest();
// => Peter have 12 dollars, Paul is here Tina has 7 and Paul goes back

For convenience beforeLast and afterLast methods are also available.

`var res = sm.content(msg).beforeLast(/Paul/)``

After

Same as before but instead "after" ;)

If in doubt, see the test suite in the /test folder.

Between

between is chained on a content object and returns a new content object with the text between two matches.

var msg = "Peter has 15 dollars, Jane has 15 and Paul has 32 or 15"
sm.content(msg).between(/Peter/).and(/Paul/).last(/\d+/g).replaceWith('20');
 
// => Peter has 15 dollars, Jane has 20 and Paul has 32 or 15

inclusive

Both between, and are exclusive by default. You can now also use an options hash {include: true} to be inclusive. This option can also be used with before and after.

var msg = "Peter has 15 dollars, Jane has 15 and Paul has 32 or 15"
sm.content(msg).between(/Peter/, {include: true}).and(/Paul/, {include: true}).result;
 
// => Peter has 15 dollars, Jane has 20 and Paul

Shorthand inclusive:

`sm.content(msg).betweenIncl(/Peter/).andIncl(/Paul/)``

prependTxt

Adds text at beginning of content

`sm.content("Kristian").prependTxt('Hello, Sir ')``

appendTxt

Adds text at the end of content

sm.content("Paula").appendTxt(', says Goodbye')

Status

All tests pass :)

More advanced operations

For even more string manipulation, I recommend splitting a string into its multiple parts using a split function, then iterating through them and using this API on each part, then joining them back together.

You are most welcome to propose a nice API to facilitate this.

File mutator API

File mutation always starts with readFile

var fileMutateObj = fm.readFile('test/files/test.txt');

The result of readFile should always be chained with perform, which performs the string mutation on the content read.

perform wraps the read content in a content object (see: String mutator API) which becomes this in the context/scope of the function.

fm.readFile('test/files/test.txt').perform(function() {
    return this.first(/\d+/).prepend('$');
  })

The result of the perform mutation can be chained with any of:

  • write([newContent])
  • writeFile(fileName, [newContent])
  • read()
  • lastWritten
  • original

Complete example:

fm.readFile('test/files/test.txt').perform(function() {
    return this.first(/\d+/).prepend('$');
  }).write();
 
console.log('wrote', written, res.lastWritten);
res.write(res.original);
 
res.writeFile('another_file.txt');

TODO

Cleanup and Refactor!!! Lot's of duplication :(

Add more customizability than simply first/last. It would be sweet if user could pass a function that selects one or more matches to operate on/from.

Contributing

Add unit tests for any new or changed functionality. Lint and test your code using Grunt.

License

Copyright (c) 2014 Kristian Mandrup
Licensed under the MIT license.

Package Sidebar

Install

npm i string-mutator

Weekly Downloads

3

Version

0.2.0

License

MIT

Last publish

Collaborators

  • kmandrup