diff --git a/koans/AboutApplyingWhatWeHaveLearnt.js b/koans/AboutApplyingWhatWeHaveLearnt.js index eccc93763..9ae9451ae 100644 --- a/koans/AboutApplyingWhatWeHaveLearnt.js +++ b/koans/AboutApplyingWhatWeHaveLearnt.js @@ -2,112 +2,142 @@ var _; //globals describe("About Applying What We Have Learnt", function() { - var products; - - beforeEach(function () { - products = [ - { name: "Sonoma", ingredients: ["artichoke", "sundried tomatoes", "mushrooms"], containsNuts: false }, - { name: "Pizza Primavera", ingredients: ["roma", "sundried tomatoes", "goats cheese", "rosemary"], containsNuts: false }, - { name: "South Of The Border", ingredients: ["black beans", "jalapenos", "mushrooms"], containsNuts: false }, - { name: "Blue Moon", ingredients: ["blue cheese", "garlic", "walnuts"], containsNuts: true }, - { name: "Taste Of Athens", ingredients: ["spinach", "kalamata olives", "sesame seeds"], containsNuts: true } - ]; - }); - - /*********************************************************************************/ - - it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (imperative)", function () { - - var i,j,hasMushrooms, productsICanEat = []; - - for (i = 0; i < products.length; i+=1) { - if (products[i].containsNuts === false) { - hasMushrooms = false; - for (j = 0; j < products[i].ingredients.length; j+=1) { - if (products[i].ingredients[j] === "mushrooms") { - hasMushrooms = true; - } + var products; + + beforeEach(function() { + products = [ + { name: "Sonoma", ingredients: ["artichoke", "sundried tomatoes", "mushrooms"], containsNuts: false }, + { name: "Pizza Primavera", ingredients: ["roma", "sundried tomatoes", "goats cheese", "rosemary"], containsNuts: false }, + { name: "South Of The Border", ingredients: ["black beans", "jalapenos", "mushrooms"], containsNuts: false }, + { name: "Blue Moon", ingredients: ["blue cheese", "garlic", "walnuts"], containsNuts: true }, + { name: "Taste Of Athens", ingredients: ["spinach", "kalamata olives", "sesame seeds"], containsNuts: true } + ]; + }); + + /*********************************************************************************/ + + it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (imperative)", function() { + + var i, j, hasMushrooms, productsICanEat = []; + + for (i = 0; i < products.length; i += 1) { + if (products[i].containsNuts === false) { + hasMushrooms = false; + for (j = 0; j < products[i].ingredients.length; j += 1) { + if (products[i].ingredients[j] === "mushrooms") { + hasMushrooms = true; + } + } + if (!hasMushrooms) productsICanEat.push(products[i]); } - if (!hasMushrooms) productsICanEat.push(products[i]); } - } - expect(productsICanEat.length).toBe(FILL_ME_IN); - }); + expect(productsICanEat.length).toBe(1); + }); - it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (functional)", function () { + it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (functional)", function() { - var productsICanEat = []; + var productsICanEat = []; - /* solve using filter() & all() / any() */ + /* solve using filter() & all() / any() */ - expect(productsICanEat.length).toBe(FILL_ME_IN); - }); + // 1) Решение с помошью filter() & all() + var productsWithoutNuts = products.filter(p => !p.containsNuts); - /*********************************************************************************/ + productsWithoutNuts.forEach(pwn => { + if (_(pwn.ingredients).all(i => i !== "mushrooms")) { + productsICanEat.push(pwn); + } + }) + + // 2) Решение с помошью any() + // for (const p of products) { + // if (p.containsNuts || _(p.ingredients).any(i => i === "mushrooms")) { + // continue; + // } + + // productsICanEat.push(p); + // } - it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (imperative)", function () { + expect(productsICanEat.length).toBe(1); + }); - var sum = 0; - for(var i=1; i<1000; i+=1) { - if (i % 3 === 0 || i % 5 === 0) { - sum += i; - } - } + /*********************************************************************************/ - expect(sum).toBe(FILL_ME_IN); - }); + it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (imperative)", function() { + + var sum = 0; + for (var i = 1; i < 1000; i += 1) { + if (i % 3 === 0 || i % 5 === 0) { + sum += i; + } + } - it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (functional)", function () { + expect(sum).toBe(233168); + }); - var sum = FILL_ME_IN; /* try chaining range() and reduce() */ + it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (functional)", function() { - expect(233168).toBe(FILL_ME_IN); - }); + var sum = _.range(1000).reduce((sum, x) => (x % 3 === 0 || x % 5 === 0) ? sum + x : sum); /* try chaining range() and reduce() */ - /*********************************************************************************/ - it("should count the ingredient occurrence (imperative)", function () { - var ingredientCount = { "{ingredient name}": 0 }; + expect(233168).toBe(sum); + }); - for (i = 0; i < products.length; i+=1) { - for (j = 0; j < products[i].ingredients.length; j+=1) { - ingredientCount[products[i].ingredients[j]] = (ingredientCount[products[i].ingredients[j]] || 0) + 1; + /*********************************************************************************/ + it("should count the ingredient occurrence (imperative)", function() { + var ingredientCount = { "{ingredient name}": 0 }; + + for (i = 0; i < products.length; i += 1) { + for (j = 0; j < products[i].ingredients.length; j += 1) { + ingredientCount[products[i].ingredients[j]] = (ingredientCount[products[i].ingredients[j]] || 0) + 1; + } } - } - expect(ingredientCount['mushrooms']).toBe(FILL_ME_IN); - }); + expect(ingredientCount['mushrooms']).toBe(2); + }); + + it("should count the ingredient occurrence (functional)", function() { + var ingredientCount = { "{ingredient name}": 0 }; - it("should count the ingredient occurrence (functional)", function () { - var ingredientCount = { "{ingredient name}": 0 }; + for (i = 0; i < products.length; i += 1) { + for (j = 0; j < products[i].ingredients.length; j += 1) { + ingredientCount[products[i].ingredients[j]] = (ingredientCount[products[i].ingredients[j]] || 0) + 1; + } + } - /* chain() together map(), flatten() and reduce() */ + /* chain() together map(), flatten() and reduce() */ + var mushroomsCount = _(products) + .chain() + .map(p => p.ingredients) + .flatten() + .reduce((sum, x) => x === 'mushrooms' ? sum + 1 : sum, 0) + .value(); - expect(ingredientCount['mushrooms']).toBe(FILL_ME_IN); - }); + expect(ingredientCount['mushrooms']).toBe(mushroomsCount); + }); - /*********************************************************************************/ - /* UNCOMMENT FOR EXTRA CREDIT */ - /* - it("should find the largest prime factor of a composite number", function () { + /*********************************************************************************/ + /* UNCOMMENT FOR EXTRA CREDIT */ + /* + it("should find the largest prime factor of a composite number", function () { - }); + }); - it("should find the largest palindrome made from the product of two 3 digit numbers", function () { + it("should find the largest palindrome made from the product of two 3 digit numbers", function () { - }); + }); - it("should find the smallest number divisible by each of the numbers 1 to 20", function () { + it("should find the smallest number divisible by each of the numbers 1 to 20", function () { - }); + }); - it("should find the difference between the sum of the squares and the square of the sums", function () { + it("should find the difference between the sum of the squares and the square of the sums", function () { - }); + }); - it("should find the 10001st prime", function () { + it("should find the 10001st prime", function () { - }); - */ -}); + }); + */ +}); \ No newline at end of file diff --git a/koans/AboutArrays.js b/koans/AboutArrays.js index f9b33f8cc..c4ff543e8 100644 --- a/koans/AboutArrays.js +++ b/koans/AboutArrays.js @@ -1,97 +1,99 @@ describe("About Arrays", function() { - //We shall contemplate truth by testing reality, via spec expectations. - it("should create arrays", function() { - var emptyArray = []; - expect(typeof(emptyArray)).toBe(FILL_ME_IN); //A mistake? - http://javascript.crockford.com/remedial.html - expect(emptyArray.length).toBe(FILL_ME_IN); - - var multiTypeArray = [0, 1, "two", function () { return 3; }, {value1: 4, value2: 5}, [6, 7]]; - expect(multiTypeArray[0]).toBe(FILL_ME_IN); - expect(multiTypeArray[2]).toBe(FILL_ME_IN); - expect(multiTypeArray[3]()).toBe(FILL_ME_IN); - expect(multiTypeArray[4].value1).toBe(FILL_ME_IN); - expect(multiTypeArray[4]["value2"]).toBe(FILL_ME_IN); - expect(multiTypeArray[5][0]).toBe(FILL_ME_IN); - }); - - it("should understand array literals", function () { - var array = []; - expect(array).toEqual([]); - - array[0] = 1; - expect(array).toEqual([1]); - - array[1] = 2; - expect(array).toEqual([1, FILL_ME_IN]); - - array.push(3); - expect(array).toEqual(FILL_ME_IN); - }); - - it("should understand array length", function () { - var fourNumberArray = [1, 2, 3, 4]; - - expect(fourNumberArray.length).toBe(FILL_ME_IN); - fourNumberArray.push(5, 6); - expect(fourNumberArray.length).toBe(FILL_ME_IN); - - var tenEmptyElementArray = new Array(10); - expect(tenEmptyElementArray.length).toBe(FILL_ME_IN); - - tenEmptyElementArray.length = 5; - expect(tenEmptyElementArray.length).toBe(FILL_ME_IN); - }); - - it("should slice arrays", function () { - var array = ["peanut", "butter", "and", "jelly"]; - - expect(array.slice(0, 1)).toEqual(FILL_ME_IN); - expect(array.slice(0, 2)).toEqual(FILL_ME_IN); - expect(array.slice(2, 2)).toEqual(FILL_ME_IN); - expect(array.slice(2, 20)).toEqual(FILL_ME_IN); - expect(array.slice(3, 0)).toEqual(FILL_ME_IN); - expect(array.slice(3, 100)).toEqual(FILL_ME_IN); - expect(array.slice(5, 1)).toEqual(FILL_ME_IN); - }); - - it("should know array references", function () { - var array = [ "zero", "one", "two", "three", "four", "five" ]; - - function passedByReference(refArray) { - refArray[1] = "changed in function"; - } - passedByReference(array); - expect(array[1]).toBe(FILL_ME_IN); - - var assignedArray = array; - assignedArray[5] = "changed in assignedArray"; - expect(array[5]).toBe(FILL_ME_IN); - - var copyOfArray = array.slice(); - copyOfArray[3] = "changed in copyOfArray"; - expect(array[3]).toBe(FILL_ME_IN); - }); - - it("should push and pop", function () { - var array = [1, 2]; - array.push(3); - - expect(array).toEqual(FILL_ME_IN); - - var poppedValue = array.pop(); - expect(poppedValue).toBe(FILL_ME_IN); - expect(array).toEqual(FILL_ME_IN); - }); - - it("should know about shifting arrays", function () { - var array = [1, 2]; - - array.unshift(3); - expect(array).toEqual(FILL_ME_IN); - - var shiftedValue = array.shift(); - expect(shiftedValue).toEqual(FILL_ME_IN); - expect(array).toEqual(FILL_ME_IN); - }); -}); + //We shall contemplate truth by testing reality, via spec expectations. + it("should create arrays", function() { + var emptyArray = []; + expect(typeof(emptyArray)).toBe("object"); //A mistake? - http://javascript.crockford.com/remedial.html + expect(emptyArray.length).toBe(0); + + var multiTypeArray = [0, 1, "two", function() { return 3; }, { value1: 4, value2: 5 }, + [6, 7] + ]; + expect(multiTypeArray[0]).toBe(0); + expect(multiTypeArray[2]).toBe("two"); + expect(multiTypeArray[3]()).toBe(3); + expect(multiTypeArray[4].value1).toBe(4); + expect(multiTypeArray[4]["value2"]).toBe(5); + expect(multiTypeArray[5][0]).toBe(6); + }); + + it("should understand array literals", function() { + var array = []; + expect(array).toEqual([]); + + array[0] = 1; + expect(array).toEqual([1]); + + array[1] = 2; + expect(array).toEqual([1, 2]); + + array.push(3); + expect(array).toEqual([1, 2, 3]); + }); + + it("should understand array length", function() { + var fourNumberArray = [1, 2, 3, 4]; + + expect(fourNumberArray.length).toBe(4); + fourNumberArray.push(5, 6); + expect(fourNumberArray.length).toBe(6); + + var tenEmptyElementArray = new Array(10); + expect(tenEmptyElementArray.length).toBe(10); + + tenEmptyElementArray.length = 5; + expect(tenEmptyElementArray.length).toBe(5); + }); + + it("should slice arrays", function() { + var array = ["peanut", "butter", "and", "jelly"]; + + expect(array.slice(0, 1)).toEqual(["peanut"]); + expect(array.slice(0, 2)).toEqual(["peanut", "butter"]); + expect(array.slice(2, 2)).toEqual([]); + expect(array.slice(2, 20)).toEqual(["and", "jelly"]); + expect(array.slice(3, 0)).toEqual([]); + expect(array.slice(3, 100)).toEqual(["jelly"]); + expect(array.slice(5, 1)).toEqual([]); + }); + + it("should know array references", function() { + var array = ["zero", "one", "two", "three", "four", "five"]; + + function passedByReference(refArray) { + refArray[1] = "changed in function"; + } + passedByReference(array); + expect(array[1]).toBe("changed in function"); + + var assignedArray = array; + assignedArray[5] = "changed in assignedArray"; + expect(array[5]).toBe("changed in assignedArray"); + + var copyOfArray = array.slice(); + copyOfArray[3] = "changed in copyOfArray"; + expect(array[3]).toBe("three"); + }); + + it("should push and pop", function() { + var array = [1, 2]; + array.push(3); + + expect(array).toEqual([1, 2, 3]); + + var poppedValue = array.pop(); + expect(poppedValue).toBe(3); + expect(array).toEqual([1, 2]); + }); + + it("should know about shifting arrays", function() { + var array = [1, 2]; + + array.unshift(3); + expect(array).toEqual([3, 1, 2]); + + var shiftedValue = array.shift(); + expect(shiftedValue).toEqual(3); + expect(array).toEqual([1, 2]); + }); +}); \ No newline at end of file diff --git a/koans/AboutExpects.js b/koans/AboutExpects.js index 7d1a827cb..f2dbf5044 100644 --- a/koans/AboutExpects.js +++ b/koans/AboutExpects.js @@ -1,40 +1,40 @@ describe('About Expects', function() { - // We shall contemplate truth by testing reality, via spec expectations. - it('should expect true', function() { - - // Your journey begins here: Replace the word false with true - expect(false).toBeTruthy(); - }); - - // To understand reality, we must compare our expectations against reality. - it('should expect equality', function() { - var expectedValue = FILL_ME_IN; - var actualValue = 1 + 1; - - expect(actualValue === expectedValue).toBeTruthy(); - }); - - // Some ways of asserting equality are better than others. - it('should assert equality a better way', function() { - var expectedValue = FILL_ME_IN; - var actualValue = 1 + 1; - - // toEqual() compares using common sense equality. - expect(actualValue).toEqual(expectedValue); - }); - - // Sometimes you need to be precise about what you "type." - it('should assert equality with ===', function() { - var expectedValue = FILL_ME_IN; - var actualValue = (1 + 1).toString(); - - // toBe() will always use === to compare. - expect(actualValue).toBe(expectedValue); - }); - - // Sometimes we will ask you to fill in the values. - it('should have filled in values', function() { - expect(1 + 1).toEqual(FILL_ME_IN); - }); -}); + // We shall contemplate truth by testing reality, via spec expectations. + it('should expect true', function() { + + // Your journey begins here: Replace the word false with true + expect(true).toBeTruthy(); + }); + + // To understand reality, we must compare our expectations against reality. + it('should expect equality', function() { + var expectedValue = 2; + var actualValue = 1 + 1; + + expect(actualValue === expectedValue).toBeTruthy(); + }); + + // Some ways of asserting equality are better than others. + it('should assert equality a better way', function() { + var expectedValue = 2; + var actualValue = 1 + 1; + + // toEqual() compares using common sense equality. + expect(actualValue).toEqual(expectedValue); + }); + + // Sometimes you need to be precise about what you "type." + it('should assert equality with ===', function() { + var expectedValue = '2'; + var actualValue = (1 + 1).toString(); + + // toBe() will always use === to compare. + expect(actualValue).toBe(expectedValue); + }); + + // Sometimes we will ask you to fill in the values. + it('should have filled in values', function() { + expect(1 + 1).toEqual(2); + }); +}); \ No newline at end of file diff --git a/koans/AboutFunctions.js b/koans/AboutFunctions.js index 569100806..30af98b40 100644 --- a/koans/AboutFunctions.js +++ b/koans/AboutFunctions.js @@ -1,100 +1,100 @@ describe("About Functions", function() { - it("should declare functions", function() { + it("should declare functions", function() { - function add(a, b) { - return a + b; - } + function add(a, b) { + return a + b; + } - expect(add(1, 2)).toBe(FILL_ME_IN); - }); + expect(add(1, 2)).toBe(3); + }); - it("should know internal variables override outer variables", function () { - var message = "Outer"; + it("should know internal variables override outer variables", function() { + var message = "Outer"; - function getMessage() { - return message; - } + function getMessage() { + return message; + } - function overrideMessage() { - var message = "Inner"; - return message; - } + function overrideMessage() { + var message = "Inner"; + return message; + } - expect(getMessage()).toBe(FILL_ME_IN); - expect(overrideMessage()).toBe(FILL_ME_IN); - expect(message).toBe(FILL_ME_IN); - }); + expect(getMessage()).toBe("Outer"); + expect(overrideMessage()).toBe("Inner"); + expect(message).toBe("Outer"); + }); - it("should have lexical scoping", function () { - var variable = "top-level"; - function parentfunction() { - var variable = "local"; - function childfunction() { - return variable; - } - return childfunction(); - } - expect(parentfunction()).toBe(FILL_ME_IN); - }); + it("should have lexical scoping", function() { + var variable = "top-level"; - it("should use lexical scoping to synthesise functions", function () { + function parentfunction() { + var variable = "local"; - function makeMysteryFunction(makerValue) - { - var newFunction = function doMysteriousThing(param) - { - return makerValue + param; - }; - return newFunction; - } + function childfunction() { + return variable; + } + return childfunction(); + } + expect(parentfunction()).toBe("local"); + }); - var mysteryFunction3 = makeMysteryFunction(3); - var mysteryFunction5 = makeMysteryFunction(5); + it("should use lexical scoping to synthesise functions", function() { - expect(mysteryFunction3(10) + mysteryFunction5(5)).toBe(FILL_ME_IN); - }); + function makeMysteryFunction(makerValue) { + var newFunction = function doMysteriousThing(param) { + return makerValue + param; + }; + return newFunction; + } - it("should allow extra function arguments", function () { + var mysteryFunction3 = makeMysteryFunction(3); + var mysteryFunction5 = makeMysteryFunction(5); - function returnFirstArg(firstArg) { - return firstArg; - } + expect(mysteryFunction3(10) + mysteryFunction5(5)).toBe(23); + }); - expect(returnFirstArg("first", "second", "third")).toBe(FILL_ME_IN); + it("should allow extra function arguments", function() { - function returnSecondArg(firstArg, secondArg) { - return secondArg; - } + function returnFirstArg(firstArg) { + return firstArg; + } - expect(returnSecondArg("only give first arg")).toBe(FILL_ME_IN); + expect(returnFirstArg("first", "second", "third")).toBe("first"); - function returnAllArgs() { - var argsArray = []; - for (var i = 0; i < arguments.length; i += 1) { - argsArray.push(arguments[i]); - } - return argsArray.join(","); - } + function returnSecondArg(firstArg, secondArg) { + return secondArg; + } - expect(returnAllArgs("first", "second", "third")).toBe(FILL_ME_IN); - }); + expect(returnSecondArg("only give first arg")).toBe(undefined); - it("should pass functions as values", function () { + function returnAllArgs() { + var argsArray = []; + for (var i = 0; i < arguments.length; i += 1) { + argsArray.push(arguments[i]); + } + return argsArray.join(","); + } - var appendRules = function (name) { - return name + " rules!"; - }; + expect(returnAllArgs("first", "second", "third")).toBe("first,second,third"); + }); - var appendDoubleRules = function (name) { - return name + " totally rules!"; - }; + it("should pass functions as values", function() { - var praiseSinger = { givePraise: appendRules }; - expect(praiseSinger.givePraise("John")).toBe(FILL_ME_IN); + var appendRules = function(name) { + return name + " rules!"; + }; - praiseSinger.givePraise = appendDoubleRules; - expect(praiseSinger.givePraise("Mary")).toBe(FILL_ME_IN); + var appendDoubleRules = function(name) { + return name + " totally rules!"; + }; - }); -}); + var praiseSinger = { givePraise: appendRules }; + expect(praiseSinger.givePraise("John")).toBe("John rules!"); + + praiseSinger.givePraise = appendDoubleRules; + expect(praiseSinger.givePraise("Mary")).toBe("Mary totally rules!"); + + }); +}); \ No newline at end of file diff --git a/koans/AboutHigherOrderFunctions.js b/koans/AboutHigherOrderFunctions.js index 07c416792..0a493017e 100644 --- a/koans/AboutHigherOrderFunctions.js +++ b/koans/AboutHigherOrderFunctions.js @@ -5,86 +5,90 @@ var _; //globals that you would expect in Prototype.js (or Ruby), but without extending any of the built-in JavaScript objects. It's the tie to go along with jQuery's tux." */ -describe("About Higher Order Functions", function () { - - it("should use filter to return array items that meet a criteria", function () { - var numbers = [1,2,3]; - var odd = _(numbers).filter(function (x) { return x % 2 !== 0 }); - - expect(odd).toEqual(FILL_ME_IN); - expect(odd.length).toBe(FILL_ME_IN); - expect(numbers.length).toBe(FILL_ME_IN); - }); - - it("should use 'map' to transform each element", function () { - var numbers = [1, 2, 3]; - var numbersPlus1 = _(numbers).map(function(x) { return x + 1 }); - - expect(numbersPlus1).toEqual(FILL_ME_IN); - expect(numbers).toEqual(FILL_ME_IN); - }); - - it("should use 'reduce' to update the same result on each iteration", function () { - var numbers = [1, 2, 3]; - var reduction = _(numbers).reduce( - function(/* result from last call */ memo, /* current */ x) { return memo + x }, /* initial */ 0); - - expect(reduction).toBe(FILL_ME_IN); - expect(numbers).toEqual(FILL_ME_IN); - }); - - it("should use 'forEach' for simple iteration", function () { - var numbers = [1,2,3]; - var msg = ""; - var isEven = function (item) { - msg += (item % 2) === 0; - }; - - _(numbers).forEach(isEven); - - expect(msg).toEqual(FILL_ME_IN); - expect(numbers).toEqual(FILL_ME_IN); - }); - - it("should use 'all' to test whether all items pass condition", function () { - var onlyEven = [2,4,6]; - var mixedBag = [2,4,5,6]; - - var isEven = function(x) { return x % 2 === 0 }; - - expect(_(onlyEven).all(isEven)).toBe(FILL_ME_IN); - expect(_(mixedBag).all(isEven)).toBe(FILL_ME_IN); - }); - - it("should use 'any' to test if any items passes condition" , function () { - var onlyEven = [2,4,6]; - var mixedBag = [2,4,5,6]; - - var isEven = function(x) { return x % 2 === 0 }; - - expect(_(onlyEven).any(isEven)).toBe(FILL_ME_IN); - expect(_(mixedBag).any(isEven)).toBe(FILL_ME_IN); - }); - - it("should use range to generate an array", function() { - expect(_.range(3)).toEqual(FILL_ME_IN); - expect(_.range(1, 4)).toEqual(FILL_ME_IN); - expect(_.range(0, -4, -1)).toEqual(FILL_ME_IN); - }); - - it("should use flatten to make nested arrays easy to work with", function() { - expect(_([ [1, 2], [3, 4] ]).flatten()).toEqual(FILL_ME_IN); - }); - - it("should use chain() ... .value() to use multiple higher order functions", function() { - var result = _([ [0, 1], 2 ]).chain() - .flatten() - .map(function(x) { return x+1 } ) - .reduce(function (sum, x) { return sum + x }) - .value(); - - expect(result).toEqual(FILL_ME_IN); - }); - -}); - +describe("About Higher Order Functions", function() { + + it("should use filter to return array items that meet a criteria", function() { + var numbers = [1, 2, 3]; + var odd = _(numbers).filter(function(x) { return x % 2 !== 0 }); + + expect(odd).toEqual([1, 3]); + expect(odd.length).toBe(2); + expect(numbers.length).toBe(3); + }); + + it("should use 'map' to transform each element", function() { + var numbers = [1, 2, 3]; + var numbersPlus1 = _(numbers).map(function(x) { return x + 1 }); + + expect(numbersPlus1).toEqual([2, 3, 4]); + expect(numbers).toEqual([1, 2, 3]); + }); + + it("should use 'reduce' to update the same result on each iteration", function() { + var numbers = [1, 2, 3]; + var reduction = _(numbers).reduce( + function( /* result from last call */ memo, /* current */ x) { return memo + x }, /* initial */ 0); + + expect(reduction).toBe(6); + expect(numbers).toEqual([1, 2, 3]); + }); + + it("should use 'forEach' for simple iteration", function() { + var numbers = [1, 2, 3]; + var msg = ""; + var isEven = function(item) { + msg += (item % 2) === 0; + }; + + _(numbers).forEach(isEven); + + expect(msg).toEqual("falsetruefalse"); + expect(numbers).toEqual([1, 2, 3]); + }); + + it("should use 'all' to test whether all items pass condition", function() { + var onlyEven = [2, 4, 6]; + var mixedBag = [2, 4, 5, 6]; + + var isEven = function(x) { return x % 2 === 0 }; + + expect(_(onlyEven).all(isEven)).toBe(true); + expect(_(mixedBag).all(isEven)).toBe(false); + }); + + it("should use 'any' to test if any items passes condition", function() { + var onlyEven = [2, 4, 6]; + var mixedBag = [2, 4, 5, 6]; + + var isEven = function(x) { return x % 2 === 0 }; + + expect(_(onlyEven).any(isEven)).toBe(true); + expect(_(mixedBag).any(isEven)).toBe(true); + }); + + it("should use range to generate an array", function() { + expect(_.range(3)).toEqual([0, 1, 2]); + expect(_.range(1, 4)).toEqual([1, 2, 3]); + expect(_.range(0, -4, -1)).toEqual([0, -1, -2, -3]); + }); + + it("should use flatten to make nested arrays easy to work with", function() { + expect(_([ + [1, 2], + [3, 4] + ]).flatten()).toEqual([1, 2, 3, 4]); + }); + + it("should use chain() ... .value() to use multiple higher order functions", function() { + var result = _([ + [0, 1], 2 + ]).chain() + .flatten() + .map(function(x) { return x + 1 }) + .reduce(function(sum, x) { return sum + x }) + .value(); + + expect(result).toEqual(6); + }); + +}); \ No newline at end of file diff --git a/koans/AboutInheritance.js b/koans/AboutInheritance.js index 5dba545b0..9e3bf6010 100644 --- a/koans/AboutInheritance.js +++ b/koans/AboutInheritance.js @@ -1,85 +1,85 @@ function Muppet(age, hobby) { - this.age = age; - this.hobby = hobby; + this.age = age; + this.hobby = hobby; - this.answerNanny = function(){ - return "Everything's cool!"; - } + this.answerNanny = function() { + return "Everything's cool!"; + } } function SwedishChef(age, hobby, mood) { - Muppet.call(this, age, hobby); - this.mood = mood; + Muppet.call(this, age, hobby); + this.mood = mood; - this.cook = function() { - return "Mmmm soup!"; - } + this.cook = function() { + return "Mmmm soup!"; + } } SwedishChef.prototype = new Muppet(); describe("About inheritance", function() { - beforeEach(function(){ - this.muppet = new Muppet(2, "coding"); - this.swedishChef = new SwedishChef(2, "cooking", "chillin"); - }); - - it("should be able to call a method on the derived object", function() { - expect(this.swedishChef.cook()).toEqual(FILL_ME_IN); - }); - - it("should be able to call a method on the base object", function() { - expect(this.swedishChef.answerNanny()).toEqual(FILL_ME_IN); - }); - - it("should set constructor parameters on the base object", function() { - expect(this.swedishChef.age).toEqual(FILL_ME_IN); - expect(this.swedishChef.hobby).toEqual(FILL_ME_IN); - }); - - it("should set constructor parameters on the derived object", function() { - expect(this.swedishChef.mood).toEqual(FILL_ME_IN); - }); + beforeEach(function() { + this.muppet = new Muppet(2, "coding"); + this.swedishChef = new SwedishChef(2, "cooking", "chillin"); + }); + + it("should be able to call a method on the derived object", function() { + expect(this.swedishChef.cook()).toEqual("Mmmm soup!"); + }); + + it("should be able to call a method on the base object", function() { + expect(this.swedishChef.answerNanny()).toEqual("Everything's cool!"); + }); + + it("should set constructor parameters on the base object", function() { + expect(this.swedishChef.age).toEqual(2); + expect(this.swedishChef.hobby).toEqual("cooking"); + }); + + it("should set constructor parameters on the derived object", function() { + expect(this.swedishChef.mood).toEqual("chillin"); + }); }); // http://javascript.crockford.com/prototypal.html -Object.prototype.beget = function () { - function F() {} - F.prototype = this; - return new F(); +Object.prototype.beget = function() { + function F() {} + F.prototype = this; + return new F(); } function Gonzo(age, hobby, trick) { - Muppet.call(this, age, hobby); - this.trick = trick; + Muppet.call(this, age, hobby); + this.trick = trick; - this.doTrick = function() { - return this.trick; - } + this.doTrick = function() { + return this.trick; + } } //no longer need to call the Muppet (base type) constructor Gonzo.prototype = Muppet.prototype.beget(); describe("About Crockford's inheritance improvement", function() { - beforeEach(function(){ - this.gonzo = new Gonzo(3, "daredevil performer", "eat a tire"); - }); - - it("should be able to call a method on the derived object", function() { - expect(this.gonzo.doTrick()).toEqual(FILL_ME_IN); - }); - - it("should be able to call a method on the base object", function() { - expect(this.gonzo.answerNanny()).toEqual(FILL_ME_IN); - }); - - it("should set constructor parameters on the base object", function() { - expect(this.gonzo.age).toEqual(FILL_ME_IN); - expect(this.gonzo.hobby).toEqual(FILL_ME_IN); - }); - - it("should set constructor parameters on the derived object", function() { - expect(this.gonzo.trick).toEqual(FILL_ME_IN); - }); -}); + beforeEach(function() { + this.gonzo = new Gonzo(3, "daredevil performer", "eat a tire"); + }); + + it("should be able to call a method on the derived object", function() { + expect(this.gonzo.doTrick()).toEqual("eat a tire"); + }); + + it("should be able to call a method on the base object", function() { + expect(this.gonzo.answerNanny()).toEqual("Everything's cool!"); + }); + + it("should set constructor parameters on the base object", function() { + expect(this.gonzo.age).toEqual(3); + expect(this.gonzo.hobby).toEqual("daredevil performer"); + }); + + it("should set constructor parameters on the derived object", function() { + expect(this.gonzo.trick).toEqual("eat a tire"); + }); +}); \ No newline at end of file diff --git a/koans/AboutMutability.js b/koans/AboutMutability.js index fd9b69af2..4323f0dd6 100644 --- a/koans/AboutMutability.js +++ b/koans/AboutMutability.js @@ -1,68 +1,65 @@ describe("About Mutability", function() { - it("should expect object properties to be public and mutable", function () { - var aPerson = {firstname: "John", lastname: "Smith" }; - aPerson.firstname = "Alan"; + it("should expect object properties to be public and mutable", function() { + var aPerson = { firstname: "John", lastname: "Smith" }; + aPerson.firstname = "Alan"; - expect(aPerson.firstname).toBe(FILL_ME_IN); - }); + expect(aPerson.firstname).toBe("Alan"); + }); - it("should understand that constructed properties are public and mutable", function () { - function Person(firstname, lastname) - { - this.firstname = firstname; - this.lastname = lastname; - } - var aPerson = new Person ("John", "Smith"); - aPerson.firstname = "Alan"; + it("should understand that constructed properties are public and mutable", function() { + function Person(firstname, lastname) { + this.firstname = firstname; + this.lastname = lastname; + } + var aPerson = new Person("John", "Smith"); + aPerson.firstname = "Alan"; - expect(aPerson.firstname).toBe(FILL_ME_IN); - }); + expect(aPerson.firstname).toBe("Alan"); + }); - it("should expect prototype properties to be public and mutable", function () { - function Person(firstname, lastname) - { - this.firstname = firstname; - this.lastname = lastname; - } - Person.prototype.getFullName = function () { - return this.firstname + " " + this.lastname; - }; + it("should expect prototype properties to be public and mutable", function() { + function Person(firstname, lastname) { + this.firstname = firstname; + this.lastname = lastname; + } + Person.prototype.getFullName = function() { + return this.firstname + " " + this.lastname; + }; - var aPerson = new Person ("John", "Smith"); - expect(aPerson.getFullName()).toBe(FILL_ME_IN); + var aPerson = new Person("John", "Smith"); + expect(aPerson.getFullName()).toBe("John Smith"); - aPerson.getFullName = function () { - return this.lastname + ", " + this.firstname; - }; + aPerson.getFullName = function() { + return this.lastname + ", " + this.firstname; + }; - expect(aPerson.getFullName()).toBe(FILL_ME_IN); - }); + expect(aPerson.getFullName()).toBe("Smith, John"); + }); - it("should know that variables inside a constructor and constructor args are private", function () { - function Person(firstname, lastname) - { - var fullName = firstname + " " + lastname; + it("should know that variables inside a constructor and constructor args are private", function() { + function Person(firstname, lastname) { + var fullName = firstname + " " + lastname; - this.getFirstName = function () { return firstname; }; - this.getLastName = function () { return lastname; }; - this.getFullName = function () { return fullName; }; - } - var aPerson = new Person ("John", "Smith"); + this.getFirstName = function() { return firstname; }; + this.getLastName = function() { return lastname; }; + this.getFullName = function() { return fullName; }; + } + var aPerson = new Person("John", "Smith"); - aPerson.firstname = "Penny"; - aPerson.lastname = "Andrews"; - aPerson.fullName = "Penny Andrews"; + aPerson.firstname = "Penny"; + aPerson.lastname = "Andrews"; + aPerson.fullName = "Penny Andrews"; - expect(aPerson.getFirstName()).toBe(FILL_ME_IN); - expect(aPerson.getLastName()).toBe(FILL_ME_IN); - expect(aPerson.getFullName()).toBe(FILL_ME_IN); + expect(aPerson.getFirstName()).toBe("John"); + expect(aPerson.getLastName()).toBe("Smith"); + expect(aPerson.getFullName()).toBe("John Smith"); - aPerson.getFullName = function () { - return aPerson.lastname + ", " + aPerson.firstname; - }; + aPerson.getFullName = function() { + return aPerson.lastname + ", " + aPerson.firstname; + }; - expect(aPerson.getFullName()).toBe(FILL_ME_IN); - }); + expect(aPerson.getFullName()).toBe("Andrews, Penny"); + }); -}); +}); \ No newline at end of file diff --git a/koans/AboutObjects.js b/koans/AboutObjects.js index 9f9ed93cc..57839704a 100644 --- a/koans/AboutObjects.js +++ b/koans/AboutObjects.js @@ -1,109 +1,108 @@ -describe("About Objects", function () { +describe("About Objects", function() { - describe("Properties", function () { - var megalomaniac; + describe("Properties", function() { + var megalomaniac; - beforeEach(function () { - megalomaniac = { mastermind: "Joker", henchwoman: "Harley" }; - }); + beforeEach(function() { + megalomaniac = { mastermind: "Joker", henchwoman: "Harley" }; + }); + + it("should confirm objects are collections of properties", function() { + expect(megalomaniac.mastermind).toBe("Joker"); + }); - it("should confirm objects are collections of properties", function () { - expect(megalomaniac.mastermind).toBe(FILL_ME_IN); + it("should confirm that properties are case sensitive", function() { + expect(megalomaniac.henchwoman).toBe("Harley"); + expect(megalomaniac.henchWoman).toBe(undefined); + }); }); - it("should confirm that properties are case sensitive", function () { - expect(megalomaniac.henchwoman).toBe(FILL_ME_IN); - expect(megalomaniac.henchWoman).toBe(FILL_ME_IN); + + it("should know properties that are functions act like methods", function() { + var megalomaniac = { + mastermind: "Brain", + henchman: "Pinky", + battleCry: function(noOfBrains) { + return "They are " + this.henchman + " and the" + + Array(noOfBrains + 1).join(" " + this.mastermind); + } + }; + + var battleCry = megalomaniac.battleCry(4); + expect("They are Pinky and the Brain Brain Brain Brain").toMatch(battleCry); }); - }); - - - it("should know properties that are functions act like methods", function () { - var megalomaniac = { - mastermind : "Brain", - henchman: "Pinky", - battleCry: function (noOfBrains) { - return "They are " + this.henchman + " and the" + - Array(noOfBrains + 1).join(" " + this.mastermind); - } - }; - - var battleCry = megalomaniac.battleCry(4); - expect(FILL_ME_IN).toMatch(battleCry); - }); - - it("should confirm that when a function is attached to an object, 'this' refers to the object", function () { - var currentDate = new Date(); - var currentYear = (currentDate.getFullYear()); - var megalomaniac = { - mastermind: "James Wood", - henchman: "Adam West", - birthYear: 1970, - calculateAge: function () { - return currentYear - this.birthYear; - } - }; - - expect(currentYear).toBe(FILL_ME_IN); - expect(megalomaniac.calculateAge()).toBe(FILL_ME_IN); - }); - - describe("'in' keyword", function () { - var megalomaniac; - beforeEach(function () { - megalomaniac = { - mastermind: "The Monarch", - henchwoman: "Dr Girlfriend", - theBomb: true - }; + + it("should confirm that when a function is attached to an object, 'this' refers to the object", function() { + var currentDate = new Date(); + var currentYear = (currentDate.getFullYear()); + var megalomaniac = { + mastermind: "James Wood", + henchman: "Adam West", + birthYear: 1970, + calculateAge: function() { + return currentYear - this.birthYear; + } + }; + + expect(currentYear).toBe(2022); + expect(megalomaniac.calculateAge()).toBe(52); }); - it("should have the bomb", function () { + describe("'in' keyword", function() { + var megalomaniac; + beforeEach(function() { + megalomaniac = { + mastermind: "The Monarch", + henchwoman: "Dr Girlfriend", + theBomb: true + }; + }); - var hasBomb = "theBomb" in megalomaniac; + it("should have the bomb", function() { - expect(hasBomb).toBe(FILL_ME_IN); - }); + var hasBomb = "theBomb" in megalomaniac; + + expect(hasBomb).toBe(true); + }); - it("should not have the detonator however", function () { + it("should not have the detonator however", function() { - var hasDetonator = "theDetonator" in megalomaniac; + var hasDetonator = "theDetonator" in megalomaniac; - expect(hasDetonator).toBe(FILL_ME_IN); + expect(hasDetonator).toBe(false); + }); }); - }); - it("should know that properties can be added and deleted", function () { - var megalomaniac = { mastermind : "Agent Smith", henchman: "Agent Smith" }; + it("should know that properties can be added and deleted", function() { + var megalomaniac = { mastermind: "Agent Smith", henchman: "Agent Smith" }; - expect("secretary" in megalomaniac).toBe(FILL_ME_IN); + expect("secretary" in megalomaniac).toBe(false); - megalomaniac.secretary = "Agent Smith"; - expect("secretary" in megalomaniac).toBe(FILL_ME_IN); + megalomaniac.secretary = "Agent Smith"; + expect("secretary" in megalomaniac).toBe(true); - delete megalomaniac.henchman; - expect("henchman" in megalomaniac).toBe(FILL_ME_IN); - }); + delete megalomaniac.henchman; + expect("henchman" in megalomaniac).toBe(false); + }); - it("should use prototype to add to all objects", function () { - function Circle(radius) - { - this.radius = radius; - } + it("should use prototype to add to all objects", function() { + function Circle(radius) { + this.radius = radius; + } - var simpleCircle = new Circle(10); - var colouredCircle = new Circle(5); - colouredCircle.colour = "red"; + var simpleCircle = new Circle(10); + var colouredCircle = new Circle(5); + colouredCircle.colour = "red"; - expect(simpleCircle.colour).toBe(FILL_ME_IN); - expect(colouredCircle.colour).toBe(FILL_ME_IN); + expect(simpleCircle.colour).toBe(undefined); + expect(colouredCircle.colour).toBe("red"); - Circle.prototype.describe = function () { - return "This circle has a radius of: " + this.radius; - }; + Circle.prototype.describe = function() { + return "This circle has a radius of: " + this.radius; + }; - expect(simpleCircle.describe()).toBe(FILL_ME_IN); - expect(colouredCircle.describe()).toBe(FILL_ME_IN); - }); -}); + expect(simpleCircle.describe()).toBe("This circle has a radius of: 10"); + expect(colouredCircle.describe()).toBe("This circle has a radius of: 5"); + }); +}); \ No newline at end of file