-
-
Save dfkaye/d715d9e99d4ef9298cac4176038b1c49 to your computer and use it in GitHub Desktop.
refactoring challenge from @airporty => https://twitter.com/airportyh/status/931540087602581504
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 17 November 2017 | |
// original https://gist.github.com/airportyh/203f7c2d8a8b29af44218b79596af32f | |
// from @airporty https://twitter.com/airportyh/status/931540087602581504 | |
// The initial refactoring breaks `main()` steps to smaller functions, but adds | |
// whitespace. | |
// 21 November 2017 - added discrete unit tests for each function, vastly more | |
// robust, heavily renamed, heavier on comments. | |
// 4 Jan 2018 - more method renaming. | |
function getPluralFor(number) { | |
// simplified by unit test - accept only number or coercible param | |
return Number(number) === 1 ? '' : 's' | |
} | |
function getNameFor(author) { | |
// fixed by unit test with trim() | |
var name = (author.name || '').trim() | |
return name | |
|| [author.firstName, author.lastName] | |
.join(' ') | |
.replace(/'/g, '') | |
.trim() | |
|| '<Unknown author>' | |
} | |
function getArticlesBy(author) { | |
var articles = author.articles; | |
return Array.isArray(articles) ? articles : [] | |
} | |
function getTitleFor(article) { | |
// fixed by unit test with article and title.trim() | |
var title = article.title | |
return typeof title == 'string' && title.trim() || '<Untitled>' | |
} | |
function useLettersAndDigits(word) { | |
return word.replace(/[^\d^\w]/g, '') | |
} | |
function isNonEmpty(word) { | |
// filter added by unit test | |
var length = typeof word == 'string' ? word.trim().length : 0 | |
return !!length | |
} | |
function getWordcountFor(article) { | |
// type check added by unit tests | |
contents = article && typeof article.contents == 'string' ? article.contents.trim() : '' | |
// filter added by unit test | |
var words = contents | |
.split(/[\s]+/) | |
.map(useLettersAndDigits) | |
.filter(isNonEmpty); | |
var set = new Set(words) | |
// return check fixed by unit tests | |
// if words.length is 0, return 0 | |
// else return size of unique set | |
return words.length && set.size | |
} | |
function forEachArticle(article) { | |
// fixed by unit testing | |
var title = getTitleFor(article) | |
var wordCount = getWordcountFor(article) | |
return { title, wordCount } | |
} | |
function forEachTitle(article) { | |
// title fixed by unit testing | |
var title = getTitleFor(article) | |
var wordCount = article.wordCount | |
var plural = getPluralFor(wordCount) | |
return ` Article "${title}" has ${wordCount} unique word${plural}.` | |
} | |
function forEachAuthor(author) { | |
// default check added by unit tests | |
if (author == null) { | |
return undefined | |
} | |
var name = getNameFor(author) | |
var articles = getArticlesBy(author) | |
var articleCount = articles.length | |
var plural = getPluralFor(articleCount) | |
var aboutAuthor = `Author "${name}" has published ${articleCount} article${plural}.` | |
var aboutTitles = articles | |
.map(forEachArticle) | |
.map(forEachTitle) | |
return { | |
author: aboutAuthor, | |
titles: aboutTitles | |
} | |
} | |
/* entry point */ | |
function main(authors) { | |
if (!Array.isArray(authors) || !authors.length) { | |
return | |
} | |
authors.map(forEachAuthor).map(about => { | |
console.warn(about.author) | |
about.titles.map(function(title) { | |
console.log(title) | |
}) | |
}) | |
} | |
/* test it out */ | |
console.info("/* main api test */") | |
var fixture = [ | |
{ name: 'test'}, | |
{ firstName: 'firsty'}, | |
{ firstName: 'firsty', lastName: 'lasty'}, | |
{ name: 'namey', firstName: 'firsty', lastName: 'lasty'}, | |
{ articles: []}, | |
{ articles: [{ title: 'short Title'}]}, | |
{ articles: [{ title: '', contents: "not a very long article"}]}, | |
{ name: 'some author', articles: [{ title: 'some title', contents: "some contents containing 5 words."}]}, | |
{ | |
firstName: 'Author', lastName: 'McAuthor', | |
articles: [ | |
{ | |
title: 'Interesting Book with Words', | |
contents: "I found this book so awesome I can't hardly read it anymore, full stop." | |
}, | |
{ | |
title: 'Rex Tillerson\'s Guide to the Department of State', | |
contents: "I found this book really awesome and I couldn't put it down after 10.5 minutes." | |
}, | |
{ | |
title: 'Lance Shmendrickson', | |
contents: "Nothing but numbers like, 8, 8, and 8." | |
} | |
] | |
} | |
] | |
/* call it */ | |
main(fixture) | |
// Should see => | |
/* | |
Author "test" has published 0 articles. | |
Author "firsty" has published 0 articles. | |
Author "firsty lasty" has published 0 articles. | |
Author "namey" has published 0 articles. | |
Author "<Unknown author>" has published 0 articles. | |
Author "<Unknown author>" has published 1 article. | |
Article "short Title" has 0 unique words. | |
Author "<Unknown author>" has published 1 article. | |
Article "<Untitled>" has 5 unique words. | |
Author "some author" has published 1 article. | |
Article "some title" has 5 unique words. | |
Author "Author McAuthor" has published 3 articles. | |
Article "Interesting Book with Words" has 13 unique words. | |
Article "Rex Tillerson's Guide to the Department of State" has 14 unique words. | |
Article "Lance Shmendrickson" has 6 unique words. | |
*/ | |
/* unit tests */ | |
console.log("\n") | |
console.info("/* unit tests */") | |
console.info("assertions should print test title followed by") | |
console.info("%c true", 'color: blue') | |
console.log("expect getPluralFor('3') to return 's'", | |
getPluralFor('3') === 's') | |
console.log("expect getPluralFor(1) to return ''", | |
getPluralFor(1) === '') | |
console.log("expect getPluralFor(-2) to return 's'", | |
getPluralFor(-2) === 's') // pathological test | |
console.log("expect getNameFor({ name: 'james' }) to return 'james'", | |
getNameFor({ name: 'james' }) === 'james') | |
console.log("expect getNameFor({ name: 'james', lastName: 'last' }) to return only 'james'", | |
getNameFor({ name: 'james', lastName: 'last' }) === 'james') | |
console.log("expect getNameFor({ firstName: 'james', lastName: 'last' }) to return 'james last'", | |
getNameFor({ firstName: 'james', lastName: 'last' }) === 'james last') | |
console.log("expect getNameFor({ name: ' ', firstName: ' ', lastName: ' ' }) to return '<Unknown author>'", | |
getNameFor({ name: ' ', firstName: ' ', lastName: ' ' }) === '<Unknown author>') | |
console.log("expect getNameFor({ }) to return empty array", | |
getNameFor({ }).length === 0) | |
console.log("expect getNameFor({ articles: { one: 'one article' } }) to return empty array", | |
getNameFor({ articles: { one: 'one article' } }).length === 0) | |
console.log("expect getNameFor({ articles: [{ title: 'one article' }] }) to return array of one item", | |
getNameFor({ articles: [{ title: 'one article' } ] })[0].title === 'one article') | |
console.log("expect getTitleFor({ title: 'one article' }) to return 'one article'", | |
getTitleFor({ title: 'one article' }) === 'one article') | |
console.log("expect getTitleFor({ title: ' ' }) to return '<Untitled>'", | |
getTitleFor({ title: ' ' }) === '<Untitled>') | |
console.log("expect useLettersAndDigits('123.456') to return '123456'", | |
useLettersAndDigits('123.456') === '123456') | |
console.log("expect useLettersAndDigits('comma,') to return 'comma'", | |
useLettersAndDigits('comma,') === 'comma') | |
console.log("expect useLettersAndDigits('1for2') to return '1for2'", | |
useLettersAndDigits('1for2') === '1for2') | |
console.log("expect useLettersAndDigits('self-regard') to return 'selfregard'", | |
useLettersAndDigits('self-regard') === 'selfregard') | |
console.log("expect useLettersAndDigits('') to return ''", | |
useLettersAndDigits('') === '') | |
console.log("expect isNonEmpty(' ') to return false", | |
isNonEmpty(' ') === false) | |
console.log("expect isNonEmpty(' 5 ') to return true", | |
isNonEmpty(' 5 ') === true) | |
console.log("expect getWordcountFor({ contents: 'one one' }) to return 1", | |
getWordcountFor({ contents: 'one one' }) === 1) | |
console.log("expect getWordcountFor({ contents: ' ' }) to return 0", | |
getWordcountFor({ contents: ' ' }) === 0) | |
console.log("expect getWordcountFor({ contents: ' h red 99 ' }) to return 3", | |
getWordcountFor({ contents: ' h red 99 ' }) === 3) | |
console.log("expect forEachArticle({ title: 'test' }).title to return 'test'", | |
forEachArticle({ title: 'test' }).title === 'test') | |
console.log("expect forEachArticle({ contents: 'testing one two three and three only ' }).wordCount to return 6", | |
forEachArticle({ contents: 'testing one two three and three only ' }).wordCount === 6) | |
console.log("expect forEachTitle({ title: 'test', wordCount: 3 }) to return \" Article \"test\" has 3 unique words.\"", | |
forEachTitle({ title: 'test', wordCount: 3 }) === " Article \"test\" has 3 unique words.") | |
console.log("expect forEachTitle({ wordCount: 1 }) to return \" Article \"<Untitled>\" has 1 unique word.\"", | |
forEachTitle({ wordCount: 1 }) === " Article \"<Untitled>\" has 1 unique word.") | |
console.log("expect forEachAuthor() to return undefined", | |
forEachAuthor() === undefined) | |
console.log("expect forEachAuthor({ articles: [1,2,3] }).author to return \"Author \"<Unknown author>\" has published 3 articles.\"", | |
forEachAuthor({ articles: [1,2,3] }).author === "Author \"<Unknown author>\" has published 3 articles.") | |
console.log("expect forEachAuthor({ firstName: 'Ted', lastName: 'Johanson', articles: [8] }).author to return \"Author \"Ted Johanson\" has published 1 article.\"", | |
forEachAuthor({ firstName: 'Ted', lastName: 'Johanson', articles: [8] }).author === "Author \"Ted Johanson\" has published 1 article.") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// original from @airporty | |
// gist https://gist.github.com/airportyh/203f7c2d8a8b29af44218b79596af32f | |
// tweet https://twitter.com/airportyh/status/931540087602581504 | |
function main(authors) { | |
authors.forEach(function(author) { | |
let name, articles; | |
if (author) { | |
if (author.name) { | |
name = author.name; | |
} else if (author.firstName) { | |
if (author.lastName) { | |
name = author.firstName + ' ' + author.lastName; | |
} else { | |
name = author.firstName; | |
} | |
} | |
} | |
if (!name) { | |
name = '<Unknown author>'; | |
} | |
if (author) { | |
articles = author.articles; | |
} | |
if (!articles) { | |
articles = []; | |
} | |
let articleCount = articles.length; | |
let maybeS = articleCount > 1 || articleCount === 0 ? 's' : ''; | |
console.log(`${name} has published ${articles.length} article${maybeS}.`); | |
articles.forEach(function(article) { | |
let title, wordCount; | |
if (article) { | |
title = article.title; | |
} | |
if (!title) { | |
title = '<Untitled>'; | |
} | |
if (article) { | |
if (article.contents) { | |
let words = article.contents | |
.split(/[^A-Za-z']+/) | |
.filter(word => !!word); | |
wordCount = words.length; | |
} | |
} | |
if (!wordCount) { | |
wordCount = 0; | |
} | |
console.log(` Article ${title} has ${wordCount} words.`); | |
}); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment