=0&&r.push(n.slice(2));return r},n._arrayCmp=v,n.SequenceMatcher=s,n.getCloseMatches=l,n._countLeading=w,n.Differ=e,n.IS_LINE_JUNK=i,n.IS_CHARACTER_JUNK=o,n._formatRangeUnified=E,n.unifiedDiff=g,n._formatRangeContext=m,n.contextDiff=a,n.ndiff=c,n.restore=d}).call(this)}),t("/difflib.js"),t("/difflib")}();
\ No newline at end of file
diff --git a/lib/difflib.js b/lib/difflib.js
index 80d250e..7598e99 100644
--- a/lib/difflib.js
+++ b/lib/difflib.js
@@ -1,4 +1,4 @@
-// Generated by CoffeeScript 1.3.1
+// Generated by CoffeeScript 1.7.1
/*
Module difflib -- helpers for computing deltas between objects.
@@ -23,8 +23,7 @@ Class SequenceMatcher:
Class Differ:
For producing human-readable deltas from sequences of lines of text.
-*/
-
+ */
(function() {
var Differ, Heap, IS_CHARACTER_JUNK, IS_LINE_JUNK, SequenceMatcher, assert, contextDiff, floor, getCloseMatches, max, min, ndiff, restore, unifiedDiff, _any, _arrayCmp, _calculateRatio, _countLeading, _formatRangeContext, _formatRangeUnified, _has,
@@ -75,114 +74,110 @@ Class Differ:
SequenceMatcher = (function() {
- SequenceMatcher.name = 'SequenceMatcher';
-
/*
- SequenceMatcher is a flexible class for comparing pairs of sequences of
- any type, so long as the sequence elements are hashable. The basic
- algorithm predates, and is a little fancier than, an algorithm
- published in the late 1980's by Ratcliff and Obershelp under the
- hyperbolic name "gestalt pattern matching". The basic idea is to find
- the longest contiguous matching subsequence that contains no "junk"
- elements (R-O doesn't address junk). The same idea is then applied
- recursively to the pieces of the sequences to the left and to the right
- of the matching subsequence. This does not yield minimal edit
- sequences, but does tend to yield matches that "look right" to people.
+ SequenceMatcher is a flexible class for comparing pairs of sequences of
+ any type, so long as the sequence elements are hashable. The basic
+ algorithm predates, and is a little fancier than, an algorithm
+ published in the late 1980's by Ratcliff and Obershelp under the
+ hyperbolic name "gestalt pattern matching". The basic idea is to find
+ the longest contiguous matching subsequence that contains no "junk"
+ elements (R-O doesn't address junk). The same idea is then applied
+ recursively to the pieces of the sequences to the left and to the right
+ of the matching subsequence. This does not yield minimal edit
+ sequences, but does tend to yield matches that "look right" to people.
- SequenceMatcher tries to compute a "human-friendly diff" between two
- sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the
- longest *contiguous* & junk-free matching subsequence. That's what
- catches peoples' eyes. The Windows(tm) windiff has another interesting
- notion, pairing up elements that appear uniquely in each sequence.
- That, and the method here, appear to yield more intuitive difference
- reports than does diff. This method appears to be the least vulnerable
- to synching up on blocks of "junk lines", though (like blank lines in
- ordinary text files, or maybe "" lines in HTML files). That may be
- because this is the only method of the 3 that has a *concept* of
- "junk" .
+ SequenceMatcher tries to compute a "human-friendly diff" between two
+ sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the
+ longest *contiguous* & junk-free matching subsequence. That's what
+ catches peoples' eyes. The Windows(tm) windiff has another interesting
+ notion, pairing up elements that appear uniquely in each sequence.
+ That, and the method here, appear to yield more intuitive difference
+ reports than does diff. This method appears to be the least vulnerable
+ to synching up on blocks of "junk lines", though (like blank lines in
+ ordinary text files, or maybe "" lines in HTML files). That may be
+ because this is the only method of the 3 that has a *concept* of
+ "junk" .
- Example, comparing two strings, and considering blanks to be "junk":
+ Example, comparing two strings, and considering blanks to be "junk":
- >>> isjunk = (c) -> c is ' '
- >>> s = new SequenceMatcher(isjunk,
- 'private Thread currentThread;',
- 'private volatile Thread currentThread;')
+ >>> isjunk = (c) -> c is ' '
+ >>> s = new SequenceMatcher(isjunk,
+ 'private Thread currentThread;',
+ 'private volatile Thread currentThread;')
- .ratio() returns a float in [0, 1], measuring the "similarity" of the
- sequences. As a rule of thumb, a .ratio() value over 0.6 means the
- sequences are close matches:
+ .ratio() returns a float in [0, 1], measuring the "similarity" of the
+ sequences. As a rule of thumb, a .ratio() value over 0.6 means the
+ sequences are close matches:
- >>> s.ratio().toPrecision(3)
- '0.866'
+ >>> s.ratio().toPrecision(3)
+ '0.866'
- If you're only interested in where the sequences match,
- .getMatchingBlocks() is handy:
+ If you're only interested in where the sequences match,
+ .getMatchingBlocks() is handy:
- >>> for [a, b, size] in s.getMatchingBlocks()
- ... console.log("a[#{a}] and b[#{b}] match for #{size} elements");
- a[0] and b[0] match for 8 elements
- a[8] and b[17] match for 21 elements
- a[29] and b[38] match for 0 elements
+ >>> for [a, b, size] in s.getMatchingBlocks()
+ ... console.log("a[#{a}] and b[#{b}] match for #{size} elements");
+ a[0] and b[0] match for 8 elements
+ a[8] and b[17] match for 21 elements
+ a[29] and b[38] match for 0 elements
- Note that the last tuple returned by .get_matching_blocks() is always a
- dummy, (len(a), len(b), 0), and this is the only case in which the last
- tuple element (number of elements matched) is 0.
+ Note that the last tuple returned by .get_matching_blocks() is always a
+ dummy, (len(a), len(b), 0), and this is the only case in which the last
+ tuple element (number of elements matched) is 0.
- If you want to know how to change the first sequence into the second,
- use .get_opcodes():
+ If you want to know how to change the first sequence into the second,
+ use .get_opcodes():
- >>> for [op, a1, a2, b1, b2] in s.getOpcodes()
- ... console.log "#{op} a[#{a1}:#{a2}] b[#{b1}:#{b2}]"
- equal a[0:8] b[0:8]
- insert a[8:8] b[8:17]
- equal a[8:29] b[17:38]
+ >>> for [op, a1, a2, b1, b2] in s.getOpcodes()
+ ... console.log "#{op} a[#{a1}:#{a2}] b[#{b1}:#{b2}]"
+ equal a[0:8] b[0:8]
+ insert a[8:8] b[8:17]
+ equal a[8:29] b[17:38]
- See the Differ class for a fancy human-friendly file differencer, which
- uses SequenceMatcher both to compare sequences of lines, and to compare
- sequences of characters within similar (near-matching) lines.
+ See the Differ class for a fancy human-friendly file differencer, which
+ uses SequenceMatcher both to compare sequences of lines, and to compare
+ sequences of characters within similar (near-matching) lines.
- See also function getCloseMatches() in this module, which shows how
- simple code building on SequenceMatcher can be used to do useful work.
+ See also function getCloseMatches() in this module, which shows how
+ simple code building on SequenceMatcher can be used to do useful work.
- Timing: Basic R-O is cubic time worst case and quadratic time expected
- case. SequenceMatcher is quadratic time for the worst case and has
- expected-case behavior dependent in a complicated way on how many
- elements the sequences have in common; best case time is linear.
+ Timing: Basic R-O is cubic time worst case and quadratic time expected
+ case. SequenceMatcher is quadratic time for the worst case and has
+ expected-case behavior dependent in a complicated way on how many
+ elements the sequences have in common; best case time is linear.
- Methods:
+ Methods:
- constructor(isjunk=null, a='', b='')
- Construct a SequenceMatcher.
+ constructor(isjunk=null, a='', b='')
+ Construct a SequenceMatcher.
- setSeqs(a, b)
- Set the two sequences to be compared.
+ setSeqs(a, b)
+ Set the two sequences to be compared.
- setSeq1(a)
- Set the first sequence to be compared.
+ setSeq1(a)
+ Set the first sequence to be compared.
- setSeq2(b)
- Set the second sequence to be compared.
+ setSeq2(b)
+ Set the second sequence to be compared.
- findLongestMatch(alo, ahi, blo, bhi)
- Find longest matching block in a[alo:ahi] and b[blo:bhi].
+ findLongestMatch(alo, ahi, blo, bhi)
+ Find longest matching block in a[alo:ahi] and b[blo:bhi].
- getMatchingBlocks()
- Return list of triples describing matching subsequences.
+ getMatchingBlocks()
+ Return list of triples describing matching subsequences.
- getOpcodes()
- Return list of 5-tuples describing how to turn a into b.
+ getOpcodes()
+ Return list of 5-tuples describing how to turn a into b.
- ratio()
- Return a measure of the sequences' similarity (float in [0,1]).
+ ratio()
+ Return a measure of the sequences' similarity (float in [0,1]).
- quickRatio()
- Return an upper bound on .ratio() relatively quickly.
+ quickRatio()
+ Return an upper bound on .ratio() relatively quickly.
- realQuickRatio()
- Return an upper bound on ratio() very quickly.
- */
-
-
+ realQuickRatio()
+ Return an upper bound on ratio() very quickly.
+ */
function SequenceMatcher(isjunk, a, b, autojunk) {
this.isjunk = isjunk;
if (a == null) {
@@ -192,35 +187,36 @@ Class Differ:
b = '';
}
this.autojunk = autojunk != null ? autojunk : true;
+
/*
- Construct a SequenceMatcher.
+ Construct a SequenceMatcher.
- Optional arg isjunk is null (the default), or a one-argument
- function that takes a sequence element and returns true iff the
- element is junk. Null is equivalent to passing "(x) -> 0", i.e.
- no elements are considered to be junk. For example, pass
- (x) -> x in ' \t'
- if you're comparing lines as sequences of characters, and don't
- want to synch up on blanks or hard tabs.
+ Optional arg isjunk is null (the default), or a one-argument
+ function that takes a sequence element and returns true iff the
+ element is junk. Null is equivalent to passing "(x) -> 0", i.e.
+ no elements are considered to be junk. For example, pass
+ (x) -> x in ' \t'
+ if you're comparing lines as sequences of characters, and don't
+ want to synch up on blanks or hard tabs.
- Optional arg a is the first of two sequences to be compared. By
- default, an empty string. The elements of a must be hashable. See
- also .setSeqs() and .setSeq1().
+ Optional arg a is the first of two sequences to be compared. By
+ default, an empty string. The elements of a must be hashable. See
+ also .setSeqs() and .setSeq1().
- Optional arg b is the second of two sequences to be compared. By
- default, an empty string. The elements of b must be hashable. See
- also .setSeqs() and .setSeq2().
+ Optional arg b is the second of two sequences to be compared. By
+ default, an empty string. The elements of b must be hashable. See
+ also .setSeqs() and .setSeq2().
- Optional arg autojunk should be set to false to disable the
- "automatic junk heuristic" that treats popular elements as junk
- (see module documentation for more information).
- */
-
+ Optional arg autojunk should be set to false to disable the
+ "automatic junk heuristic" that treats popular elements as junk
+ (see module documentation for more information).
+ */
this.a = this.b = null;
this.setSeqs(a, b);
}
SequenceMatcher.prototype.setSeqs = function(a, b) {
+
/*
Set the two sequences to be compared.
@@ -228,12 +224,13 @@ Class Differ:
>>> s.setSeqs('abcd', 'bcde')
>>> s.ratio()
0.75
- */
+ */
this.setSeq1(a);
return this.setSeq2(b);
};
SequenceMatcher.prototype.setSeq1 = function(a) {
+
/*
Set the first sequence to be compared.
@@ -252,7 +249,7 @@ Class Differ:
repeatedly for each of the other sequences.
See also setSeqs() and setSeq2().
- */
+ */
if (a === this.a) {
return;
}
@@ -261,25 +258,26 @@ Class Differ:
};
SequenceMatcher.prototype.setSeq2 = function(b) {
+
/*
- Set the second sequence to be compared.
+ Set the second sequence to be compared.
- The first sequence to be compared is not changed.
+ The first sequence to be compared is not changed.
- >>> s = new SequenceMatcher(null, 'abcd', 'bcde')
- >>> s.ratio()
- 0.75
- >>> s.setSeq2('abcd')
- >>> s.ratio()
- 1.0
+ >>> s = new SequenceMatcher(null, 'abcd', 'bcde')
+ >>> s.ratio()
+ 0.75
+ >>> s.setSeq2('abcd')
+ >>> s.ratio()
+ 1.0
- SequenceMatcher computes and caches detailed information about the
- second sequence, so if you want to compare one sequence S against
- many sequences, use .setSeq2(S) once and call .setSeq1(x)
- repeatedly for each of the other sequences.
+ SequenceMatcher computes and caches detailed information about the
+ second sequence, so if you want to compare one sequence S against
+ many sequences, use .setSeq2(S) once and call .setSeq1(x)
+ repeatedly for each of the other sequences.
- See also setSeqs() and setSeq1().
- */
+ See also setSeqs() and setSeq1().
+ */
if (b === this.b) {
return;
}
@@ -331,6 +329,7 @@ Class Differ:
};
SequenceMatcher.prototype.findLongestMatch = function(alo, ahi, blo, bhi) {
+
/*
Find longest matching block in a[alo...ahi] and b[blo...bhi].
@@ -356,8 +355,7 @@ Class Differ:
>>> s = new SequenceMatcher(null, 'ab', 'c')
>>> s.findLongestMatch(0, 2, 0, 1)
[0, 0, 0]
- */
-
+ */
var a, b, b2j, besti, bestj, bestsize, i, isbjunk, j, j2len, k, newj2len, _i, _j, _len, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
_ref = [this.a, this.b, this.b2j, this.isbjunk], a = _ref[0], b = _ref[1], b2j = _ref[2], isbjunk = _ref[3];
_ref1 = [alo, blo, 0], besti = _ref1[0], bestj = _ref1[1], bestsize = _ref1[2];
@@ -396,25 +394,25 @@ Class Differ:
};
SequenceMatcher.prototype.getMatchingBlocks = function() {
+
/*
- Return list of triples describing matching subsequences.
+ Return list of triples describing matching subsequences.
- Each triple is of the form [i, j, n], and means that
- a[i...i+n] == b[j...j+n]. The triples are monotonically increasing in
- i and in j. it's also guaranteed that if
- [i, j, n] and [i', j', n'] are adjacent triples in the list, and
- the second is not the last triple in the list, then i+n != i' or
- j+n != j'. IOW, adjacent triples never describe adjacent equal
- blocks.
+ Each triple is of the form [i, j, n], and means that
+ a[i...i+n] == b[j...j+n]. The triples are monotonically increasing in
+ i and in j. it's also guaranteed that if
+ [i, j, n] and [i', j', n'] are adjacent triples in the list, and
+ the second is not the last triple in the list, then i+n != i' or
+ j+n != j'. IOW, adjacent triples never describe adjacent equal
+ blocks.
- The last triple is a dummy, [a.length, b.length, 0], and is the only
- triple with n==0.
+ The last triple is a dummy, [a.length, b.length, 0], and is the only
+ triple with n==0.
- >>> s = new SequenceMatcher(null, 'abxcd', 'abcd')
- >>> s.getMatchingBlocks()
- [[0, 0, 2], [3, 2, 2], [5, 4, 0]]
- */
-
+ >>> s = new SequenceMatcher(null, 'abxcd', 'abcd')
+ >>> s.getMatchingBlocks()
+ [[0, 0, 2], [3, 2, 2], [5, 4, 0]]
+ */
var ahi, alo, bhi, blo, i, i1, i2, j, j1, j2, k, k1, k2, la, lb, matchingBlocks, nonAdjacent, queue, x, _i, _len, _ref, _ref1, _ref2, _ref3, _ref4;
if (this.matchingBlocks) {
return this.matchingBlocks;
@@ -457,6 +455,7 @@ Class Differ:
};
SequenceMatcher.prototype.getOpcodes = function() {
+
/*
Return list of 5-tuples describing how to turn a into b.
@@ -480,8 +479,7 @@ Class Differ:
[ 'replace' , 3 , 4 , 2 , 3 ] ,
[ 'equal' , 4 , 6 , 3 , 5 ] ,
[ 'insert' , 6 , 6 , 5 , 6 ] ]
- */
-
+ */
var ai, answer, bj, i, j, size, tag, _i, _len, _ref, _ref1, _ref2;
if (this.opcodes) {
return this.opcodes;
@@ -515,6 +513,7 @@ Class Differ:
if (n == null) {
n = 3;
}
+
/*
Isolate change clusters by eliminating ranges with no changes.
@@ -540,8 +539,7 @@ Class Differ:
[ [ 'equal' , 31 , 34 , 27 , 30 ],
[ 'replace' , 34 , 35 , 30 , 31 ],
[ 'equal' , 35 , 38 , 31 , 34 ] ] ]
- */
-
+ */
codes = this.getOpcodes();
if (!codes.length) {
codes = [['equal', 0, 1, 0, 1]];
@@ -574,28 +572,28 @@ Class Differ:
};
SequenceMatcher.prototype.ratio = function() {
+
/*
- Return a measure of the sequences' similarity (float in [0,1]).
+ Return a measure of the sequences' similarity (float in [0,1]).
- Where T is the total number of elements in both sequences, and
- M is the number of matches, this is 2.0*M / T.
- Note that this is 1 if the sequences are identical, and 0 if
- they have nothing in common.
+ Where T is the total number of elements in both sequences, and
+ M is the number of matches, this is 2.0*M / T.
+ Note that this is 1 if the sequences are identical, and 0 if
+ they have nothing in common.
- .ratio() is expensive to compute if you haven't already computed
- .getMatchingBlocks() or .getOpcodes(), in which case you may
- want to try .quickRatio() or .realQuickRatio() first to get an
- upper bound.
-
- >>> s = new SequenceMatcher(null, 'abcd', 'bcde')
- >>> s.ratio()
- 0.75
- >>> s.quickRatio()
- 0.75
- >>> s.realQuickRatio()
- 1.0
- */
-
+ .ratio() is expensive to compute if you haven't already computed
+ .getMatchingBlocks() or .getOpcodes(), in which case you may
+ want to try .quickRatio() or .realQuickRatio() first to get an
+ upper bound.
+
+ >>> s = new SequenceMatcher(null, 'abcd', 'bcde')
+ >>> s.ratio()
+ 0.75
+ >>> s.quickRatio()
+ 0.75
+ >>> s.realQuickRatio()
+ 1.0
+ */
var match, matches, _i, _len, _ref;
matches = 0;
_ref = this.getMatchingBlocks();
@@ -607,13 +605,13 @@ Class Differ:
};
SequenceMatcher.prototype.quickRatio = function() {
+
/*
- Return an upper bound on ratio() relatively quickly.
+ Return an upper bound on ratio() relatively quickly.
- This isn't defined beyond that it is an upper bound on .ratio(), and
- is faster to compute.
- */
-
+ This isn't defined beyond that it is an upper bound on .ratio(), and
+ is faster to compute.
+ */
var avail, elt, fullbcount, matches, numb, _i, _j, _len, _len1, _ref, _ref1;
if (!this.fullbcount) {
this.fullbcount = fullbcount = {};
@@ -643,13 +641,13 @@ Class Differ:
};
SequenceMatcher.prototype.realQuickRatio = function() {
+
/*
- Return an upper bound on ratio() very quickly.
+ Return an upper bound on ratio() very quickly.
- This isn't defined beyond that it is an upper bound on .ratio(), and
- is faster to compute than either .ratio() or .quickRatio().
- */
-
+ This isn't defined beyond that it is an upper bound on .ratio(), and
+ is faster to compute than either .ratio() or .quickRatio().
+ */
var la, lb, _ref;
_ref = [this.a.length, this.b.length], la = _ref[0], lb = _ref[1];
return _calculateRatio(min(la, lb), la + lb);
@@ -659,41 +657,44 @@ Class Differ:
})();
- getCloseMatches = function(word, possibilities, n, cutoff) {
- var result, s, score, x, _i, _j, _len, _len1, _ref, _results;
+ getCloseMatches = function(word, possibilities, n, cutoff, formatter) {
+ var o, result, s, score, x, _i, _j, _len, _len1, _ref, _results;
if (n == null) {
n = 3;
}
if (cutoff == null) {
cutoff = 0.6;
}
+
/*
- Use SequenceMatcher to return list of the best "good enough" matches.
+ Use SequenceMatcher to return list of the best "good enough" matches.
- word is a sequence for which close matches are desired (typically a
- string).
+ word is a sequence for which close matches are desired (typically a
+ string).
- possibilities is a list of sequences against which to match word
- (typically a list of strings).
+ possibilities is a list of sequences against which to match word
+ (typically a list of strings).
- Optional arg n (default 3) is the maximum number of close matches to
- return. n must be > 0.
+ Optional arg n (default 3) is the maximum number of close matches to
+ return. n must be > 0.
- Optional arg cutoff (default 0.6) is a float in [0, 1]. Possibilities
- that don't score at least that similar to word are ignored.
+ Optional arg cutoff (default 0.6) is a float in [0, 1]. Possibilities
+ that don't score at least that similar to word are ignored.
- The best (no more than n) matches among the possibilities are returned
- in a list, sorted by similarity score, most similar first.
+ Optional arg formatter is a function that is run on each element from possibilities
+ before matching is run.
- >>> getCloseMatches('appel', ['ape', 'apple', 'peach', 'puppy'])
- ['apple', 'ape']
- >>> KEYWORDS = require('coffee-script').RESERVED
- >>> getCloseMatches('wheel', KEYWORDS)
- ['when', 'while']
- >>> getCloseMatches('accost', KEYWORDS)
- ['const']
- */
-
+ The best (no more than n) matches among the possibilities are returned
+ in a list, sorted by similarity score, most similar first.
+
+ >>> getCloseMatches('appel', ['ape', 'apple', 'peach', 'puppy'])
+ ['apple', 'ape']
+ >>> KEYWORDS = require('coffee-script').RESERVED
+ >>> getCloseMatches('wheel', KEYWORDS)
+ ['when', 'while']
+ >>> getCloseMatches('accost', KEYWORDS)
+ ['const']
+ */
if (!(n > 0)) {
throw new Error("n must be > 0: (" + n + ")");
}
@@ -705,9 +706,13 @@ Class Differ:
s.setSeq2(word);
for (_i = 0, _len = possibilities.length; _i < _len; _i++) {
x = possibilities[_i];
+ o = x;
+ if (formatter) {
+ x = formatter(x);
+ }
s.setSeq1(x);
if (s.realQuickRatio() >= cutoff && s.quickRatio() >= cutoff && s.ratio() >= cutoff) {
- result.push([s.ratio(), x]);
+ result.push([s.ratio(), o]);
}
}
result = Heap.nlargest(result, n, _arrayCmp);
@@ -720,13 +725,13 @@ Class Differ:
};
_countLeading = function(line, ch) {
+
/*
- Return number of `ch` characters at the start of `line`.
+ Return number of `ch` characters at the start of `line`.
- >>> _countLeading(' abc', ' ')
- 3
- */
-
+ >>> _countLeading(' abc', ' ')
+ 3
+ */
var i, n, _ref;
_ref = [0, line.length], i = _ref[0], n = _ref[1];
while (i < n && line[i] === ch) {
@@ -737,122 +742,118 @@ Class Differ:
Differ = (function() {
- Differ.name = 'Differ';
-
/*
- Differ is a class for comparing sequences of lines of text, and
- producing human-readable differences or deltas. Differ uses
- SequenceMatcher both to compare sequences of lines, and to compare
- sequences of characters within similar (near-matching) lines.
-
- Each line of a Differ delta begins with a two-letter code:
-
- '- ' line unique to sequence 1
- '+ ' line unique to sequence 2
- ' ' line common to both sequences
- '? ' line not present in either input sequence
-
- Lines beginning with '? ' attempt to guide the eye to intraline
- differences, and were not present in either input sequence. These lines
- can be confusing if the sequences contain tab characters.
-
- Note that Differ makes no claim to produce a *minimal* diff. To the
- contrary, minimal diffs are often counter-intuitive, because they synch
- up anywhere possible, sometimes accidental matches 100 pages apart.
- Restricting synch points to contiguous matches preserves some notion of
- locality, at the occasional cost of producing a longer diff.
-
- Example: Comparing two texts.
-
- >>> text1 = ['1. Beautiful is better than ugly.\n',
- ... '2. Explicit is better than implicit.\n',
- ... '3. Simple is better than complex.\n',
- ... '4. Complex is better than complicated.\n']
- >>> text1.length
- 4
- >>> text2 = ['1. Beautiful is better than ugly.\n',
- ... '3. Simple is better than complex.\n',
- ... '4. Complicated is better than complex.\n',
- ... '5. Flat is better than nested.\n']
-
- Next we instantiate a Differ object:
-
- >>> d = new Differ()
-
- Note that when instantiating a Differ object we may pass functions to
- filter out line and character 'junk'.
-
- Finally, we compare the two:
-
- >>> result = d.compare(text1, text2)
- [ ' 1. Beautiful is better than ugly.\n',
- '- 2. Explicit is better than implicit.\n',
- '- 3. Simple is better than complex.\n',
- '+ 3. Simple is better than complex.\n',
- '? ++\n',
- '- 4. Complex is better than complicated.\n',
- '? ^ ---- ^\n',
- '+ 4. Complicated is better than complex.\n',
- '? ++++ ^ ^\n',
- '+ 5. Flat is better than nested.\n' ]
-
- Methods:
-
- constructor(linejunk=null, charjunk=null)
- Construct a text differencer, with optional filters.
- compare(a, b)
- Compare two sequences of lines; generate the resulting delta.
- */
-
-
+ Differ is a class for comparing sequences of lines of text, and
+ producing human-readable differences or deltas. Differ uses
+ SequenceMatcher both to compare sequences of lines, and to compare
+ sequences of characters within similar (near-matching) lines.
+
+ Each line of a Differ delta begins with a two-letter code:
+
+ '- ' line unique to sequence 1
+ '+ ' line unique to sequence 2
+ ' ' line common to both sequences
+ '? ' line not present in either input sequence
+
+ Lines beginning with '? ' attempt to guide the eye to intraline
+ differences, and were not present in either input sequence. These lines
+ can be confusing if the sequences contain tab characters.
+
+ Note that Differ makes no claim to produce a *minimal* diff. To the
+ contrary, minimal diffs are often counter-intuitive, because they synch
+ up anywhere possible, sometimes accidental matches 100 pages apart.
+ Restricting synch points to contiguous matches preserves some notion of
+ locality, at the occasional cost of producing a longer diff.
+
+ Example: Comparing two texts.
+
+ >>> text1 = ['1. Beautiful is better than ugly.\n',
+ ... '2. Explicit is better than implicit.\n',
+ ... '3. Simple is better than complex.\n',
+ ... '4. Complex is better than complicated.\n']
+ >>> text1.length
+ 4
+ >>> text2 = ['1. Beautiful is better than ugly.\n',
+ ... '3. Simple is better than complex.\n',
+ ... '4. Complicated is better than complex.\n',
+ ... '5. Flat is better than nested.\n']
+
+ Next we instantiate a Differ object:
+
+ >>> d = new Differ()
+
+ Note that when instantiating a Differ object we may pass functions to
+ filter out line and character 'junk'.
+
+ Finally, we compare the two:
+
+ >>> result = d.compare(text1, text2)
+ [ ' 1. Beautiful is better than ugly.\n',
+ '- 2. Explicit is better than implicit.\n',
+ '- 3. Simple is better than complex.\n',
+ '+ 3. Simple is better than complex.\n',
+ '? ++\n',
+ '- 4. Complex is better than complicated.\n',
+ '? ^ ---- ^\n',
+ '+ 4. Complicated is better than complex.\n',
+ '? ++++ ^ ^\n',
+ '+ 5. Flat is better than nested.\n' ]
+
+ Methods:
+
+ constructor(linejunk=null, charjunk=null)
+ Construct a text differencer, with optional filters.
+ compare(a, b)
+ Compare two sequences of lines; generate the resulting delta.
+ */
function Differ(linejunk, charjunk) {
this.linejunk = linejunk;
this.charjunk = charjunk;
+
/*
- Construct a text differencer, with optional filters.
+ Construct a text differencer, with optional filters.
- The two optional keyword parameters are for filter functions:
+ The two optional keyword parameters are for filter functions:
- - `linejunk`: A function that should accept a single string argument,
- and return true iff the string is junk. The module-level function
- `IS_LINE_JUNK` may be used to filter out lines without visible
- characters, except for at most one splat ('#'). It is recommended
- to leave linejunk null.
+ - `linejunk`: A function that should accept a single string argument,
+ and return true iff the string is junk. The module-level function
+ `IS_LINE_JUNK` may be used to filter out lines without visible
+ characters, except for at most one splat ('#'). It is recommended
+ to leave linejunk null.
- - `charjunk`: A function that should accept a string of length 1. The
- module-level function `IS_CHARACTER_JUNK` may be used to filter out
- whitespace characters (a blank or tab; **note**: bad idea to include
- newline in this!). Use of IS_CHARACTER_JUNK is recommended.
- */
-
+ - `charjunk`: A function that should accept a string of length 1. The
+ module-level function `IS_CHARACTER_JUNK` may be used to filter out
+ whitespace characters (a blank or tab; **note**: bad idea to include
+ newline in this!). Use of IS_CHARACTER_JUNK is recommended.
+ */
}
Differ.prototype.compare = function(a, b) {
+
/*
- Compare two sequences of lines; generate the resulting delta.
+ Compare two sequences of lines; generate the resulting delta.
- Each sequence must contain individual single-line strings ending with
- newlines. Such sequences can be obtained from the `readlines()` method
- of file-like objects. The delta generated also consists of newline-
- terminated strings, ready to be printed as-is via the writeline()
- method of a file-like object.
+ Each sequence must contain individual single-line strings ending with
+ newlines. Such sequences can be obtained from the `readlines()` method
+ of file-like objects. The delta generated also consists of newline-
+ terminated strings, ready to be printed as-is via the writeline()
+ method of a file-like object.
- Example:
+ Example:
- >>> d = new Differ
- >>> d.compare(['one\n', 'two\n', 'three\n'],
- ... ['ore\n', 'tree\n', 'emu\n'])
- [ '- one\n',
- '? ^\n',
- '+ ore\n',
- '? ^\n',
- '- two\n',
- '- three\n',
- '? -\n',
- '+ tree\n',
- '+ emu\n' ]
- */
-
+ >>> d = new Differ
+ >>> d.compare(['one\n', 'two\n', 'three\n'],
+ ... ['ore\n', 'tree\n', 'emu\n'])
+ [ '- one\n',
+ '? ^\n',
+ '+ ore\n',
+ '? ^\n',
+ '- two\n',
+ '- three\n',
+ '? -\n',
+ '+ tree\n',
+ '+ emu\n' ]
+ */
var ahi, alo, bhi, blo, cruncher, g, line, lines, tag, _i, _j, _len, _len1, _ref, _ref1;
cruncher = new SequenceMatcher(this.linejunk, a, b);
lines = [];
@@ -884,10 +885,10 @@ Class Differ:
};
Differ.prototype._dump = function(tag, x, lo, hi) {
- /*
- Generate comparison results for a same-tagged range.
- */
+ /*
+ Generate comparison results for a same-tagged range.
+ */
var i, _i, _results;
_results = [];
for (i = _i = lo; lo <= hi ? _i < hi : _i > hi; i = lo <= hi ? ++_i : --_i) {
@@ -919,22 +920,22 @@ Class Differ:
};
Differ.prototype._fancyReplace = function(a, alo, ahi, b, blo, bhi) {
+
/*
- When replacing one block of lines with another, search the blocks
- for *similar* lines; the best-matching pair (if any) is used as a
- synch point, and intraline difference marking is done on the
- similar pair. Lots of work, but often worth it.
+ When replacing one block of lines with another, search the blocks
+ for *similar* lines; the best-matching pair (if any) is used as a
+ synch point, and intraline difference marking is done on the
+ similar pair. Lots of work, but often worth it.
- Example:
- >>> d = new Differ
- >>> d._fancyReplace(['abcDefghiJkl\n'], 0, 1,
- ... ['abcdefGhijkl\n'], 0, 1)
- [ '- abcDefghiJkl\n',
- '? ^ ^ ^\n',
- '+ abcdefGhijkl\n',
- '? ^ ^ ^\n' ]
- */
-
+ Example:
+ >>> d = new Differ
+ >>> d._fancyReplace(['abcDefghiJkl\n'], 0, 1,
+ ... ['abcdefGhijkl\n'], 0, 1)
+ [ '- abcDefghiJkl\n',
+ '? ^ ^ ^\n',
+ '+ abcdefGhijkl\n',
+ '? ^ ^ ^\n' ]
+ */
var aelt, ai, ai1, ai2, atags, belt, bestRatio, besti, bestj, bj, bj1, bj2, btags, cruncher, cutoff, eqi, eqj, i, j, la, lb, line, lines, tag, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _n, _o, _ref, _ref1, _ref10, _ref11, _ref12, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9;
_ref = [0.74, 0.75], bestRatio = _ref[0], cutoff = _ref[1];
cruncher = new SequenceMatcher(this.charjunk);
@@ -1034,19 +1035,19 @@ Class Differ:
};
Differ.prototype._qformat = function(aline, bline, atags, btags) {
+
/*
- Format "?" output and deal with leading tabs.
+ Format "?" output and deal with leading tabs.
- Example:
+ Example:
- >>> d = new Differ
- >>> d._qformat('\tabcDefghiJkl\n', '\tabcdefGhijkl\n',
- [ '- \tabcDefghiJkl\n',
- '? \t ^ ^ ^\n',
- '+ \tabcdefGhijkl\n',
- '? \t ^ ^ ^\n' ]
- */
-
+ >>> d = new Differ
+ >>> d._qformat('\tabcDefghiJkl\n', '\tabcdefGhijkl\n',
+ [ '- \tabcDefghiJkl\n',
+ '? \t ^ ^ ^\n',
+ '+ \tabcdefGhijkl\n',
+ '? \t ^ ^ ^\n' ]
+ */
var common, lines;
lines = [];
common = min(_countLeading(aline, '\t'), _countLeading(bline, '\t'));
@@ -1073,19 +1074,19 @@ Class Differ:
if (pat == null) {
pat = /^\s*#?\s*$/;
}
- /*
- Return 1 for ignorable line: iff `line` is blank or contains a single '#'.
-
- Examples:
-
- >>> IS_LINE_JUNK('\n')
- true
- >>> IS_LINE_JUNK(' # \n')
- true
- >>> IS_LINE_JUNK('hello\n')
- false
- */
+ /*
+ Return 1 for ignorable line: iff `line` is blank or contains a single '#'.
+
+ Examples:
+
+ >>> IS_LINE_JUNK('\n')
+ true
+ >>> IS_LINE_JUNK(' # \n')
+ true
+ >>> IS_LINE_JUNK('hello\n')
+ false
+ */
return pat.test(line);
};
@@ -1093,28 +1094,28 @@ Class Differ:
if (ws == null) {
ws = ' \t';
}
- /*
- Return 1 for ignorable character: iff `ch` is a space or tab.
-
- Examples:
- >>> IS_CHARACTER_JUNK(' ').should.be.true
- true
- >>> IS_CHARACTER_JUNK('\t').should.be.true
- true
- >>> IS_CHARACTER_JUNK('\n').should.be.false
- false
- >>> IS_CHARACTER_JUNK('x').should.be.false
- false
- */
+ /*
+ Return 1 for ignorable character: iff `ch` is a space or tab.
+
+ Examples:
+ >>> IS_CHARACTER_JUNK(' ').should.be.true
+ true
+ >>> IS_CHARACTER_JUNK('\t').should.be.true
+ true
+ >>> IS_CHARACTER_JUNK('\n').should.be.false
+ false
+ >>> IS_CHARACTER_JUNK('x').should.be.false
+ false
+ */
return __indexOf.call(ws, ch) >= 0;
};
_formatRangeUnified = function(start, stop) {
- /*
- Convert range to the "ed" format'
- */
+ /*
+ Convert range to the "ed" format'
+ */
var beginning, length;
beginning = start + 1;
length = stop - start;
@@ -1130,45 +1131,45 @@ Class Differ:
unifiedDiff = function(a, b, _arg) {
var file1Range, file2Range, first, fromdate, fromfile, fromfiledate, group, i1, i2, j1, j2, last, line, lines, lineterm, n, started, tag, todate, tofile, tofiledate, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6;
_ref = _arg != null ? _arg : {}, fromfile = _ref.fromfile, tofile = _ref.tofile, fromfiledate = _ref.fromfiledate, tofiledate = _ref.tofiledate, n = _ref.n, lineterm = _ref.lineterm;
+
/*
- Compare two sequences of lines; generate the delta as a unified diff.
+ Compare two sequences of lines; generate the delta as a unified diff.
- Unified diffs are a compact way of showing line changes and a few
- lines of context. The number of context lines is set by 'n' which
- defaults to three.
+ Unified diffs are a compact way of showing line changes and a few
+ lines of context. The number of context lines is set by 'n' which
+ defaults to three.
- By default, the diff control lines (those with ---, +++, or @@) are
- created with a trailing newline.
+ By default, the diff control lines (those with ---, +++, or @@) are
+ created with a trailing newline.
- For inputs that do not have trailing newlines, set the lineterm
- argument to "" so that the output will be uniformly newline free.
+ For inputs that do not have trailing newlines, set the lineterm
+ argument to "" so that the output will be uniformly newline free.
- The unidiff format normally has a header for filenames and modification
- times. Any or all of these may be specified using strings for
- 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.
- The modification times are normally expressed in the ISO 8601 format.
+ The unidiff format normally has a header for filenames and modification
+ times. Any or all of these may be specified using strings for
+ 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.
+ The modification times are normally expressed in the ISO 8601 format.
- Example:
+ Example:
- >>> unifiedDiff('one two three four'.split(' '),
- ... 'zero one tree four'.split(' '), {
- ... fromfile: 'Original'
- ... tofile: 'Current',
- ... fromfiledate: '2005-01-26 23:30:50',
- ... tofiledate: '2010-04-02 10:20:52',
- ... lineterm: ''
- ... })
- [ '--- Original\t2005-01-26 23:30:50',
- '+++ Current\t2010-04-02 10:20:52',
- '@@ -1,4 +1,4 @@',
- '+zero',
- ' one',
- '-two',
- '-three',
- '+tree',
- ' four' ]
- */
-
+ >>> unifiedDiff('one two three four'.split(' '),
+ ... 'zero one tree four'.split(' '), {
+ ... fromfile: 'Original'
+ ... tofile: 'Current',
+ ... fromfiledate: '2005-01-26 23:30:50',
+ ... tofiledate: '2010-04-02 10:20:52',
+ ... lineterm: ''
+ ... })
+ [ '--- Original\t2005-01-26 23:30:50',
+ '+++ Current\t2010-04-02 10:20:52',
+ '@@ -1,4 +1,4 @@',
+ '+zero',
+ ' one',
+ '-two',
+ '-three',
+ '+tree',
+ ' four' ]
+ */
if (fromfile == null) {
fromfile = '';
}
@@ -1233,10 +1234,10 @@ Class Differ:
};
_formatRangeContext = function(start, stop) {
- /*
- Convert range to the "ed" format'
- */
+ /*
+ Convert range to the "ed" format'
+ */
var beginning, length;
beginning = start + 1;
length = stop - start;
@@ -1252,47 +1253,47 @@ Class Differ:
contextDiff = function(a, b, _arg) {
var file1Range, file2Range, first, fromdate, fromfile, fromfiledate, group, i1, i2, j1, j2, last, line, lines, lineterm, n, prefix, started, tag, todate, tofile, tofiledate, _, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6;
_ref = _arg != null ? _arg : {}, fromfile = _ref.fromfile, tofile = _ref.tofile, fromfiledate = _ref.fromfiledate, tofiledate = _ref.tofiledate, n = _ref.n, lineterm = _ref.lineterm;
+
/*
- Compare two sequences of lines; generate the delta as a context diff.
+ Compare two sequences of lines; generate the delta as a context diff.
- Context diffs are a compact way of showing line changes and a few
- lines of context. The number of context lines is set by 'n' which
- defaults to three.
+ Context diffs are a compact way of showing line changes and a few
+ lines of context. The number of context lines is set by 'n' which
+ defaults to three.
- By default, the diff control lines (those with *** or ---) are
- created with a trailing newline. This is helpful so that inputs
- created from file.readlines() result in diffs that are suitable for
- file.writelines() since both the inputs and outputs have trailing
- newlines.
+ By default, the diff control lines (those with *** or ---) are
+ created with a trailing newline. This is helpful so that inputs
+ created from file.readlines() result in diffs that are suitable for
+ file.writelines() since both the inputs and outputs have trailing
+ newlines.
- For inputs that do not have trailing newlines, set the lineterm
- argument to "" so that the output will be uniformly newline free.
+ For inputs that do not have trailing newlines, set the lineterm
+ argument to "" so that the output will be uniformly newline free.
- The context diff format normally has a header for filenames and
- modification times. Any or all of these may be specified using
- strings for 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.
- The modification times are normally expressed in the ISO 8601 format.
- If not specified, the strings default to blanks.
+ The context diff format normally has a header for filenames and
+ modification times. Any or all of these may be specified using
+ strings for 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.
+ The modification times are normally expressed in the ISO 8601 format.
+ If not specified, the strings default to blanks.
- Example:
- >>> a = ['one\n', 'two\n', 'three\n', 'four\n']
- >>> b = ['zero\n', 'one\n', 'tree\n', 'four\n']
- >>> contextDiff(a, b, {fromfile: 'Original', tofile: 'Current'})
- [ '*** Original\n',
- '--- Current\n',
- '***************\n',
- '*** 1,4 ****\n',
- ' one\n',
- '! two\n',
- '! three\n',
- ' four\n',
- '--- 1,4 ----\n',
- '+ zero\n',
- ' one\n',
- '! tree\n',
- ' four\n' ]
- */
-
+ Example:
+ >>> a = ['one\n', 'two\n', 'three\n', 'four\n']
+ >>> b = ['zero\n', 'one\n', 'tree\n', 'four\n']
+ >>> contextDiff(a, b, {fromfile: 'Original', tofile: 'Current'})
+ [ '*** Original\n',
+ '--- Current\n',
+ '***************\n',
+ '*** 1,4 ****\n',
+ ' one\n',
+ '! two\n',
+ '! three\n',
+ ' four\n',
+ '--- 1,4 ----\n',
+ '+ zero\n',
+ ' one\n',
+ '! tree\n',
+ ' four\n' ]
+ */
if (fromfile == null) {
fromfile = '';
}
@@ -1383,61 +1384,61 @@ Class Differ:
if (charjunk == null) {
charjunk = IS_CHARACTER_JUNK;
}
+
/*
- Compare `a` and `b` (lists of strings); return a `Differ`-style delta.
+ Compare `a` and `b` (lists of strings); return a `Differ`-style delta.
- Optional keyword parameters `linejunk` and `charjunk` are for filter
- functions (or None):
+ Optional keyword parameters `linejunk` and `charjunk` are for filter
+ functions (or None):
- - linejunk: A function that should accept a single string argument, and
- return true iff the string is junk. The default is null, and is
- recommended;
+ - linejunk: A function that should accept a single string argument, and
+ return true iff the string is junk. The default is null, and is
+ recommended;
- - charjunk: A function that should accept a string of length 1. The
- default is module-level function IS_CHARACTER_JUNK, which filters out
- whitespace characters (a blank or tab; note: bad idea to include newline
- in this!).
+ - charjunk: A function that should accept a string of length 1. The
+ default is module-level function IS_CHARACTER_JUNK, which filters out
+ whitespace characters (a blank or tab; note: bad idea to include newline
+ in this!).
- Example:
- >>> a = ['one\n', 'two\n', 'three\n']
- >>> b = ['ore\n', 'tree\n', 'emu\n']
- >>> ndiff(a, b)
- [ '- one\n',
- '? ^\n',
- '+ ore\n',
- '? ^\n',
- '- two\n',
- '- three\n',
- '? -\n',
- '+ tree\n',
- '+ emu\n' ]
- */
-
+ Example:
+ >>> a = ['one\n', 'two\n', 'three\n']
+ >>> b = ['ore\n', 'tree\n', 'emu\n']
+ >>> ndiff(a, b)
+ [ '- one\n',
+ '? ^\n',
+ '+ ore\n',
+ '? ^\n',
+ '- two\n',
+ '- three\n',
+ '? -\n',
+ '+ tree\n',
+ '+ emu\n' ]
+ */
return (new Differ(linejunk, charjunk)).compare(a, b);
};
restore = function(delta, which) {
- /*
- Generate one of the two sequences that generated a delta.
-
- Given a `delta` produced by `Differ.compare()` or `ndiff()`, extract
- lines originating from file 1 or 2 (parameter `which`), stripping off line
- prefixes.
-
- Examples:
- >>> a = ['one\n', 'two\n', 'three\n']
- >>> b = ['ore\n', 'tree\n', 'emu\n']
- >>> diff = ndiff(a, b)
- >>> restore(diff, 1)
- [ 'one\n',
- 'two\n',
- 'three\n' ]
- >>> restore(diff, 2)
- [ 'ore\n',
- 'tree\n',
- 'emu\n' ]
- */
+ /*
+ Generate one of the two sequences that generated a delta.
+
+ Given a `delta` produced by `Differ.compare()` or `ndiff()`, extract
+ lines originating from file 1 or 2 (parameter `which`), stripping off line
+ prefixes.
+
+ Examples:
+ >>> a = ['one\n', 'two\n', 'three\n']
+ >>> b = ['ore\n', 'tree\n', 'emu\n']
+ >>> diff = ndiff(a, b)
+ >>> restore(diff, 1)
+ [ 'one\n',
+ 'two\n',
+ 'three\n' ]
+ >>> restore(diff, 2)
+ [ 'ore\n',
+ 'tree\n',
+ 'emu\n' ]
+ */
var line, lines, prefixes, tag, _i, _len, _ref;
tag = {
1: '- ',
diff --git a/src/difflib.coffee b/src/difflib.coffee
index 7cbd396..b28a605 100644
--- a/src/difflib.coffee
+++ b/src/difflib.coffee
@@ -678,7 +678,7 @@ class SequenceMatcher
# shorter sequence
_calculateRatio(min(la, lb), la + lb)
-getCloseMatches = (word, possibilities, n=3, cutoff=0.6) ->
+getCloseMatches = (word, possibilities, n=3, cutoff=0.6, formatter) ->
###
Use SequenceMatcher to return list of the best "good enough" matches.
@@ -694,6 +694,9 @@ getCloseMatches = (word, possibilities, n=3, cutoff=0.6) ->
Optional arg cutoff (default 0.6) is a float in [0, 1]. Possibilities
that don't score at least that similar to word are ignored.
+ Optional arg formatter is a function that is run on each element from possibilities
+ before matching is run.
+
The best (no more than n) matches among the possibilities are returned
in a list, sorted by similarity score, most similar first.
@@ -713,11 +716,14 @@ getCloseMatches = (word, possibilities, n=3, cutoff=0.6) ->
s = new SequenceMatcher()
s.setSeq2(word)
for x in possibilities
+ o = x
+ if formatter
+ x = formatter x
s.setSeq1(x)
if s.realQuickRatio() >= cutoff and
s.quickRatio() >= cutoff and
s.ratio() >= cutoff
- result.push([s.ratio(), x])
+ result.push([s.ratio(), o])
# Move the best scorers to head of list
result = Heap.nlargest(result, n, _arrayCmp)
diff --git a/test/global.coffee b/test/global.coffee
index a5bb19c..09a51b9 100644
--- a/test/global.coffee
+++ b/test/global.coffee
@@ -32,6 +32,17 @@ test '.getCloseMatches', ->
getCloseMatches('wheel', KEYWORDS).should.eql ['when', 'while']
getCloseMatches('accost', KEYWORDS).should.eql ['const']
+ # format callback:
+ m = getCloseMatches 'appel', [
+ { id: 'a', fruit: 'apple' }
+ { id: 'b', fruit: 'pineapple' }
+ { id: 'c', fruit: 'cherry' }
+ { id: 'd', fruit: 'mango' }
+ ], null, 0.5, (i) ->
+ i.fruit
+ m[0].id.should.eql 'a'
+ m[1].id.should.eql 'b'
+
test '._countLeading', ->
_countLeading(' abc', ' ').should.eql 3
diff --git a/util/build.coffee b/util/build.coffee
index c4c5fb0..bf9016f 100755
--- a/util/build.coffee
+++ b/util/build.coffee
@@ -16,8 +16,8 @@ BANNER = '''
build = (dest) ->
browserified = browserify.bundle(__dirname + '/../lib/difflib.js')
namespaced = 'var difflib = (function() {' + browserified + 'return require("/difflib");})();'
- uglified = uglify(namespaced)
- bannered = BANNER + uglified
+ uglified = uglify.minify({'difflib.js': namespaced}, {fromString: true})
+ bannered = BANNER + uglified.code
fs.writeFileSync(dest, bannered)
build(__dirname + '/../dist/difflib-browser.js')