I'm starting just now with CoffeeScript and I found out that I can't solve problems like looping and recursives with just one line. I would like to improve the code that I just wrote using built-in CoffeeScript helpers.
'use strict'
file_system = require 'fs'
Types = require './types'
Extract =
each_file: (index = 0) ->
length = @files.length
file = @files[index]
if index < length
Types.read file, @next.bind @
@each_file index + 1
next: (file) ->
@result.push file
if @result.length == @files.length
return @cb.clean.call @cb, @result
@each_file()
return
init: (files, cb) ->
@files = files
@cb = cb
@result = []
@each_file()
return
module.exports = Extract
The script speaks for itself; I'm doing a recursive function to send files to Types.read, and I store the result in the result array.
1 Answer 1
Fake for-loops and comprehensions
At the beginning of your post, you say that you can't always achieve everything with looping in one line in CoffeeScript. When you say that, I assume you are taking about the each_file:
each_file: (index = 0) -> length = @files.length file = @files[index] if index < length Types.read file, @next.bind @ @each_file index + 1
This is kinda ugly right now because you seem to be using a method to fake a for-loop. Luckily, with CoffeeScript's comprehensions, we can turn this into a simple 1-line expression.
First, we need to be iterating through all of the @files. That can be written simply like this:
Types.read(file, @next.bind this) for file in @files
This is a comprehension that will go through all of the @files and substitute the file in the Types.read call with the current file it's looping over.
Now that we have this, you can remove that
file = @files[index]
line, along with that single index parameter. Why? Because, now that we have this loop, we no longer have any of that method-recursion-fake-for-loop-idness.
Along with those, since this is now a comprehensions that loops through all the values in an array, we don't need to do any checking to make sure the index is less than the length.
if index < length
Can be removed. Guess what your method looks like now?
each_file: () ->
Types.read(file, @next.bind @) for file in @files
The above method will do exactly what it was doing before: it will go through all of the files in @files and pass it into Types.read along with @next.bind @.
What's different now?
It's much shorter and much simpler than what you were doing before. As I already stated, you seemed to be reinventing the
forloop with that recursion you were doing.It's more idiomatic. CoffeeScript has those comprehensions so you can simplify long tasks into a few small and readable lines.
Misc.
init: (files, cb) -> @files = files @cb = cb
This can be shortened to this:
init: (@files, @cb) ->
The CoffeeScript compiler treats parameters with a @ before them as a name of a property to set to the parameter. For example, @files will become:
this.files = files
in the method body.
You must log in to answer this question.
Explore related questions
See similar questions with these tags.
Types.readdoing? \$\endgroup\$