├── .gitignore ├── .npmignore ├── LICENCE ├── mostify.js ├── package.json ├── readMe.md └── src ├── mostify.ls └── package.json.ls /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | src/cmd.bat 3 | src/test.ls 4 | test.js -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | node_modules 3 | test.js 4 | .git -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Joy Krishna Mondal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /mostify.js: -------------------------------------------------------------------------------- 1 | var most, create, _, generateStream, mostify, slice$ = [].slice; 2 | most = require('most'); 3 | create = require('@most/create')['default']; 4 | _ = require('ramda'); 5 | generateStream = function(type, mainWithCallback){ 6 | return function(){ 7 | var userInput; 8 | userInput = slice$.call(arguments); 9 | return create(function(add, end, error){ 10 | userInput[userInput.length] = function(){ 11 | var ioResponse; 12 | ioResponse = slice$.call(arguments); 13 | if (type === 'with error') { 14 | if (ioResponse[0]) { 15 | error([ioResponse, userInput]); 16 | } else { 17 | ioResponse.shift(); 18 | add([ioResponse, _.init(userInput)]); 19 | } 20 | } else { 21 | add([ioResponse, _.init(userInput)]); 22 | } 23 | return end(); 24 | }; 25 | return mainWithCallback.apply(null, userInput); 26 | }); 27 | }; 28 | }; 29 | mostify = _.curry(function(type, module){ 30 | var keys, output, i$, len$, key; 31 | switch (typeof module) { 32 | case 'function': 33 | return generateStream(type, module); 34 | case 'object': 35 | keys = Object.keys(module); 36 | output = {}; 37 | for (i$ = 0, len$ = keys.length; i$ < len$; ++i$) { 38 | key = keys[i$]; 39 | output[key] = generateStream(type, module[key]); 40 | } 41 | return output; 42 | default: 43 | throw { 44 | message: 'Mostify: only accepts types function and object', 45 | name: 'typeError' 46 | }; 47 | } 48 | }); 49 | module.exports = { 50 | 'default': mostify('no error'), 51 | withError: mostify('with error'), 52 | __esModule: true 53 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@partially-applied/mostify", 3 | "version": "1.0.2", 4 | "description": "like promisify but for most.js", 5 | "main": "mostify.js", 6 | "dependencies": { 7 | "most": "1.0.0", 8 | "ramda": "0.21.0", 9 | "@most/create": "1.1.0" 10 | }, 11 | "license": { 12 | "type": "MIT", 13 | "url": "http://www.opensource.org/licenses/mit-license.php" 14 | }, 15 | "keyword": "livescript" 16 | } 17 | -------------------------------------------------------------------------------- /readMe.md: -------------------------------------------------------------------------------- 1 | 2 | ![](https://i.imgur.com/Whw8XEX.jpg) 3 | 4 | ### Mostify 5 | Like promisify but for `most.js` 6 | 7 | ``` 8 | npm install @partially-applied/mostify 9 | ``` 10 | 11 | ### Quick Guide in Code 12 | 13 | **JavaScript (ES5)** 14 | 15 | ```javascript 16 | 17 | // mostify returns an object 18 | // with two functions .withError and .default 19 | 20 | var mostify = (require ('@partially-applied/mostify')).withError 21 | 22 | // since we are dealing with fs in this example 23 | // we will be using .withError option 24 | 25 | var fsRaw = require ('fs') 26 | 27 | 28 | var fs = mostify(fsRaw) 29 | 30 | fs.readFile ('hello.txt') 31 | 32 | .map(function (input){ 33 | response = input[0] // returns an array 34 | console.log (response.toString()) // text file string 35 | }) 36 | .drain() 37 | 38 | ``` 39 | 40 | 41 | **Babel User** 42 | 43 | Using preset `es2015`, the only issue you need to worry about is imports: 44 | 45 | ```javascript 46 | 47 | import mostify from "@partially-applied/mostify" // for .default 48 | 49 | import {withError as mostify} from '@partially-applied/mostify' 50 | // for .withError 51 | 52 | ``` 53 | 54 | 55 | **LiveScript (ES5)** 56 | 57 | ```livescript 58 | 59 | # mostify returns an object 60 | # with two functions .withError and .default 61 | 62 | mostify = (require '@partially-applied/mostify').withError 63 | 64 | # since we are dealing with fs in this example 65 | # we will be using .withError option 66 | 67 | fs-raw = require 'fs' 68 | 69 | 70 | fs = mostify fs-raw 71 | 72 | fs.readFile 'hello.txt' 73 | .map ([response]) -> # returns an array 74 | console.log response.toString! # text file string 75 | .drain! 76 | ``` 77 | 78 | ## Features 79 | 80 | #### 1. Input Tracking 81 | 82 | The return value as you can observe is an array, the array has two elements 83 | 84 | ```livescript 85 | 86 | fs.readFile 'hello.txt' 87 | .map ([response,user-input]) -> 88 | console.log user-input[0] # 'hello.txt' 89 | .drain() 90 | 91 | ``` 92 | 93 | or with livescript pattern matching to make it nicer 94 | 95 | ```livescript 96 | 97 | fs.readFile 'hello.txt' 98 | .map ([response,[text-file]]) -> # important! returns an array 99 | console.log text-file # 'hello.txt' 100 | .drain() 101 | 102 | ``` 103 | 104 | **Application of Input Tracking** 105 | 106 | Input tracking is useful if you want to match requests and responses: 107 | 108 | ```livescript 109 | 110 | request stream : --a--b--c---> 111 | response stream : --b--c--a---> 112 | 113 | ``` 114 | 115 | The letters are paired - `--a--` in request stream corresponds to `--a--` in respose stream. Due to the nature of async computation its not possible to guarantee order, this is why sometimes you want to pass some variable id from request stream into the response stream as a way to track and pair them. 116 | 117 | ```livescript 118 | 119 | most = require 'most' 120 | 121 | fs = (require '@partially-applied/mostify').withError (require 'fs') 122 | 123 | # a list of sample files to read 124 | list-of-files = ['hello.txt','foo.txt','bar.txt'] 125 | 126 | responses = [] # an array that will store a list of streams 127 | 128 | for file in list-of-files 129 | response.push (fs.readFile file) 130 | 131 | 132 | most.mergeArray responses # merge all the streams in the array 133 | .map ([value,[filename]]) -> 134 | console.log value # how will you match which value is the output of which file ? 135 | # good thing the secound array element has filenames. 136 | 137 | 138 | .drain() 139 | 140 | 141 | 142 | 143 | ``` 144 | 145 | 146 | **Example with passing extra arguments** 147 | 148 | 149 | ```livescript 150 | 151 | # we can even pass an unique index in case file names are not unique 152 | 153 | files = ['hello.txt','foo.txt','bar.txt'] # make sure the files exist ! 154 | 155 | responses = [] 156 | 157 | for I from 0 til files.length 158 | response.push (fs.readFile files[I],'utf8',I) 159 | 160 | 161 | most.mergeArray responses 162 | .map (value) -> 163 | 164 | [output,[filename,encoding,index]] = value 165 | 166 | console.log index # => 0 then 1 then 2 167 | # essentially all input arguments get passed 168 | .drain() 169 | 170 | ``` 171 | 172 | #### 2. Single Functions 173 | 174 | Sometimes you do not want to mostify the entire module but singleton functions. The entry function *type checks* and if the parameter is a function then it only mostifies the function. 175 | 176 | 177 | ### Type Signature 178 | ```livescript 179 | 180 | :: [response,userinput] 181 | 182 | ``` 183 | 184 | - staying close to all stream API specs, returns a single argument in this case a Array. 185 | - where `response` is the argument object from the callback that we are intercepting. 186 | - where `userinput` is the argument object which the user passed to the orignal function call 187 | - If you pass 'with error' flag then the assumption is made that the first argument of the callback we are intercepting is the error object: 188 | - if error object is defined then the error stream is activated 189 | - `response` argument would be shifted by one element to the left. 190 | 191 | 192 | 193 | 194 | 195 | *Why use mostify rather than just use promises ?* 196 | 197 | 198 | If you are using `most.js` , creating a promise object seem like a extra unwanted step. Callbacks are the lowest level of abstraction you can find and rather than wrapping callbacks using promises and then rewrapping it using `most` streams, I think its more elegant to use `most` streams directly. It also helps that most streams are also more general while providing all the error handling goodiness that promise provides. 199 | 200 | ```livescript 201 | 202 | #Before 203 | Node.js style Callback -> Promise -> Most Stream 204 | 205 | #After 206 | Node.js style Callback -> Most Stream 207 | 208 | ``` -------------------------------------------------------------------------------- /src/mostify.ls: -------------------------------------------------------------------------------- 1 | most = require 'most' 2 | 3 | create = (require '@most/create').default 4 | 5 | _ = require 'ramda' 6 | 7 | generate-stream = (type,main-with-callback) -> -> 8 | 9 | user-input = [...arguments] # like .. 'hello.txt',(encoding:'uft') 10 | 11 | (add,end,error) <- create 12 | 13 | user-input[user-input.length] = -> # edit the final argument for add callback 14 | 15 | io-response = [...arguments] 16 | 17 | if (type is 'with error') 18 | 19 | if io-response[0] 20 | 21 | error [io-response,user-input] 22 | 23 | else 24 | 25 | io-response.shift! 26 | 27 | add [io-response,(_.init user-input)] 28 | 29 | else 30 | 31 | add [io-response,(_.init user-input)] 32 | 33 | 34 | end! 35 | 36 | main-with-callback.apply null, user-input 37 | 38 | 39 | 40 | 41 | 42 | mostify = _.curry (type,module) -> 43 | 44 | switch typeof module 45 | | 'function' => 46 | generate-stream type,module 47 | | 'object' => 48 | 49 | keys = Object.keys module 50 | 51 | output = {} 52 | 53 | for key in keys 54 | 55 | output[key] = generate-stream type, module[key] 56 | 57 | output 58 | 59 | | otherwise => 60 | 61 | throw message:'Mostify: only accepts types function and object',name:'typeError' 62 | 63 | return 64 | 65 | 66 | 67 | 68 | 69 | 70 | module.exports = 71 | default:mostify 'no error' # since there are only two options - I haven't used 'no error' string anywhere 72 | with-error:mostify 'with error' 73 | __esModule:true # only to maintain babel compatibility - will be removed when babel hype dies down 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/package.json.ls: -------------------------------------------------------------------------------- 1 | 2 | name:'@partially-applied/mostify' 3 | version:'1.0.2' 4 | description:'like promisify but for most.js' 5 | main:'mostify.js' 6 | dependencies: 7 | 'most':'1.0.0' 8 | 'ramda':'0.21.0' 9 | '@most/create':'1.1.0' 10 | license: 11 | *type:"MIT" 12 | url:"http://www.opensource.org/licenses/mit-license.php" 13 | keyword: 14 | *"livescript" 15 | 16 | --------------------------------------------------------------------------------