Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First release #2

Closed
4 of 6 tasks
jwoudenberg opened this issue Mar 6, 2016 · 7 comments
Closed
4 of 6 tasks

First release #2

jwoudenberg opened this issue Mar 6, 2016 · 7 comments
Milestone

Comments

@jwoudenberg
Copy link
Collaborator

jwoudenberg commented Mar 6, 2016

Stuff that needs to happen before we can go public with this. Feel free to add additional points.

@jwoudenberg jwoudenberg added this to the v1.0.0 milestone Mar 6, 2016
@jwoudenberg
Copy link
Collaborator Author

jwoudenberg commented Apr 18, 2016

I think the role of this library is coming a bit better in focus. Macho is going to use the world mocking pretty extensively for it's cli tests and I'm not happy with how that works yet. So I'd like to wrap this up and preferably release it before returning to Macho.

I propose to focus this library on providing a monadic api for doing IO in node. The underlying IO monad being used should be exposed in some way but I'd argue that for the most part you don't need direct access to that at all (you just start with one of the Monad-returning functions and chain from there).

By going this way, I think it's a bit easier to show people what this library is about. We can have it mirror the native node implementation (of course using curried functions and IO monads instead of callbacks) so those familiar with Node and Monads should be able to use it straight away.

Should there at some point be an interesting in splitting out the IO monad itself into a separate library, for instance to have the flexibility to build another lib for browser IO on top of it, that's of course always a possibility.

I've started by automatically creating Monad versions of every fs method. The only disadvantage I see of wrapping automatically is that we cannot set the argument order to something most sensible for currying, but I don't think that outweighs the convenience of having the same API as the native fs module.

Because working in js involves importing a lot of possibly IO oriented libs, I want to add a very simple function to wrap any external function into an IO action, one that automatically adds a method to the world:

const myIo = io.extend({
  // Resolve returns a synchronous value.
  'my.resolve': (path) => require('resolve')(path)
  // Globby returns a promise.
  globby: (globs) => require('globby')(globs)
})

// myIo contains the native IO actions.
myIo.fs.readFile(...)

// myIo is extended with the user provided IO actions.
myIO.my.resolve(...)

For testing, I think a generator-based approach could be really cool:

const io = require('./cli')
const myCliTest = ioTestHelper(io, function * () {
  // Wait for the cli to call `io.process.argv`.
  yield take('process.argv')
  // Respond with some made-up answer.
  yield put(['myCli', './foo.txt'])

  // Wait again for the cli. This time it calls `io.fs.readFile` passing some arguments.
  const [readPath, readOptions] = yield take('io.fs.readFile')
  // Again return some response.
  yield put('Some text in a file\n')
  ...
})

The test helper could throw if the cli calls another io action than the one specified in the generator.

What do you think?

@jwoudenberg
Copy link
Collaborator Author

Btw, the cli app in the test scenario above is just a suggestion. I don't think I'd recommend testing the entire app in that way. Because the functions that make up the app are pure though, we can use it to write effective unit tests for the different parts of the cli.

@stoeffel
Copy link
Collaborator

This is great!
A app build with this could also easily be tested with some thing like redux-saga-test.
Not sure about passing names though. Why no just the functions!

@jwoudenberg
Copy link
Collaborator Author

Hey, sorry, saw I forgot to respond to this.

Perhaps I misunderstand the comment, but the problem I found with just using the functions is that from the outside, you have no idea what the function is supposed to do. The only way to find out is to run it, incurring the side effects, which you don't want in the test scenario.

So the names are basically there to make testing nicer. Without them, the test can be told a function is called with certain arguments, but whether it is console.log or require will be impossible to tell.

If you don't rely on the testing functionality and just want to run your IO monads, they bring no advantage. But you won't see them either in using the lib, so I think that's ok, right?

@jwoudenberg
Copy link
Collaborator Author

Ok, so from my point of view #3 and #5 are done. If you agree, I'd say we move this to the futurize org, open it up, and I'll tackle CI and publishing :).

@stoeffel
Copy link
Collaborator

stoeffel commented May 6, 2016

done. I moved it over and OS-ed it.

@jwoudenberg
Copy link
Collaborator Author

Thanks! Publishes v1.0.0, added some badges and enabled greenkeeper.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants