diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..7b1c78f8 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,35 @@ +# unifying the coding style for different editors and IDEs => editorconfig.org + +; indicate this is the root of the project +root = true + +########################################################### +; common +########################################################### + +[*] +charset = utf-8 + +end_of_line = LF +insert_final_newline = true +trim_trailing_whitespace = true + +indent_style = space +indent_size = 2 + +########################################################### +; make +########################################################### + +[Makefile] +indent_style = tab + +[makefile] +indent_style = tab + +########################################################### +; markdown +########################################################### + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore index cfba75e0..61d374b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ -*.beam *.swp .DS_Store node_modules +npm-debug.log tmp diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..514f547a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: node_js + +node_js: + - 0.10 + +script: + - "make test" + - ./bin/configlet-linux-amd64 . + diff --git a/EXERCISES.txt b/EXERCISES.txt deleted file mode 100644 index 94d9a5d8..00000000 --- a/EXERCISES.txt +++ /dev/null @@ -1,54 +0,0 @@ -bob -word-count -anagram -beer-song -nucleotide-count -rna-transcription -point-mutations -phone-number -grade-school -robot-name -leap -etl -space-age -grains -gigasecond -triangle -scrabble-score -roman-numerals -binary -prime-factors -raindrops -allergies -strain -atbash-cipher -accumulate -crypto-square -trinary -sieve -simple-cipher -octal -luhn -pig-latin -pythagorean-triplet -series -difference-of-squares -secret-handshake -linked-list -wordy -hexadecimal -largest-series-product -kindergarten-garden -binary-search-tree -matrix -robot-simulator -nth-prime -palindrome-products -pascals-triangle -say -custom-set -sum-of-multiples -queen-attack -saddle-points -ocr-numbers -meetup diff --git a/Makefile b/Makefile index b7d79c04..fc190c23 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # assignments ASSIGNMENT ?= "" -IGNOREDIRS := "node_modules" -ASSIGNMENTS = $(shell find . -maxdepth 1 -mindepth 1 -type d | tr -d './' | sort | grep -Ev $(IGNOREDIRS)) +IGNOREDIRS := "^(\.git|bin|node_modules)$$" +ASSIGNMENTS = $(shell find . -maxdepth 1 -mindepth 1 -type d -exec basename -a {} + | sort | grep -Ev $(IGNOREDIRS)) # output directories TMPDIR ?= "/tmp" diff --git a/README.md b/README.md index de27183e..c4901da3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,24 @@ -# xJavaScript +# xJavaScript [![Build Status](https://travis-ci.org/exercism/xjavascript.png?branch=master)](https://travis-ci.org/exercism/xjavascript) Exercism exercises in JavaScript + +## Running Unit Test Suite + +### All Assignments + + % make test + +### Single Assignment + + % make test-assignment ASSIGNMENT=wordy + +## Contributing Guide + +Please see the [contributing guide](https://github.com/exercism/x-api/blob/master/CONTRIBUTING.md#the-exercise-data) + ## License + The MIT License (MIT) Copyright (c) 2014 Katrina Owen, _@kytrinyx.com + diff --git a/SETUP.md b/SETUP.md new file mode 100644 index 00000000..ce40ecd9 --- /dev/null +++ b/SETUP.md @@ -0,0 +1,13 @@ +## Making the Test Suite Pass + +Execute the tests with: + +```bash +$ jasmine-node bob_test.spec.js +``` + +All but the first test have been skipped. + +Once you get a test passing, you can unskip the next one by +changing `xit` to `it`. + diff --git a/anagram/anagram_test.spec.js b/anagram/anagram_test.spec.js index 96925811..5c8aa84a 100644 --- a/anagram/anagram_test.spec.js +++ b/anagram/anagram_test.spec.js @@ -1,58 +1,75 @@ -var Anagram = require('./anagram'); +var anagram = require('./anagram'); describe('Anagram', function() { it("no matches",function() { - var detector = new Anagram("diaper"); - var matches = detector.match([ "hello", "world", "zombies", "pants"]); + var subject = anagram("diaper"); + var matches = subject.matches([ "hello", "world", "zombies", "pants"]); + expect(matches).toEqual([]); }); xit("detects simple anagram",function() { - var detector = new Anagram("ant"); - var matches = detector.match(['tan', 'stand', 'at']); + var subject = anagram("ant"); + var matches = subject.matches(['tan', 'stand', 'at']); + expect(matches).toEqual(['tan']); }); xit("does not detect false positives",function() { - var detector = new Anagram("galea"); - var matches = detector.match(["eagle"]); + var subject = anagram("galea"); + var matches = subject.matches(["eagle"]); + expect(matches).toEqual([]); }); xit("detects multiple anagrams",function() { - var detector = new Anagram("master"); - var matches = detector.match(['stream', 'pigeon', 'maters']); + var subject = anagram("master"); + var matches = subject.matches(['stream', 'pigeon', 'maters']); + expect(matches).toEqual(['stream', 'maters']); }); xit("does not detect anagram subsets",function() { - var detector = new Anagram("good"); - var matches = detector.match(['dog', 'goody']); + var subject = anagram("good"); + var matches = subject.matches(['dog', 'goody']); + expect(matches).toEqual([]); }); xit("detects anagram",function() { - var detector = new Anagram("listen"); - var matches = detector.match(['enlists', 'google', 'inlets', 'banana']); + var subject = anagram("listen"); + var matches = subject.matches(['enlists', 'google', 'inlets', 'banana']); + expect(matches).toEqual(['inlets']); }); xit("detects multiple anagrams",function() { - var detector = new Anagram("allergy"); - var matches = detector.match(['gallery', 'ballerina', 'regally', 'clergy', 'largely', 'leading']); + var subject = anagram("allergy"); + var matches = subject.matches(['gallery', 'ballerina', 'regally', 'clergy', 'largely', 'leading']); + expect(matches).toEqual(['gallery', 'regally', 'largely']); }); xit("detects anagrams case-insensitively",function() { - var detector = new Anagram("Orchestra"); - var matches = detector.match(['cashregister', 'Carthorse', 'radishes']); + var subject = anagram("Orchestra"); + var matches = subject.matches(['cashregister', 'Carthorse', 'radishes']); + expect(matches).toEqual(['Carthorse']); }); xit("does not detect a word as its own anagram",function() { - var detector = new Anagram("banana"); - var matches = detector.match(['Banana']); + var subject = anagram("banana"); + var matches = subject.matches(['Banana']); + expect(matches).toEqual([]); }); + + xit("matches() accepts string arguments",function() { + var subject = anagram("ant"); + var matches = subject.matches("stand", "tan", "at"); + + expect(matches).toEqual(["tan"]); + }); + }); diff --git a/anagram/example.js b/anagram/example.js index 0e0b6b34..5e582ffe 100644 --- a/anagram/example.js +++ b/anagram/example.js @@ -1,34 +1,30 @@ -(function() { - 'use strict'; +"use strict"; +module.exports = anagram; - function Anagram(word) { - this.word = word.toLowerCase(); - } - - Anagram.prototype.match = function(words) { - var matches = []; - - for(var i = 0; i < words.length; i++) { - var currentWord = words[i]; +function anagram(word) { + return { + // public API + matches: matches.bind(this, word) + }; +} - if (currentWord.length == this.word.length && currentWord.toLowerCase() != this.word) { - var currentWordLetters = currentWord.toLowerCase().split('').sort(); - var matchingWordLetters = this.word.split('').sort(); +function matches(word, words) { + words = Array.isArray(words) ? words : [].slice.call(arguments, 1); - var isMatch = true; + return words.filter(function (candidate) { + return !sameWord(word, candidate) && isAnagram(word, candidate); + }); +} - for (var j = 0; j < currentWordLetters.length; j++) { - if (currentWordLetters[j] != matchingWordLetters[j]) { - isMatch = false; - } - } +function sameWord(word, candidate) { + return word.toLowerCase() === candidate.toLowerCase(); +} - if (isMatch) { matches.push(currentWord); } - } +function isAnagram(word, candiate) { + return normalize(word) === normalize(candiate); +} - } - return matches; - }; +function normalize(string) { + return string.toLowerCase().split("").sort().toString(); +} - module.exports = Anagram; -})(); diff --git a/assignments/javascript/.gitignore b/assignments/javascript/.gitignore deleted file mode 100644 index 93f13619..00000000 --- a/assignments/javascript/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules -npm-debug.log diff --git a/beer-song/example.js b/beer-song/example.js index f246188f..2a224e17 100644 --- a/beer-song/example.js +++ b/beer-song/example.js @@ -5,7 +5,7 @@ var str = ""; if (number === 0) { - str = "no more bottles"; + str = "No more bottles"; } else if (number === 1) { str = "1 bottle"; } else { @@ -29,7 +29,7 @@ } function next_bottle(current_verse) { - return bottles(next_verse(current_verse)) + " of beer on the wall.\n"; + return bottles(next_verse(current_verse)).toLowerCase() + " of beer on the wall.\n"; } function next_verse(current_verse) { @@ -53,15 +53,11 @@ }; exports.verse = function(number) { - var line1 = bottles(number).capitalize() + " of beer on the wall, "; - var line2 = bottles(number) + " of beer.\n"; + var line1 = bottles(number) + " of beer on the wall, "; + var line2 = bottles(number).toLowerCase() + " of beer.\n"; var line3 = action(number); var line4 = next_bottle(number); return [line1, line2, line3, line4].join(""); }; - - String.prototype.capitalize = function() { - return this.charAt(0).toUpperCase() + this.slice(1); - }; })(); \ No newline at end of file diff --git a/bin/configlet-darwin-386 b/bin/configlet-darwin-386 new file mode 100755 index 00000000..d552a15e Binary files /dev/null and b/bin/configlet-darwin-386 differ diff --git a/bin/configlet-darwin-amd64 b/bin/configlet-darwin-amd64 new file mode 100755 index 00000000..abde89f2 Binary files /dev/null and b/bin/configlet-darwin-amd64 differ diff --git a/bin/configlet-linux-386 b/bin/configlet-linux-386 new file mode 100755 index 00000000..ebc005e7 Binary files /dev/null and b/bin/configlet-linux-386 differ diff --git a/bin/configlet-linux-amd64 b/bin/configlet-linux-amd64 new file mode 100755 index 00000000..4f48e868 Binary files /dev/null and b/bin/configlet-linux-amd64 differ diff --git a/bin/configlet-windows-386.exe b/bin/configlet-windows-386.exe new file mode 100755 index 00000000..79ab39e0 Binary files /dev/null and b/bin/configlet-windows-386.exe differ diff --git a/bin/configlet-windows-amd64.exe b/bin/configlet-windows-amd64.exe new file mode 100755 index 00000000..46fb7a13 Binary files /dev/null and b/bin/configlet-windows-amd64.exe differ diff --git a/bob/bob_test.spec.js b/bob/bob_test.spec.js index e419fd3b..123bd647 100644 --- a/bob/bob_test.spec.js +++ b/bob/bob_test.spec.js @@ -59,7 +59,7 @@ describe("Bob", function() { }); xit("calmly speaking about umlauts", function() { - var result = bob.hey("\xdcML\xe4\xdcTS!"); + var result = bob.hey("\xdcML\xe4\xdcTS"); expect(result).toEqual('Whatever.'); }); diff --git a/bracket-push/bracket-push_test.spec.js b/bracket-push/bracket-push_test.spec.js new file mode 100644 index 00000000..484e7385 --- /dev/null +++ b/bracket-push/bracket-push_test.spec.js @@ -0,0 +1,28 @@ +var bracket = require('./bracket-push'); + +describe("bracketPush()", function() { + it("checks for appropriate bracketing in a set of brackets", function() { + expect(bracketPush("{}")).toEqual(true); + }); + + xit("returns false for unclosed brackets", function() { + expect(bracketPush("{{")).toEqual(false); + }); + + xit("checks bracketing in more than one pair of brackets", function() { + expect(bracketPush("{}[]")).toEqual(true); + }); + + xit("checks bracketing in nested brackets", function() { + expect(bracketPush("{[]}")).toEqual(true); + }); + + xit("checks bracket closure with deeper nesting", function() { + expect(bracketPush("{[)][]}")).toEqual(false); + }); + + xit("checks bracket closure in a long string of brackets", function() { + expect(bracketPush("{[]([()])}")).toEqual(true); + }); + +}); \ No newline at end of file diff --git a/bracket-push/example.js b/bracket-push/example.js new file mode 100644 index 00000000..445bf8ee --- /dev/null +++ b/bracket-push/example.js @@ -0,0 +1,40 @@ +'use strict'; + +var bracketPush = function(input) { + if (input.length === 0) { + return true; + } + + var bracketArray; + bracketArray = input; + var iArr = []; + + if (typeof input === "string") { + bracketArray = input.split(""); + } + + var openArray = ["{", "[", "("]; + var closeArray = ["}", "]", ")"]; + + for (var i = 0; i < bracketArray.length; i++) { + for (var j = 0; j < openArray.length; j++) { + if (bracketArray[i] === openArray[j]) { + iArr.push(i); + } + } + } + + var topNumber = Math.max.apply(Math, iArr); + + for (var k = 0; k < 3; k++) { + if (bracketArray[topNumber] === openArray[k]) { + if (typeof bracketArray[(topNumber + 1)] !== undefined) { + if (bracketArray[(topNumber + 1)] === closeArray[k]) { + bracketArray.splice(topNumber, 2); + return bracketPush(bracketArray); + } + } + } + } + return false; +}; \ No newline at end of file diff --git a/circular-buffer/circular-buffer_test.spec.js b/circular-buffer/circular-buffer_test.spec.js new file mode 100644 index 00000000..cf27f17d --- /dev/null +++ b/circular-buffer/circular-buffer_test.spec.js @@ -0,0 +1,103 @@ +var circularBuffer = require('./circular-buffer').circularBuffer; +var bufferEmptyException = require('./circular-buffer').bufferEmptyException; +var bufferFullException = require('./circular-buffer').bufferFullException; + +describe("CircularBuffer", function() { + + it("reading an empty buffer throws a BufferEmptyException", function() { + var buffer = circularBuffer(1); + expect(buffer.read).toThrow(bufferEmptyException()); + }); + + xit("write and read back one item", function() { + var buffer = circularBuffer(1); + buffer.write('1'); + expect(buffer.read()).toBe('1'); + expect(buffer.read).toThrow(bufferEmptyException()); + }); + + xit("write and read back multiple items", function() { + var buffer = circularBuffer(2); + buffer.write('1'); + buffer.write('2'); + expect(buffer.read()).toBe('1'); + expect(buffer.read()).toBe('2'); + expect(buffer.read).toThrow(bufferEmptyException()); + }); + + xit("clearing a buffer", function() { + var buffer = circularBuffer(2); + buffer.write('1'); + buffer.write('2'); + buffer.clear(); + expect(buffer.read).toThrowError + buffer.write('3'); + buffer.write('4'); + expect(buffer.read()).toBe('3'); + expect(buffer.read()).toBe('4'); + }); + + xit("alternate write and read", function() { + var buffer = circularBuffer(2); + buffer.write('1'); + expect(buffer.read()).toBe('1'); + buffer.write('2'); + expect(buffer.read()).toBe('2'); + }); + + xit("reads back oldest item", function() { + var buffer = circularBuffer(3); + buffer.write('1'); + buffer.write('2'); + buffer.read(); + buffer.write('3'); + expect(buffer.read()).toBe('2'); + expect(buffer.read()).toBe('3'); + }); + + xit("writes of undefined or null don't occupy buffer", function() { + var buffer = circularBuffer(3); + buffer.write(null); + buffer.write(undefined); + [1,2,3].map(function(i) { buffer.write(i.toString()) }) + expect(buffer.read()).toBe('1'); + }); + + xit("writing to a full buffer throws a BufferFullException", function() { + var buffer = circularBuffer(2); + buffer.write('1'); + buffer.write('2'); + expect(function() { + buffer.write('A'); + }).toThrow(bufferFullException()); + }); + + xit("forced writes over write oldest item in a full buffer", function() { + var buffer = circularBuffer(2); + buffer.write('1'); + buffer.write('2'); + buffer.forceWrite('A'); + expect(buffer.read()).toBe('2'); + expect(buffer.read()).toBe('A'); + expect(buffer.read).toThrow(bufferEmptyException()); + }); + + xit("alternate force write and read into full buffer", function() { + var buffer = circularBuffer(5); + [1,2,3].map(function(i) { buffer.write(i.toString()) }) + buffer.read(); + buffer.read(); + buffer.write('4'); + buffer.read(); + [5,6,7,8].map(function(i) { buffer.write(i.toString()) }) + buffer.forceWrite('A'); + buffer.forceWrite('B'); + expect(buffer.read()).toBe('6'); + expect(buffer.read()).toBe('7'); + expect(buffer.read()).toBe('8'); + expect(buffer.read()).toBe('A'); + expect(buffer.read()).toBe('B'); + expect(buffer.read).toThrow(bufferEmptyException()); + }); + +}); \ No newline at end of file diff --git a/circular-buffer/example.js b/circular-buffer/example.js new file mode 100644 index 00000000..909532fc --- /dev/null +++ b/circular-buffer/example.js @@ -0,0 +1,99 @@ +function CircularBuffer(capacity) { + + var readPoint = 0; + var writePoint = 0; + var buffer = new Array(capacity); + + return { + read: function() { + if (isBufferEmpty()) { throw new BufferEmptyException(); } + var data = buffer[readPoint]; + buffer[readPoint] = null; + updateReadPoint(); + return data; + }, + + write: function(data) { + updateBuffer(data, function() { + if (isBufferFull()) { throw new BufferFullException(); } + buffer[writePoint] = data; + }) + }, + + forceWrite: function(data) { + updateBuffer(data, function(){ + buffer[writePoint] = data; + if (isBufferFull()) { updateReadPoint() } + }) + }, + + clear: function() { + readPoint = 0; + writePoint = 0; + buffer = new Array(capacity); + }, + + isFull: function() { + return isBufferFull(); + }, + + isEmpty: function() { + return isBufferEmpty(); + } + }; + + function isBufferEmpty() { + return buffer.every(isEmpty); + }; + + function isBufferFull() { + return buffer.filter(isFull).length === capacity; + }; + + function updateBuffer(data, callback) { + if (isEmpty(data)) { return; } + callback(); + updateWritePoint(); + }; + + function updateWritePoint() { + writePoint = (writePoint + 1) % capacity; + }; + + function updateReadPoint() { + readPoint = (readPoint + 1) % capacity; + }; + + function isFull(data) { + return !isEmpty(data); + }; + + function isEmpty(data) { + return data === null || data === undefined; + }; + +}; + +function BufferEmptyException() { + this.name = "BufferEmptyException"; + this.message = "Buffer is empty."; +}; + +function BufferFullException() { + this.name = "BufferFullException"; + this.message = "Buffer is full."; +}; + +module.exports = { + circularBuffer: function(capacity) { + return new CircularBuffer(capacity); + }, + + bufferEmptyException: function() { + return new BufferEmptyException(); + }, + + bufferFullException: function() { + return new BufferFullException(); + } +}; \ No newline at end of file diff --git a/clock/clock_test.spec.js b/clock/clock_test.spec.js new file mode 100644 index 00000000..57e26d81 --- /dev/null +++ b/clock/clock_test.spec.js @@ -0,0 +1,61 @@ +var at = require('./clock').at; + +describe("Clock", function () { + + it("prints the hour", function () { + expect(at(8).toString()).toEqual("08:00"); + expect(at(9).toString()).toEqual("09:00"); + }); + + xit("prints past the hour", function () { + expect(at(11, 9).toString()).toEqual("11:09"); + expect(at(11, 19).toString()).toEqual("11:19"); + }); + + xit("can add minutes", function () { + var clock = at(10).plus(3); + expect(clock.toString()).toEqual("10:03"); + }); + + xit("can add over an hour", function () { + var clock = at(10).plus(61); + expect(clock.toString()).toEqual("11:01"); + }); + + xit("wraps around midnight", function () { + var clock = at(23, 59).plus(2); + expect(clock.toString()).toEqual("00:01"); + }); + + xit("can subtract minutes", function () { + var clock = at(10, 3).minus(3); + expect(clock.toString()).toEqual("10:00"); + }); + + xit("can subtract over an hour", function () { + var clock = at(10, 3).minus(30); + expect(clock.toString()).toEqual("09:33"); + + var clock = at(10, 3).minus(70); + expect(clock.toString()).toEqual("08:53"); + }); + + xit("can know if it's equal to another clock", function () { + var clock1 = at(10, 3); + var clock2 = at(10, 3); + expect(clock1.equals(clock2)).toBe(true); + }); + + xit("can know if it's not equal to another clock", function () { + var clock1 = at(10, 3); + var clock2 = at(10, 4); + expect(clock1.equals(clock2)).toBe(false); + }); + + xit("wraps around midnight backwards", function () { + var clock = at(0, 3).minus(4); + expect(clock.toString()).toEqual("23:59"); + }); + +}); + diff --git a/clock/example.js b/clock/example.js new file mode 100644 index 00000000..04c3d67d --- /dev/null +++ b/clock/example.js @@ -0,0 +1,34 @@ +exports.at = at; + +function at(hours, minutes) { + var min = 1000 * 60; + var hr = min * 60; + + var clock = {}; + var value = (~~hours * hr) + (~~minutes * min); + + clock.valueOf = function () { + return value; + }; + + clock.toString = function () { + var time = new Date(value).toISOString().split('T')[1].split(':'); + return time[0] + ":" + time[1]; + }; + + clock.plus = function (minutes) { + value += ~~minutes * min; + return clock; + }; + + clock.minus = function (minutes) { + value -= ~~minutes * min; + return clock; + }; + + clock.equals = function (other) { + return +clock === +other; + }; + + return Object.create(clock); +}; diff --git a/config.json b/config.json new file mode 100644 index 00000000..e73bf0a2 --- /dev/null +++ b/config.json @@ -0,0 +1,75 @@ +{ + "slug": "javascript", + "language": "JavaScript", + "repository": "https://github.com/exercism/xjavascript", + "active": true, + "problems": [ + "bob", + "word-count", + "hamming", + "anagram", + "food-chain", + "beer-song", + "nucleotide-count", + "rna-transcription", + "point-mutations", + "phone-number", + "grade-school", + "robot-name", + "leap", + "etl", + "space-age", + "grains", + "gigasecond", + "triangle", + "clock", + "scrabble-score", + "roman-numerals", + "circular-buffer", + "binary", + "prime-factors", + "raindrops", + "allergies", + "strain", + "atbash-cipher", + "accumulate", + "crypto-square", + "trinary", + "sieve", + "simple-cipher", + "octal", + "luhn", + "pig-latin", + "pythagorean-triplet", + "series", + "difference-of-squares", + "secret-handshake", + "linked-list", + "wordy", + "hexadecimal", + "largest-series-product", + "kindergarten-garden", + "binary-search-tree", + "matrix", + "robot-simulator", + "nth-prime", + "palindrome-products", + "pascals-triangle", + "say", + "custom-set", + "sum-of-multiples", + "queen-attack", + "saddle-points", + "ocr-numbers", + "meetup" + ], + "deprecated": [ + + ], + "ignored": [ + "node_modules" + ], + "foregone": [ + + ] +} diff --git a/nucleotide-count/example.js b/nucleotide-count/example.js index d2e6eb1a..301fe31d 100644 --- a/nucleotide-count/example.js +++ b/nucleotide-count/example.js @@ -1,31 +1,30 @@ -(function() { - 'use strict'; +'use strict'; - function DNA(dnaString){ - var splitDNA = dnaString.split(''); +module.exports = dna; - this.nucleotideCounts = { A : 0, T : 0, C : 0, G : 0 }; - this.validNucleotides = 'ATCGU'; +function dna(strand) { + var acids = (strand || ''); + var index = histogram(acids); - splitDNA.reduce(this.countAll, this.nucleotideCounts); + for (var acid in acids) { + if (!index.hasOwnProperty(acids[acid])) throw new RangeError("Invalid DNA " + strand); } - DNA.prototype.countAll = function countAll(nucleotideCounts, nucleotide) { - nucleotideCounts[nucleotide] = nucleotideCounts[nucleotide] + 1; - return nucleotideCounts; - }; + return Object.create({ + histogram: histogram.bind(null, acids), + count: count.bind(null, acids) + }); +} - DNA.prototype._isValidNucleotide = function _isValidNucleotide(nucleotide) { - return this.validNucleotides.indexOf(nucleotide) >= 0; - }; +function count(acids, acid) { + return acids.split(acid).length - 1; +} - DNA.prototype.count = function count(nucleotide) { - if(this._isValidNucleotide(nucleotide)) { - return this.nucleotideCounts[nucleotide] || 0; - } else { - throw new Error("Invalid Nucleotide"); - } +function histogram(acids) { + return { + A: count.call(acids, 'A'), + C: count.call(acids, 'C'), + G: count.call(acids, 'G'), + T: count.call(acids, 'T') }; - - module.exports = DNA; -})(); \ No newline at end of file +} diff --git a/nucleotide-count/nucleotide-count_test.spec.js b/nucleotide-count/nucleotide-count_test.spec.js index 4c56763b..e353ee40 100644 --- a/nucleotide-count/nucleotide-count_test.spec.js +++ b/nucleotide-count/nucleotide-count_test.spec.js @@ -1,56 +1,44 @@ -var DNA = require('./nucleotide-count'); +var dna = require('./nucleotide-count'); describe('DNA', function() { - it('has no nucleotides', function(){ - var expected = { A : 0, T : 0, C : 0, G : 0 }, - dna = new DNA(''); - expect(dna.nucleotideCounts).toEqual(expected); + it('Empty DNA strand has no adenosine', function() { + expect(0, dna().count('A')); }); - xit('has no adenosine', function(){ - var dna = new DNA(''); - expect(dna.count('A')).toEqual(0); + xit('Repetitive cytidine gets counted', function() { + expect(5, dna('CCCCC').count('C')); }); - xit('repetitive cytidine gets counts', function(){ - var dna = new DNA('CCCCC'); - expect(dna.count('C')).toEqual(5); + xit('Counts only thymidine', function() { + expect(1, dna('GGGGGTAACCCGG').count('T')); }); - xit('repetitive sequence has only guanosine', function(){ - var dna = new DNA('GGGGGGGG'), - expected = { A : 0, T : 0, C : 0, G : 8 }; - expect(dna.nucleotideCounts).toEqual(expected); + xit('Counts a nucleotide only once', function() { + var acid = dna('CGATTGGG'); + acid.count('T'); + acid.count('T'); + expect(2, acid.count('T')); }); - xit('counts only thymidine', function(){ - var dna = new DNA('GGGGTAACCCGG'); - expect(dna.count('T')).toEqual(1); + xit('Empty DNS strand has no nucleotides', function() { + var expected = {A: 0, T: 0, C: 0, G: 0}; + expect(expected, dna().histogram()); }); - xit('counts a nucleotide only once', function(){ - var dna = new DNA('GGTTGG'); - dna.count('T'); - expect(dna.count('T')).toEqual(2); + xit('Repetitive sequence has only guanosine', function() { + var expected = {A: 0, T: 0, C: 0, G: 8}; + expect(expected, dna('GGGGGGGG').histogram()); }); - xit('has no uracil', function(){ - var dna = new DNA('GGTTGG'); - expect(dna.count('U')).toEqual(0); + xit('Counts all nucleotides', function() { + var strand = 'AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC'; + var expected = {A: 20, T: 21, C: 17, G: 12}; + expect(expected, dna(strand).histogram()); }); - xit('validates nucleotides', function(){ - var dna = new DNA('GGTTGG'); - expect(function(){ - dna.count('X'); - }).toThrow(new Error("Invalid Nucleotide")); - }); - - xit('counts all nucleotides', function(){ - var dna = new DNA("AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC"), - expected = { A : 20, T : 21, G : 17, C : 12 }; - expect(dna.nucleotideCounts).toEqual(expected); + xit('Validates DNA', function() { + expect(dna.bind(null, 'JOHNNYAPPLESEED')).toThrow(); }); }); diff --git a/palindrome-products/example.js b/palindrome-products/example.js index c31c663c..14c7eebd 100644 --- a/palindrome-products/example.js +++ b/palindrome-products/example.js @@ -1,7 +1,6 @@ 'use strict'; module.exports = function Palindromes(options) { - this.maxFactor = options.maxFactor; this.minFactor = options.minFactor || 1; @@ -64,4 +63,4 @@ function arrayContainsArray(array,element) { } return containsArray; -} \ No newline at end of file +} diff --git a/palindrome-products/palindrome-products_test.spec.js b/palindrome-products/palindrome-products_test.spec.js index 5ad4a242..19445883 100644 --- a/palindrome-products/palindrome-products_test.spec.js +++ b/palindrome-products/palindrome-products_test.spec.js @@ -1,3 +1,4 @@ +'use strict'; var Palindromes = require('./palindrome-products'); describe("Palindrome", function() { @@ -5,14 +6,16 @@ describe("Palindrome", function() { it("largest palindrome from single digit factors", function() { var palindromes = new Palindromes({maxFactor: 9}); palindromes.generate(); - largest = palindromes.largest(); + + var largest = palindromes.largest(); expect(largest.value).toEqual(9); - expect([[[3, 3], [1, 9]], [[1, 9], [3, 3]]]).toContain(largest.factors) + expect([[[3, 3], [1, 9]], [[1, 9], [3, 3]]]).toContain(largest.factors); }); xit("largets palindrome from double digit factors", function() { var palindromes = new Palindromes({ maxFactor: 99, minFactor: 10 }); palindromes.generate(); + var largest = palindromes.largest(); expect(largest.value).toEqual(9009); expect(largest.factors).toEqual([[91, 99]]); @@ -21,6 +24,7 @@ describe("Palindrome", function() { xit("smallest palindrome from double digit factors", function() { var palindromes = new Palindromes({ maxFactor: 99, minFactor: 10 }); palindromes.generate(); + var smallest = palindromes.smallest(); expect(smallest.value).toEqual(121); expect(smallest.factors).toEqual([[11, 11]]); @@ -29,6 +33,7 @@ describe("Palindrome", function() { xit("largest palindrome from triple digit factors", function() { var palindromes = new Palindromes({ maxFactor: 999, minFactor: 100 }); palindromes.generate(); + var largest = palindromes.largest(); expect(largest.value).toEqual(906609); expect(largest.factors).toEqual([[913, 993]]); @@ -37,8 +42,10 @@ describe("Palindrome", function() { xit("smallest palindrome from triple digit factors", function() { var palindromes = new Palindromes({ maxFactor: 999, minFactor: 100 }); palindromes.generate(); + var smallest = palindromes.smallest(); expect(smallest.value).toEqual(10201); expect(smallest.factors).toEqual([[101, 101]]); }); + }); diff --git a/robot-simulator/robot-simulator_test.spec.js b/robot-simulator/robot-simulator_test.spec.js index 5266a140..06e2f744 100644 --- a/robot-simulator/robot-simulator_test.spec.js +++ b/robot-simulator/robot-simulator_test.spec.js @@ -8,16 +8,16 @@ describe("Robot", function() { for (var i = 0; i < directions.length; i++) { var currentDirection = directions[i]; - robot.orient(currentDirection) + robot.orient(currentDirection); expect(robot.bearing).toEqual(currentDirection); - }; + } }); xit("invalid robot bearing", function() { try { robot.orient("crood"); } catch(exception) { - expect(exception).toEqual("Invalid Robot Bearing") + expect(exception).toEqual("Invalid Robot Bearing"); } }); @@ -123,19 +123,19 @@ describe("Robot", function() { xit("series of instructions", function() { expect(robot.instructions("RAAL")) .toEqual(["turnRight", "advance", "advance", "turnLeft"]); - }) + }); xit("instruct robot", function() { robot.place({x: -2, y: 1, direction: "east"}); - robot.evaluate("RLAALAL") + robot.evaluate("RLAALAL"); expect(robot.coordinates).toEqual([0,2]); expect(robot.bearing).toEqual("west"); }); xit("instruct many robots", function() { - var robot1 = new Robot - var robot2 = new Robot - var robot3 = new Robot + var robot1 = new Robot(); + var robot2 = new Robot(); + var robot3 = new Robot(); robot1.place({x: 0, y: 0, direction: "north"}); robot2.place({x: 2, y: -7, direction: "east"}); robot3.place({x: 8, y: 4, direction: "south"}); diff --git a/word-count/word-count_test.spec.js b/word-count/word-count_test.spec.js index 26a7f6eb..e9e017f3 100644 --- a/word-count/word-count_test.spec.js +++ b/word-count/word-count_test.spec.js @@ -35,4 +35,14 @@ describe("words()", function() { var expectedCounts = { constructor: 2 }; expect(words("constructor Constructor")).toEqual(expectedCounts); }); + + xit("counts properly international characters", function() { + var expectedCounts = { hola: 1, "qué": 1, tal: 1, "привет": 1 }; + expect(words("¡Hola! ¿Qué tal? Привет!")).toEqual(expectedCounts); + }); + + xit("counts multiline", function() { + var expectedCounts = { hello: 1, world: 1 }; + expect(words("hello\nworld")).toEqual(expectedCounts); + }); });