From da72eacbada19feb205b14762b81452f97b3c3a4 Mon Sep 17 00:00:00 2001 From: Luiz Paulo Date: Tue, 25 Aug 2020 01:53:17 -0300 Subject: [PATCH] Add pipeline pattern --- CHANGELOG.md | 4 ++ README.md | 63 ++++++++++++------ dist/favicon.png | Bin 552 -> 0 bytes dist/index.html | 1 - dist/main.js | 12 ---- dist/patterns.min.js | 2 - dist/patterns.min.js.map | 1 - src-example/index.html | 4 +- src-example/src/middleware.js | 23 +++++++ src-example/{main.js => src/observer.js} | 5 +- src-example/src/pipeline.js | 20 ++++++ src/index.js | 6 +- src/pattern/pipeline/Pipeline.js | 17 +++++ .../pipeline/__tests__/Pipeline.test.js | 40 +++++++++++ src/pattern/pipeline/index.js | 3 + webpack.config.js | 4 +- 16 files changed, 163 insertions(+), 42 deletions(-) delete mode 100644 dist/favicon.png delete mode 100644 dist/index.html delete mode 100644 dist/main.js delete mode 100644 dist/patterns.min.js delete mode 100644 dist/patterns.min.js.map create mode 100644 src-example/src/middleware.js rename src-example/{main.js => src/observer.js} (56%) create mode 100644 src-example/src/pipeline.js create mode 100644 src/pattern/pipeline/Pipeline.js create mode 100644 src/pattern/pipeline/__tests__/Pipeline.test.js create mode 100644 src/pattern/pipeline/index.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 6967ead..b2cce0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.2.0] - 2020-08-25 +### Feature +- Added pipeline pattern + ## [1.1.0] - 2020-08-24 ### Feature - Added middleware pattern diff --git a/README.md b/README.md index 199f1a5..de18ad1 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,39 @@ See many characteristics of this library: | Available Patterns | |--------------------------| -| [Observer](Observer) | -| [Middleware](Middleware) | +| [Middleware](#Middleware) | +| [Observer](#Observer) | +| [Pipeline](#Pipeline) | + +## Middleware +A single implementation of Middleware pattern + +**Class structure** +```js +class Middleware() { + use(callback: function) + process(...data: object) +} +``` + +## Example + +```js + const middleware = new Middleware() + + middleware.use((param1, param2, param3, next) => { + param1 = 'param 1 UPDATED' + console.log('Execution 1', param1, param2, param3) + next() + }) + + middleware.use((param1, param2, param3, next) => { + console.log('Execution 2', param1, param2, param3) // param1 = 'param 1 UPDATED' + next() + }) + + middleware.process('param 1', 'param 2', 'param 3') +``` ## Observer The instance (or model) maintains a collection of objects (observers) and will notify them of any changes in their state. @@ -33,34 +64,26 @@ class Observer() { observer.emit('test', { status: 'Observer emit successful' }) ``` -## Middleware -A single implementation of Middleware pattern +## Pipeline +A Pipeline pattern implementation **Class structure** ```js -class Middleware() { - use(callback: function) - process(...data: object) +class Pipeline() { + pipe(callback: function) + process(data: object) } ``` ## Example ```js - const middleware = new Middleware() + const result = (new Pipeline()) + .pipe((data) => data + 5) + .pipe((data) => data * 20) + .pipe((data) => data / 2) + .process(5) // result 100 - middleware.use((param1, param2, param3, next) => { - param1 = 'param 1 UPDATED' - console.log('Execution 1', param1, param2, param3) - next() - }) - - middleware.use((param1, param2, param3, next) => { - console.log('Execution 2', param1, param2, param3) // param1 = 'param 1 UPDATED' - next() - }) - - middleware.process('param 1', 'param 2', 'param 3') ``` ## Versioning diff --git a/dist/favicon.png b/dist/favicon.png deleted file mode 100644 index aafea9c81c792eaf6fe14b22c06a4dff761c4b05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 552 zcmV+@0@wXgNk&E>0ssJ4MM6+kP&iBz0ssInKfn(V59AP%BtdF_l6QKNyZ@=waMVVU zB<1qww3zle$95P&+qQ9$9MbuN`9mNG(PR@%@JMWYfA;`e1b_hpDF6l_AOc~?A^=Pn z0v2Fa3;^h$7{w&qKmRv|rjsk0iZBf24)>1$LxJDR{R5;JDj6rC0>l5Xaxo}|afeBV z=L%uq{;4p}^#M#6NQwynL;i1y3NQ*`$N&a_*aGnRp6=6r_wwEkWJ{85+Sch~+qP}n zxVDaMvp2qdj5T-6H7}lSL`455AnIQ*7;rYI1>kJp{|6nty}iA)UMXD*Z{N%fru*rT zB$u?f=}W2)Z&RE|{zb#RVi!Kscr)a`W=1&SzgNm^QQpuQc{3K{zjg5m0Lt&a6hQaY zv6vDliG~ZC;#;&Z_0>ng_c`u#E4-ObcP09#Lf)?Ax`E0|jl5sWb^@jQ9^^@*6G&gV z_uyln6F~0jjmC#cH-NO6YlWX(0Wy}9y98%|MZs!IrP0c{m{YRW$~+pBRx25=U;0Hl zPattern JS

Patter JS

Open you inspection to see result

\ No newline at end of file diff --git a/dist/main.js b/dist/main.js deleted file mode 100644 index 8b7d3f6..0000000 --- a/dist/main.js +++ /dev/null @@ -1,12 +0,0 @@ -function runExample () { - testObserver() -} - -function testObserver () { - const observer = new Observer() - observer.on('test', (data) => console.log(data)) - observer.on('test', (data) => console.log('Test 2 > ', data)) - observer.emit('test', { status: 'Observer emit successful' }) -} - -document.addEventListener('DOMContentLoaded', runExample, false) diff --git a/dist/patterns.min.js b/dist/patterns.min.js deleted file mode 100644 index 887a5ec..0000000 --- a/dist/patterns.min.js +++ /dev/null @@ -1,2 +0,0 @@ -!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var r=t();for(var n in r)("object"==typeof exports?exports:e)[n]=r[n]}}(window,(function(){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=0)}([function(e,t,r){"use strict";r.r(t),r.d(t,"Observer",(function(){return n}));var n=class{constructor(){this.observer=[]}on(e,t){return this.addEvent(e),this.observer[e].push(t),this}emit(e,t){this.addEvent(e),this.observer[e].forEach(e=>e(t))}addEvent(e){void 0===this.observer[e]&&(this.observer[e]=[])}}}])})); -//# sourceMappingURL=patterns.min.js.map \ No newline at end of file diff --git a/dist/patterns.min.js.map b/dist/patterns.min.js.map deleted file mode 100644 index 5a294bd..0000000 --- a/dist/patterns.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///webpack/bootstrap","webpack:///./src/pattern/observer/Observer.js","webpack:///./src/pattern/observer/index.js"],"names":["root","factory","exports","module","define","amd","a","i","window","installedModules","__webpack_require__","moduleId","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","this","observer","event","callback","addEvent","push","data","forEach","undefined"],"mappings":"CAAA,SAA2CA,EAAMC,GAChD,GAAsB,iBAAZC,SAA0C,iBAAXC,OACxCA,OAAOD,QAAUD,SACb,GAAqB,mBAAXG,QAAyBA,OAAOC,IAC9CD,OAAO,GAAIH,OACP,CACJ,IAAIK,EAAIL,IACR,IAAI,IAAIM,KAAKD,GAAuB,iBAAZJ,QAAuBA,QAAUF,GAAMO,GAAKD,EAAEC,IAPxE,CASGC,QAAQ,WACX,O,YCTE,IAAIC,EAAmB,GAGvB,SAASC,EAAoBC,GAG5B,GAAGF,EAAiBE,GACnB,OAAOF,EAAiBE,GAAUT,QAGnC,IAAIC,EAASM,EAAiBE,GAAY,CACzCJ,EAAGI,EACHC,GAAG,EACHV,QAAS,IAUV,OANAW,EAAQF,GAAUG,KAAKX,EAAOD,QAASC,EAAQA,EAAOD,QAASQ,GAG/DP,EAAOS,GAAI,EAGJT,EAAOD,QA0Df,OArDAQ,EAAoBK,EAAIF,EAGxBH,EAAoBM,EAAIP,EAGxBC,EAAoBO,EAAI,SAASf,EAASgB,EAAMC,GAC3CT,EAAoBU,EAAElB,EAASgB,IAClCG,OAAOC,eAAepB,EAASgB,EAAM,CAAEK,YAAY,EAAMC,IAAKL,KAKhET,EAAoBe,EAAI,SAASvB,GACX,oBAAXwB,QAA0BA,OAAOC,aAC1CN,OAAOC,eAAepB,EAASwB,OAAOC,YAAa,CAAEC,MAAO,WAE7DP,OAAOC,eAAepB,EAAS,aAAc,CAAE0B,OAAO,KAQvDlB,EAAoBmB,EAAI,SAASD,EAAOE,GAEvC,GADU,EAAPA,IAAUF,EAAQlB,EAAoBkB,IAC/B,EAAPE,EAAU,OAAOF,EACpB,GAAW,EAAPE,GAA8B,iBAAVF,GAAsBA,GAASA,EAAMG,WAAY,OAAOH,EAChF,IAAII,EAAKX,OAAOY,OAAO,MAGvB,GAFAvB,EAAoBe,EAAEO,GACtBX,OAAOC,eAAeU,EAAI,UAAW,CAAET,YAAY,EAAMK,MAAOA,IACtD,EAAPE,GAA4B,iBAATF,EAAmB,IAAI,IAAIM,KAAON,EAAOlB,EAAoBO,EAAEe,EAAIE,EAAK,SAASA,GAAO,OAAON,EAAMM,IAAQC,KAAK,KAAMD,IAC9I,OAAOF,GAIRtB,EAAoB0B,EAAI,SAASjC,GAChC,IAAIgB,EAAShB,GAAUA,EAAO4B,WAC7B,WAAwB,OAAO5B,EAAgB,SAC/C,WAA8B,OAAOA,GAEtC,OADAO,EAAoBO,EAAEE,EAAQ,IAAKA,GAC5BA,GAIRT,EAAoBU,EAAI,SAASiB,EAAQC,GAAY,OAAOjB,OAAOkB,UAAUC,eAAe1B,KAAKuB,EAAQC,IAGzG5B,EAAoB+B,EAAI,GAIjB/B,EAAoBA,EAAoBgC,EAAI,G,+EC1DtC,ICtBA,EDFf,MACE,cACEC,KAAKC,SAAW,GAGlB,GAAIC,EAAOC,GAIT,OAHAH,KAAKI,SAASF,GACdF,KAAKC,SAASC,GAAOG,KAAKF,GAEnBH,KAGT,KAAME,EAAOI,GACXN,KAAKI,SAASF,GACdF,KAAKC,SAASC,GAAOK,QAAQJ,GAAYA,EAASG,IAGpD,SAASJ,QACsBM,IAAzBR,KAAKC,SAASC,KAChBF,KAAKC,SAASC,GAAS","file":"patterns.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse {\n\t\tvar a = factory();\n\t\tfor(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n\t}\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n","class Observer {\n constructor () {\n this.observer = []\n }\n\n on (event, callback) {\n this.addEvent(event)\n this.observer[event].push(callback)\n\n return this\n }\n\n emit (event, data) {\n this.addEvent(event)\n this.observer[event].forEach(callback => callback(data))\n }\n\n addEvent(event) {\n if (this.observer[event] === undefined) {\n this.observer[event] = []\n }\n }\n}\n\nexport default Observer\n","import Observer from './Observer'\n\nexport default Observer\n"],"sourceRoot":""} \ No newline at end of file diff --git a/src-example/index.html b/src-example/index.html index 1e472b8..23c41e7 100644 --- a/src-example/index.html +++ b/src-example/index.html @@ -11,6 +11,8 @@

Patter JS

Open you inspection to see result

- + + + diff --git a/src-example/src/middleware.js b/src-example/src/middleware.js new file mode 100644 index 0000000..ed7ee1c --- /dev/null +++ b/src-example/src/middleware.js @@ -0,0 +1,23 @@ +function testMiddleware () { + const middleware = new Middleware() + middleware.use((param1, param2, next) => { + param1.test += ' UPDATED' + console.log('[middleware] ', param1, param2) + next(param1, param2) + }) + + middleware.use((param1, param2, next) => { + param2 = param2 + ' UPDATED' + console.log('[middleware] ', param1, param2) + next(param1, param2) + }) + + middleware.use((param1, param2, next) => { + console.log('[middleware] ', param1, param2) + next(param1, param2) + }) + + middleware.process({ test: 123, value: 'aaa' }, 'test') +} + +document.addEventListener('DOMContentLoaded', testMiddleware, false) diff --git a/src-example/main.js b/src-example/src/observer.js similarity index 56% rename from src-example/main.js rename to src-example/src/observer.js index 8b7d3f6..849a353 100644 --- a/src-example/main.js +++ b/src-example/src/observer.js @@ -3,9 +3,10 @@ function runExample () { } function testObserver () { + console.log('[observer] ', 'test') const observer = new Observer() - observer.on('test', (data) => console.log(data)) - observer.on('test', (data) => console.log('Test 2 > ', data)) + observer.on('test', (data) => console.log('[observer] ', data)) + observer.on('test', (data) => console.log('[observer] ', 'Test 2 > ', data)) observer.emit('test', { status: 'Observer emit successful' }) } diff --git a/src-example/src/pipeline.js b/src-example/src/pipeline.js new file mode 100644 index 0000000..ca0d6ce --- /dev/null +++ b/src-example/src/pipeline.js @@ -0,0 +1,20 @@ +function testPipeline () { + const result = (new Pipeline()) + .pipe((data) => { + console.log('[pipeline] ', data + ' + ' + 5) + return data + 5 + }) + .pipe((data) => { + console.log('[pipeline] ', data + ' * ' + 3) + return data * 3 + }) + .pipe((data) => { + console.log('[pipeline] ', data + ' + ' + 150) + return data + 150 + }) + .process(5) + + console.log('[pipeline] result: ', result) +} + +document.addEventListener('DOMContentLoaded', testPipeline, false) diff --git a/src/index.js b/src/index.js index 8ee4dde..d48bf7f 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,9 @@ +import Middleware from './pattern/middleware' import Observer from './pattern/observer' +import Pipeline from './pattern/pipeline' export { - Observer + Middleware, + Observer, + Pipeline } diff --git a/src/pattern/pipeline/Pipeline.js b/src/pattern/pipeline/Pipeline.js new file mode 100644 index 0000000..ef2942f --- /dev/null +++ b/src/pattern/pipeline/Pipeline.js @@ -0,0 +1,17 @@ +class Pipeline { + constructor () { + this.pipelines = [] + } + + pipe (callback) { + this.pipelines.push(callback) + return this + } + + process (data) { + let result = data + return this.pipelines.map(fn => (result = fn(result))).pop() + } +} + +export default Pipeline diff --git a/src/pattern/pipeline/__tests__/Pipeline.test.js b/src/pattern/pipeline/__tests__/Pipeline.test.js new file mode 100644 index 0000000..f135545 --- /dev/null +++ b/src/pattern/pipeline/__tests__/Pipeline.test.js @@ -0,0 +1,40 @@ +import Pipeline from '../Pipeline' + +describe('Test Pipeline call all methods', () => { + const pipeline = new Pipeline() + + test('should assert method pipeline.pipe was called', () => { + jest.spyOn(pipeline, 'pipe') + pipeline.pipe(() => {}) + expect(pipeline.pipe).toHaveBeenCalled() + }) + + test('should assert method pipeline.process was called', () => { + jest.spyOn(pipeline, 'process') + pipeline.process(() => {}) + expect(pipeline.process).toHaveBeenCalled() + }) +}) + +describe('Test Pipeline call perfect scenaries', () => { + const result = (new Pipeline()) + .pipe((data) => { + test('Data should be 5', () => { + expect(data).toBe(5) + }) + + return data + 5 + }) + .pipe((data) => { + test('Data should be 10', () => { + expect(data).toBe(10) + }) + + return data * 2 + }) + .process(5) + + test('Result should be 20', () => { + expect(result).toBe(20) + }) +}) diff --git a/src/pattern/pipeline/index.js b/src/pattern/pipeline/index.js new file mode 100644 index 0000000..d227323 --- /dev/null +++ b/src/pattern/pipeline/index.js @@ -0,0 +1,3 @@ +import Pipeline from './Pipeline' + +export default Pipeline diff --git a/webpack.config.js b/webpack.config.js index 970d735..4c4d64c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -8,7 +8,7 @@ module.exports = { patterns: './src' }, output: { - filename: '[name].min.js', + filename: 'src/[name].min.js', path: path.resolve(__dirname, 'dist'), libraryTarget: 'umd' }, @@ -22,7 +22,7 @@ module.exports = { }), new CopyPlugin({ patterns: [ - { from: 'src-example/main.js', to: '' } + path.resolve(__dirname, 'src-example', 'src') ] }) ],