2017-06-06 4 views
1

Nodeにコンテンツのメンテナンスプログラムを書き込もうとしています。私は長い年月を経てきた古いRuby/Perl/Shellの手であり、これらの言語で同様に見える単純なコードをノードでは簡単に得ることはできません。NodeJS:idiomaticが必要です:dirのファイルを読み込み、連結し、変換し、書き込みします。

タスク:それらを変換し、(ls順で)それらを読んで、すべての*.mdファイルを検索し、ヘッダコメントとフッターのコメントでそれらを囲みます。これらのファイルには、組み立てられて変換されたときに分かりやすいHTML文書であるMarkdownがあります。ここでは、シェルの実装です:

echo '<!-- Generate at:' $(date) ' -->' $(ls *.md |xargs cat|markdown)'<!-- Copyright Mumble-demo Inc. -->'

は希望HTMLを生成します:

<!-- Generate at: Tue Jun 6 08:25:59 EDT 2017 --> <h1>This is a Markdown File</h1> <h2>Heading 1</h2> <p>Inside of markdown we can create many interesting items</p> <ul> <li>such</li> <li>as</li> <li>lists</li> </ul><!-- Copyright Mumble-demo Inc. --> 

Rubyは...

#!/usr/bin/env ruby 
require 'kramdown' 

HEADER = "<!-- Generated at #{Time.now} -->\n" 
FOOTER = "\n<!-- Copyright Mumble-demo Inc. -->" 

OUTPUT = File.open("./output", "w") 

results = Dir.glob("*.md").map { |f| File.open(f).readlines.join() }.reduce(:+) 
OUTPUT.print(HEADER, Kramdown::Document.new(results).to_html, FOOTER) 

同様に合理的である。しかし、私が行う方法を見つけ出すことはできませんこれは右の気分になっている方法でのノードで(

フィールズ・ウェイ間違った(™)同期インターフェイスである:右に感じる

const fs = require("fs") 
const marked = require("marked") 

const HEADER = `<!-- Generated at ${new Date()} -->\n` 
const FOOTER = `\n<!-- Copyright Mumble-demo Inc. -->` 

fs.readdir(".", (err, files) => { 
    if (err) throw err; 
    let markdownFiles = files.filter((f) => f.endsWith(".md")) 

    let content = markdownFiles.reduce((memo, fileName) => { 
    return memo + fs.readFileSync(fileName, 'utf8') 
    }, "") 

    let contentString = [HEADER, marked(content), FOOTER].reduce((m, i) => m + i, "") 
    fs.writeFileSync("derp", contentString); 
    console.log(contentString); 

}) 

Aウェイしかし、私は(™)仕事を得ることができないということです:読み取り

  1. ビルド
  2. ストリーム彼らは変換マークダウンする
  3. パイプ
  4. オープン出力ストリームとそれに変換されたデータをリダイレクト

朗報があるストリームヘッダーコメントを上と下に配置する時が来るまで、このアプローチは機能します。それらはファイルシステムではなくコード内に存在するので、出力ストリームにストリーム変換、サン変換する別のファイルとして「追加」することはできません。ほとんどのアプローチは、ヘッダー、フッター、ストリームデータを生成します。

明らかに、pipe() -workは非同期で動作し、フッタプリントは読み取り+変換作業が完了する前に起動します。私はひどい(そして壊れた)Promiseのチェーンを最終的には動作させなかった。

もう1つの方法は、ヘッダーとフッターをストリームに変換して(奇妙なように...)、出力ストリームにも同様に流れ込ませることです(本当に変わっているようです)。

私はここにいくつかの共通のイディオムがないか、実際にはであり、実際にはという単純な作業をこのノードで単純に実行するのは難しいですか?

答えて

1

思考:私のシェルスクリプトのほとんどのために

  • 、私は単純に同期し、文字列にファイルの内容を読み取ります。このアプローチは規模が拡大しませんが、通常は必要ありません。そして、文字列を使うとすべてが簡単になります。
  • 非同期を行う場合:非同期関数とutil.promisify()を使用します。
  • 長期的にはasynchronous iteration and async generatorsもこのようなシナリオに役立ちます。
0

同期実行プログラムnsynjsを使用して、「正しい方法」を実行できます。

MD-cat.js:あなたのコードは、この実施例と同様に変換することができる

var nsynjs = require('nsynjs'); 
var nsynFs = require('../wrappers/nodeFs'); // part of nsynjs package, needs to be added manually 

var synchronousCode = function(nsynFs) { 
    var HEADER = "<!-- Generated at "+new Date()+" -->\n"; 
    var FOOTER = "\n<!-- Copyright Mumble-demo Inc. -->"; 

    var files = nsynFs.readdir(nsynjsCtx, ".").data; 

    var content=""; 
    for(var i=0; i<files.length; i++) { 
     var file = files[i]; 
     if(file.endsWith('.md')) 
      content+=nsynFs.readFile(nsynjsCtx,file,"utf8").data; 
    } 
    nsynFs.writeFile(nsynjsCtx,"derp",HEADER+content+FOOTER); 
}; 

nsynjs.run(synchronousCode, {},nsynFs, function() { 
    console.log('synchronousCode done') 
}); 

それが同期に見えるにもかかわらず、それはボンネットの下に任意の同期機能を使用していない、したがって、それは、ノードのをブロックしません。イベントループ。

0

Gulpを試してみてください。これは今日では最も慣用的な方法です。

プロミスチェーンを使用できない場合や使用したくない場合は、シェルパイプのように感じます。

#!/usr/bin/env node 
'use strict'; 

const Promise = require('bluebird'); 
const fs = Promise.promisifyAll(require('fs')); 
const path = require('path'); 
const marked = require('marked'); 

const HEADER = `<!-- Generated at ${(new Date()).toISOString()} -->`; 
const FOOTER = '<!-- Copyright Mumble-demo Inc. -->'; 

fs.readdirAsync(process.cwd()) 
    .map((fileName) => Promise.all([fileName, fs.statAsync(fileName)])) 
    .filter(([fileName, stat]) => stat.isFile() && path.extname(fileName) === '.md') 
    .call('sort', ([a], [b]) => a.localeCompare(b, 'en-US')) 
    .map(([mdFileName]) => fs.readFileAsync(mdFileName, 'utf8')) 
    .then((mdFiles) => { 
    let out = [HEADER, marked(mdFiles.join('\n')), FOOTER].join('').replace(/\n/g, ''); 
    console.log(out); 
    return fs.writeFileAsync('out.html', out); 
    }) 
    .catch((err) => { 
    console.error(err); 
    process.exit(1); 
    }); 

思考:

  • ノードで同期コードを書くことはありません、あなたは常に後悔します。
  • プロミスチェーンは、このようなタスクに最適です。
  • stat.isFile()とsort()は、bashとRubyの例では見つからない安全機能です。それらを削除すると、2行のコードを節約できます。
  • Date.prototype.toString()の使用は、出力が予測できないため、プラットフォームとロケール固有のため、ほとんどの場合、バグとみなされるべきです。
  • ノードストリームは、大量のファイルを処理するまでは過剰です。これは、通常、マークダウンの場合には当てはまりません。
  • シェルパイプもファイルシステムストリームを使用せず、すべてをメモリにロードします。効率はおおよそ同じです。
関連する問題