CoffeeScriptの文法拡張して非同期でネストが深くならないようにしてみた
コールバックごりごり書いてるとネストが深くなって嫌だね〜
ということで深くならない用な記法を追加するプリプロセッサをでっち上げる、というテスト。
CoffeeScript自体がJSの文法を拡張するものだから、自分で追加してもいいじゃん、ということでソースを覗いてみたが、エイリアスを追加するならともかく、新しい概念を継ぎ足すのはちょっと大掛かりっぽいので、簡単なパーサ書いてみるだけにした。
なにがやりかったというと
<- と next がペアになって非同期の結果を受け取る
fs = require 'fs' main = -> err,txt1 <- fs.readFile 'hello1.txt', next err,txt2 <- fs.readFile 'hello2.txt', next err,txt3 <- fs.readFile 'hello3.txt', next console.log i.toString() for i in [txt1,txt2,txt3] main()
これをコンパイルするとこうなる(まだCoffeeScript)
fs = require 'fs' main = -> fs.readFile 'hello1.txt', (err,txt1)-> [err,txt1] = (v for _,v of arguments) fs.readFile 'hello2.txt', (err,txt2)-> [err,txt2] = (v for _,v of arguments) fs.readFile 'hello3.txt', (err,txt3)-> [err,txt3] = (v for _,v of arguments) console.log i.toString() for i in [txt1,txt2,txt3] main()
ソース
超適当
mycf
#!/usr/bin/env coffee lines = require('fs').readFileSync(process.argv[2]).toString().split('\n') async_symbol = '<-' next_symbol = 'next' ret = [] depth = 0 params = null start = null ret = [] for i in [0...lines.length] line = lines[i] prefix = line.match(/^\s+/)?[0].length or 0 str_prefix = (' ' for _ in [0...(prefix+2*depth)]).join('') if params ret.push str_prefix + "[#{params}] = (v for _,v of arguments)" params = null if line.indexOf(async_symbol) > -1 [left,right] = line.split(async_symbol) params = left.split(" ").join("") ret.push str_prefix+right.replace(/\s*/,'').replace(next_symbol, "(#{params})->") if start is null start = depth depth++ else a = lines[i].match(/^\s+/)?[0].length or 0 b = lines[i-1]?.match(/^\s+/)?[0].length or 0 if i>0 and a < b depth = start start = null str_prefix = (' ' for _ in [0...(prefix+2*depth)]).join('') ret.push str_prefix+line.replace(/\s*/,'') console.log ret.join('\n')
保存
$mycf hogehoge.async.coffee > hogehoge.coffee
欠点
- 引数の最後がコールバック関数のものしか書けない
- 並列実行の仕組みとかない
- 一度 <-で並列関数でよんだらネスト元に戻せない
cakefileに混ぜて使うぐらいには使えるかなー
そういう文法の提案があったっていいよね。