Benjamin Dumke-von der Ehe avatar Benjamin Dumke-von der Ehe committed 6e7bb34

also pass yield (better: Yield) as a parameter to the generator function

Comments (0)

Files changed (2)

 /*!
- * Copyright (c) 2011 Benjamin Dumke
+ * Copyright (c) 2011 Benjamin Dumke-von der Ehe
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
         return function (g, thisObj) {
             var stopped = false,
                 index = 0,
-                gen = {
-                    yield: function (val) {
-                        if (stopped)
-                            throw new IterationError("yield after end of iteration");
-                        var send = g.call(thisObj, val, index, stopIteration);
-                        index++;
-                        return send;
-                    },
-                    yieldMany: function (source) { asGenerator(source).forEach(function (val) { gen.yield(val); }) },
-                    stop: stopIteration
+                Yield = function (val) {
+                    if (stopped)
+                        throw new IterationError("yield after end of iteration");
+                    var send = g.call(thisObj, val, index, stopIteration);
+                    index++;
+                    return send;
+                },
+                yieldMany = function (source) {
+                    asGenerator(source).forEach(function (val) { Yield(val); })
                 };
             try {
-                f.call(gen);
+                f.call({"yield": Yield, yieldMany: yieldMany, stop: stopIteration}, Yield, yieldMany);
             } catch (ex) {
                 if (ex !== BreakIteration)
                     throw ex;
     };
     
     var makeForEach_fromArray = function (arr) {
-        return makeForEach_fromFunction(function () {
+        return makeForEach_fromFunction(function (Yield) {
             var len = arr.length;
             for (var i = 0; i < len; i++)
                 if (i in arr)
-                    this.yield(arr[i]);
+                    Yield(arr[i]);
         });
     };
     
     var makeForEach_fromObject = function (obj) {
-        return makeForEach_fromFunction(function () {
+        return makeForEach_fromFunction(function (Yield) {
             for (var key in obj)
                 if (obj.hasOwnProperty(key))
-                    this.yield([key, obj[key]]);
+                    Yield([key, obj[key]]);
         });
     };
 
         },
         filter: function (pred, thisObj) {
             var source = this;
-            return new Generator(function () {
-                var gen = this;
+            return new Generator(function (Yield) {
                 source.forEach(function (val) {
                     if (pred.call(thisObj, val))
-                        gen.yield(val);
+                        Yield(val);
                 });
             });
         },
         take: function (n) {
             var source = this;
-            return new Generator(function () {
-                var gen = this;
-                source.forEach(function (val, index) {
+            return new Generator(function (Yield) {
+                source.forEach(function (val, index, stop) {
                     if (index >= n)
-                        gen.stop();
-                    gen.yield(val);
+                        stop();
+                    Yield(val);
                 });
             });
         },
         skip: function (n) {
             var source = this;
-            return new Generator(function () {
-                var gen = this;
+            return new Generator(function (Yield) {
                 source.forEach(function(val, index) {
                     if (index >= n)
-                        gen.yield(val);
+                        Yield(val);
                 });
             });
         },
         map: function (f, thisObj) {
             var source = this;
-            return new Generator(function () {
-                var gen = this;
+            return new Generator(function (Yield) {
                 source.forEach(function (val) {
-                    gen.yield(f.call(thisObj, val));
+                    Yield(f.call(thisObj, val));
                 });
             });
         },
             
             var source = this;
             
-            return new Generator(function () {
-                var len = arr.length,
-                    gen = this;
+            return new Generator(function (Yield) {
+                var len = arr.length;
                     
-                source.forEach(function (val, index) {
+                source.forEach(function (val, index, stop) {
                     if (index >= len)
-                        gen.stop();
-                    gen.yield(zipper(val, arr[index]));
+                        stop();
+                    Yield(zipper(val, arr[index]));
                 });
             });
         },
         },
         and: function (other) {
             var source = this;
-            return new Generator(function () {
-                this.yieldMany(source);
-                this.yieldMany(other);
+            return new Generator(function (Yield, yieldMany) {
+                yieldMany(source);
+                yieldMany(other);
             });
         },
         takeWhile: function (pred) {
             var source = this;
             
-            return new Generator(function () {
-                var gen = this;
-                source.forEach(function (val) {
+            return new Generator(function (Yield) {
+                source.forEach(function (val, index, stop) {
                     if (pred(val))
-                        gen.yield(val);
+                        Yield(val);
                     else
-                        gen.stop();
+                        stop();
                 });
             });
         },
         skipWhile: function (pred) {
             var source = this;
             
-            return new Generator(function () {
-                var gen = this,
-                    skipping = true;
+            return new Generator(function (Yield) {
+                var skipping = true;
                     
                 source.forEach(function (val) {
                     skipping = skipping && pred(val);
                     if (!skipping)
-                        gen.yield(val);
+                        Yield(val);
                 });                    
             });
         },
         groupBy: function (grouper) {
             var source = this;
 
-            return new Generator(function () {
+            return new Generator(function (Yield, yieldMany) {
                 var groups = [],
                     group_contents = [];
                     
                     }
                 });
             
-                this.yieldMany(new Generator(groups).zipWithArray(group_contents, function (group, contents) {
+                yieldMany(new Generator(groups).zipWithArray(group_contents, function (group, contents) {
                     var result = new Generator(contents);
                     result.key = group;
                     return result;
         },
         sortBy: function (keyFunc) {
             var source = this;
-            return new Generator(function () {
+            return new Generator(function (Yield) {
                 var arr = source.toArray(),
-                    indexes = Range(0, arr.length).toArray(),
-                    gen = this;
+                    indexes = Range(0, arr.length).toArray();
                 
                 indexes.sort(function (a, b) {
                     var ka = keyFunc(arr[a]),
                     throw new TypeError("cannot compare " + ka + " and " + kb);
                 });
                 new Generator(indexes).forEach(function (index) {
-                    gen.yield(arr[index]);
+                    Yield(arr[index]);
                 });
             });
         }
         var i = start;
         if (typeof step === "undefined")
             step = 1;
-        return new Generator(function () {
+        return new Generator(function (Yield) {
             while (true) {
-                this.yield(i);
+                Yield(i);
                 i += step;
             }
         });
 <script>
 
     function test(name, testFunction) {
+        document.write("<div style='float:left; width: 50%;'>");
         document.write(name + ": ");
         var result, exception;
         try {
         } catch (e) {
             exception = e;
         }
+        
         if (result)
-            document.write("<b style='color:green'>passed</b><br>");
+            document.write("<b style='color:green'>passed</b>");
         else if (exception)            
-            document.write("<b style='color:red'>exception: " + exception.message + "</b><br>");
+            document.write("<b style='color:red'>exception: " + exception.message + "</b>");
         else
-            document.write("<b style='color:red'>failed</b><br>");
+            document.write("<b style='color:red'>failed</b>");
+        document.write("</div>");
     }
 
     function arrEqual (a1, a2) {
         return arrEqual(a, roundtrip);
     });
     
-    test("function constructor", function () {
+    test("function constructor with this.yield", function () {
         var g = Generator(function () {
             this.yield(13);
             this.yield(null);
         return arrEqual(a, g.toArray());
     });
     
+    test("function constructor with parameter Yield", function () {
+        var g = Generator(function (Yield) {
+            Yield(13);
+            Yield(null);
+            Yield(helloWorld);
+            Yield(-10.5);
+            Yield("lolcat");
+        });
+        return arrEqual(a, g.toArray());
+    });
+    
     test("object constructor", function () {
         var g = Generator({
             a: 13,
     
     });
     
-    test("send to yield", function () {
+    test("send to yieldwith this.yield", function () {
         var gen = Generator(function () {
             this.yield("first");
             var other = this.yield("second");
         });
         return arrEqual(arr, ["first", "second", "third", "end"]);
     });
+
+    test("send to yield with parameter Yield", function () {
+        var gen = Generator(function (Yield) {
+            Yield("first");
+            var other = this.yield("second");
+            Yield(other);
+            Yield("end");
+        });
+        var arr = [];
+        gen.forEach(function (val) {
+            arr.push(val);
+            return "third";
+        });
+        return arrEqual(arr, ["first", "second", "third", "end"]);
+    });
     
-    test("stop", function () {
+    
+    test("stop with this.yield", function () {
         var good = true;
         var gen = Generator(function () {
             this.yield(42);
         return good && lastValue === -5;
     });
        
-    test("cleanup when stopping outer", function () {
+    test("stop with parameter Yield", function () {
+        var good = true;
+        var gen = Generator(function (Yield) {
+            Yield(42);
+            Yield(1337);
+            Yield(-5);
+            good = false;
+            Yield(100);
+        });
+        var lastValue;
+        gen.forEach(function (val, index, stop) {
+            lastValue = val;
+            if (val < 0)
+                stop();
+        });
+        return good && lastValue === -5;
+    });
+       
+    test("cleanup when stopping outer with this.yield", function () {
         var innerClean = false,
             outerClean = false;
         
         return arrEqual(result, [1, 2]) && innerClean && outerClean;
     });
 
-    test("cleanup when stopping inner", function () {
+    test("cleanup when stopping outer with paramater Yield", function () {
+        var innerClean = false,
+            outerClean = false;
+        
+        var inner = Generator(function (Yield, yieldMany) {
+            try {
+                yieldMany(Generator([1, 2, 3, 4]));
+            } finally {
+                innerClean = true;
+            }
+        });
+        
+        var outer = Generator(function (Yield) {
+            var that = this;
+            try {
+                inner.forEach(function (val, index) {
+                    Yield(val);
+                    if (val > 1)
+                        that.stop();
+                });
+            } finally {
+                outerClean = true;
+            }
+        });
+
+        var result = outer.toArray();
+        return arrEqual(result, [1, 2]) && innerClean && outerClean;
+    });
+
+    test("cleanup when stopping inner with this.yield", function () {
         var innerClean = false,
             outerClean = false;
         
         return arrEqual(result, [1, 2]) && innerClean && outerClean;
     });
     
-    test("yieldMany", function () {
+    test("cleanup when stopping inner with parameter Yield", function () {
+        var innerClean = false,
+            outerClean = false;
+        
+        var inner = Generator(function (Yield, yieldMany) {
+            try {
+                yieldMany(Generator([1, 2, 3, 4]));
+            } finally {
+                innerClean = true;
+            }
+        });
+        
+        var outer = Generator(function (Yield) {
+            var that = this;
+            try {
+                inner.forEach(function (val, index, stop) {
+                    Yield(val);
+                    if (val > 1)
+                        stop();
+                });
+            } finally {
+                outerClean = true;
+            }
+        });
+
+        var result = outer.toArray();
+        return arrEqual(result, [1, 2]) && innerClean && outerClean;
+    });
+    
+    test("this.yieldMany", function () {
         
         var nested = [ [1, 7], 9, [3, [1, 8], 5], [2, [2, 3, 4]]];
         
         return arrEqual(flatten(nested).toArray(), [1, 7, 9, 3, 1, 8, 5, 2, 2, 3, 4]);
     });
 
-    test("yieldMany with array", function () {
+    test("parameter yieldMany", function () {
+        
+        var nested = [ [1, 7], 9, [3, [1, 8], 5], [2, [2, 3, 4]]];
+        
+        var flatten = function (element) {
+            if (typeof element === "number")
+                return Generator([element]);
+            
+            return Generator(function (Yield, yieldMany) {
+                Generator(element).forEach(function (val) {
+                    yieldMany(flatten(val));
+                });
+            });
+        };
+        
+        return arrEqual(flatten(nested).toArray(), [1, 7, 9, 3, 1, 8, 5, 2, 2, 3, 4]);
+    });
+
+    test("this.yieldMany with array", function () {
         
         var nested = [ [1, 7], 9, [3, [1, 8], 5], [2, [2, 3, 4]]];
         
         return arrEqual(flatten(nested), [1, 7, 9, 3, 1, 8, 5, 2, 2, 3, 4]);
     });
     
+    test("parameter yieldMany with array", function () {
+        
+        var nested = [ [1, 7], 9, [3, [1, 8], 5], [2, [2, 3, 4]]];
+        
+        var flatten = function (element) {
+            if (typeof element === "number")
+                return [element];
+            
+            return Generator(function (Yield, yieldMany) {
+                Generator(element).forEach(function (val) {
+                    yieldMany(flatten(val));
+                });
+            }).toArray();
+        };
+        
+        return arrEqual(flatten(nested), [1, 7, 9, 3, 1, 8, 5, 2, 2, 3, 4]);
+    });
+    
     test("changing source array", function () {
         var arr = ["x", 42, null];
         var gen = Generator(arr);
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.