i am writing a small utility using ramda
and data.task
that reads image files out of a directory and outputs their size. I got it working like so:
const getImagePath = assetsPath => item => `${assetsPath}${item}`
function readImages(path) {
return new Task(function(reject, resolve) {
fs.readdir(path, (err, images) => {
if (err) reject(err)
else resolve(images)
})
})
}
const withPath = path => task => {
return task.map(function(images) {
return images.map(getImagePath(path))
})
}
function getSize(task) {
return task.map(function(images) {
return images.map(sizeOf)
})
}
const getImageSize = dirPath => compose(getSize, withPath(dirPath), readImages)
The problem is with the withPath
function that adds the correct image path to the image file name but forces my api to pass in the directoryName twice: once for reading the files and second time for reading the path. This means I have to call the getImageSize
function like so:
const portfolioPath = `${__dirname}/assets/`
getImageSize(portfolioPath)(portfolioPath).fork(
function(error) {
throw error
},
function(data) {
console.log(data)
}
)
Is there any way to pass the dirname
as a parameter only once? I want the api to work like this:
getImageSize(portfolioPath).fork(
function(error) {
throw error
},
function(data) {
console.log(data)
}
)
You shouldn't be building paths manually like that
One of Node's better APIs is the Path module – I would recommend that your readImages
wrapper is made a generic readdir
wrapper, and instead resolve an Array of path.resolve
'd file paths
const readdir = dir =>
new Task ((reject, resolve) =>
fs.readdir (dir, (err, files) =>
err
? reject (err)
: resolve (files.map (f => path.resolve (dir, f)))
const getImagesSizes = dir =>
readdir (dir) .map (R.map (sizeOf))
Wrapping the Node continuation-passing style APIs just to return a Task
gets to be a bother, doesn't it?
const taskify = f => (...args) =>
Task ((reject, resolve) =>
f (...args, (err, x) =>
err ? reject (err) : resolve (x)))
const readdir = (dir, ...args) =>
taskify (fs.readdir) (dir, ...args)
.map (R.map (f => path.resolve (dir, f)))
const getImagesSizes = dir =>
readdir (dir) .map (R.map (sizeOf))
You should probably also take care to file out file paths that are directories – unless your sizeOf
implementation handles that
I managed to solve this by passing the Task
resolution a single object like so:
function readImages(path) {
return new Task(function(reject, resolve) {
fs.readdir(path, (err, images) => {
if (err) reject(err)
else resolve({ images, path })
})
})
}
const withPath = task => {
return task.map(function({ images, path }) {
return images.map(getImagePath(path))
})
}
...and then destructing it out of the task payload and now my compose function looks like this:
module.exports = (function getImageSize(dirPath) {
return compose(getSize, withPath, readImages)
})()
And my api call looks like this:
getImageSize(portfolioPath).fork(
function(error) {
throw error
},
function(data) {
console.log(data)
}
)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.