Repository: jneen/parsimmon (js)

Issue:
Tie separator
Shouldn't `tie` accept an optional separator like `tie("\n")`? As it delegates to `.join` it seems pretty reasonable.

Pull request description:
Fixes #248 Adds tieWith
An attempt to implement https://github.com/jneen/parsimmon/issues/248

The problem I have is a coverage drop from 100% to 99.8%. 

```
  278 passing (184ms)


=============================== Coverage summary ===============================
Statements   : 99.81% ( 523/524 )
Branches     : 99.4% ( 165/166 )
Functions    : 100% ( 138/138 )
Lines        : 99.81% ( 523/524 )
================================================================================

```


I guess that's because of the following `!!!` (condition branch).

```js
_.tieWith = function(separator) {
  assertString(separator);
  return this.map(function(args) {
    assertArray(args);
    if (args.length) { // !!!
      assertString(args[0]);
      var s = args[0];
      for (var i = 1; i < args.length; i++) {
        assertString(args[i]);
        s += separator + args[i];
      }
      return s;
    } else { // !!!
      return "";
    }
  });
};
```

I dunno how to create the case where args would be `[]` :(
Hope for your advice.


Patch:
diff --git a/API.md b/API.md
index 5b8ea81..150ebf2 100644
--- a/API.md
+++ b/API.md
@@ -837,9 +837,9 @@ Returns a parser that looks for `string` but does not consume it. Yields the sam
 
 Returns a parser that wants the input to match `regexp`. Yields the same result as `parser`. Equivalent to `parser.skip(Parsimmon.lookahead(regexp))`.
 
-## parser.tie()
+## parser.tieWith(separator)
 
-When called on a parser yielding an array of strings, yields all their strings concatenated. Asserts that its input is actually an array of strings.
+When called on a parser yielding an array of strings, yields all their strings concatenated with the `separator`. Asserts that its input is actually an array of strings.
 
 Example:
 
@@ -848,20 +848,24 @@ var number = Parsimmon.seq(
   Parsimmon.digits,
   Parsimmon.string('.'),
   Parsimmon.digits
-).tie().map(Number);
+).tieWith("").map(Number);
 
 number.tryParse('1.23');
 // => 1.23
 ```
 
-`parser.tie()` is similar to this:
+`parser.tieWith(separator)` is similar to this:
 
 ```js
 parser.map(function(array) {
-  return array.join('');
+  return array.join(separator);
 });
 ```
 
+## parser.tie()
+
+Equivalent to `parser.tieWith("")`.
+
 Note: `parser.tie()` is usually used after `Parsimmon.seq(...parsers)` or `parser.many()`.
 
 ## parser.many()
diff --git a/src/parsimmon.js b/src/parsimmon.js
index dba5957..155a5c5 100644
--- a/src/parsimmon.js
+++ b/src/parsimmon.js
@@ -646,18 +646,28 @@ _.many = function() {
   });
 };
 
-_.tie = function() {
+_.tieWith = function(separator) {
+  assertString(separator);
   return this.map(function(args) {
     assertArray(args);
-    var s = "";
-    for (var i = 0; i < args.length; i++) {
-      assertString(args[i]);
-      s += args[i];
+    if (args.length) {
+      assertString(args[0]);
+      var s = args[0];
+      for (var i = 1; i < args.length; i++) {
+        assertString(args[i]);
+        s += separator + args[i];
+      }
+      return s;
+    } else {
+      return "";
     }
-    return s;
   });
 };
 
+_.tie = function() {
+  return this.tieWith("");
+};
+
 _.times = function(min, max) {
   var self = this;
   if (arguments.length < 2) {


Test patch:
diff --git a/test/core/tieWith.test.js b/test/core/tieWith.test.js
new file mode 100644
index 0000000..5ccafef
--- /dev/null
+++ b/test/core/tieWith.test.js
@@ -0,0 +1,44 @@
+"use strict";
+
+suite("parser.tieWith()", function() {
+  test("handles empty args", function() {
+    var parser = Parsimmon.of([]).tieWith("");
+    var result = parser.tryParse("");
+    assert.strictEqual(result, "");
+  });
+
+  test("concatenates all the results", function() {
+    var parser = Parsimmon.seq(
+      Parsimmon.string("<| "),
+      Parsimmon.letter,
+      Parsimmon.digit,
+      Parsimmon.string(" |>")
+    ).tieWith("+");
+    var text = "<| o7 |>";
+    var result = parser.tryParse(text);
+    assert.strictEqual(result, "<| +o+7+ |>");
+  });
+
+  test("only accept array of string parsers", function() {
+    assert.throws(function() {
+      Parsimmon.of(1)
+        .tieWith("")
+        .tryParse("");
+    });
+    assert.throws(function() {
+      Parsimmon.of([1])
+        .tieWith("")
+        .tryParse("");
+    });
+    assert.throws(function() {
+      Parsimmon.of(["1", 2])
+        .tieWith("")
+        .tryParse("");
+    });
+    assert.doesNotThrow(function() {
+      Parsimmon.of(["1"])
+        .tieWith("")
+        .tryParse("");
+    });
+  });
+});