Functional JavaScript: Function Composition For Every Day Use.
// Arrow function
// https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/arrow_functions
const encodeAttribute = (x = '') => {
return x.replace(/"/g, '"')
}
const toAttributeString = (x = {}) => {
return Object.keys(x)
.map(attr => `${encodeAttribute(attr)}="${encodeAttribute(x[attr])}"`)
.join(" ")
}
const tagAttributes = x => (c = "") => {
return `<${x.tag}${x.attr? " " :""}${toAttributeString(x.attr)}>${c}</${x.tag}>`
}
const tag = x => {
return typeof x === "string"
? tagAttributes({tag: x})
: tagAttributes(x)
}
console.log(tag("b")("content"))
console.log(tag({tag: "b", attr: {class: "title", src: "http"}})("content"))
const listGroup = tag({tag: "ul", attr: {class: "list-group"}})
const listGroupItem = tag({tag: "li", attr: {class: "list-group-item"}})
const listGroupItems = items => {
return items.map(listGroupItem).join("")
}
// listGroup is a function which takes content as argument, below calling without any content
console.log(listGroup()) //<ul class="list-group"></ul>
console.log(listGroupItem()) //<li class="list-group-item"></li>
console.log(listGroupItems(['Cras justo', 'Dapibus ac']))
// <li class="list-group-item">Cras justo</li><li class="list-group-item">Dapibus ac</li>
// Passing listGroupItems as argument for listGroup
console.log(listGroup(listGroupItems(['Cras justo', 'Dapibus ac'])))
// <ul class="list-group">
// <li class="list-group-item">Cras justo</li>
// <li class="list-group-item">Dapibus ac</li>
// </ul>
const listGroupTag = tag({tag: "ul", attr: {class: "list-group"}})
const listGroup2 = items => {
return listGroupTag(listGroupItems(items))
}
console.log((listGroup2(['Cras justo', 'Dapibus ac'])))
// compose: call functions right to left
const compose = (...functions) => data => {
return functions.reduceRight((value, func) => func(value), data)
}
// pipe: call functions left to right
const pipe = (...functions) => data => {
return functions.reduce((value, func) => func(value), data)
}
const listGroup3 = items => {
return compose(listGroupTag, listGroupItems)(items)
}
console.log(listGroup3(['Cras justo', 'Dapibus ac']))
// compose returns function which takes "data" as argument, so we can write as below
const listGroup4 = compose(listGroupTag, listGroupItems)
console.log((listGroup4(['Cras justo', 'Dapibus ac'])))
// The power of function composition is realized as your codebase grows,
// allowing you to create numerous compositions.
const panelTag = tag({tag: "div", attr: {class: "panel panel-default"}})
const panelBody = tag({tag: "div", attr: {class: "panel-body"}})
const basicPanel = compose(panelTag, panelBody)
console.log(basicPanel("content"))
// <div class="panel panel-default"><div class="panel-body">content</div></div>
const listGroupPanel = compose(basicPanel, listGroupTag, listGroupItems)
console.log(listGroupPanel(['Cras justo', 'Dapibus ac']))
/*
<div class="panel panel-default">
<div class="panel-body">
<ul class="list-group">
<li class="list-group-item">Cras justo</li>
<li class="list-group-item">Dapibus ac</li>
</ul>
</div>
</div>
*/