1

readdirpモジュールからのディレクトリのストリームがあります。

したい:-

  • README.*各ディレクトリで正規表現 (例: ) を使用してファイルを検索します
  • で始まらないそのファイルの最初の行を読み取ります#
  • 各ディレクトリと、ディレクトリ内の README のこの見出し以外の最初の行を出力します。

ストリームとhighland.jsを使用してこれを実行しようとしています。

各ディレクトリ内のすべてのファイルのストリームを処理しようとして立ち往生しています。

h = require 'highland'

dirStream = readdirp root: root, depth: 0, entryType: 'directories'

dirStream = h(dirStream)
  .filter (entry) -> entry.stat.isDirectory()
  .map (entry) ->

    # Search all files in the directory for README.
    fileStream = readdirp root: entry.fullPath, depth: 0, entryType: 'files', fileFilter: '!.DS_Store'
    fileStream = h(fileStream).filter (entry) -> /README\..*/.test entry.name
    fileStream.each (file) ->
      readmeStream = fs.createReadStream file
      _(readmeStream)
        .split()
        .takeUntil (line) -> not line.startsWith '#' and line isnt ''
        .last(1)
        .toArray (comment) ->
          # TODO: How do I access `comment` asynchronously to include in the return value of the map?

    return {name: entry.name, comment: comment}
4

1 に答える 1

4

Highland ストリームは不変であり、古いストリームを変更するのではなく、古いストリームに依存する新しいストリームを返すfilterなどの操作を検討するのが最善です。map

また、ハイランド メソッドは怠惰です。今すぐデータが絶対に必要な場合にのみeachorを呼び出す必要があります。toArray

ストリームを非同期的にマッピングする標準的な方法はflatMap. のようなものmapですが、指定した関数はストリームを返す必要があります。取得するストリームflatMapは、返されたすべてのストリームを連結したものです。新しいストリームはすべての古いストリームに順番に依存するため、非同期プロセスの順序付けに使用できます。

あなたの例を次のように変更します(いくつかの変数名を明確にしました):

h = require 'highland'

readmeStream = h(readdirp root: root, depth: 0, entryType: 'directories')
  .filter (dir) -> dir.stat.isDirectory()
  .flatMap (dir) ->
    # Search all files in the directory for README.
    h(readdirp root: dir.fullPath, depth: 0, entryType: 'files', fileFilter: '!.DS_Store')
    .filter (file) -> /README\..*/.test file.name
    .flatMap (file) ->
      h(fs.createReadStream file.name)
        .split()
        .takeUntil (line) -> not line.startsWith '#' and line isnt ''
        .last(1)
        .map (comment) -> {name: file.name, comment}

このコードの型を見てみましょう。flatMapまず、が type (ハスケル記法) を持っていることに注意してくださいStream a → (a → Stream b) → Stream b。つまり、 type のものをいくつか含むストリームと、 type のaものを期待し、 saを含むストリームをb返す関数を取り、s を含むストリームを返しますb。コレクション型 (ストリームや配列など)flatMapは、返されたコレクションを連結して実装するのが標準です。

h(readdirp root: root, depth: 0, entryType: 'directories')

これに type があるとしましょうStream Directory。はfilter型を変更しないため、flatMapは になりますStream Directory → (Directory → Stream b) → Stream b。関数が何を返すか見てみましょう。

h(readdirp root: dir.fullPath, depth: 0, entryType: 'files', fileFilter: '!.DS_Store')

これを a と呼ぶStream Fileので、2 番目flatMapStream File → (File → Stream b) → Stream bです。

h(fs.createReadStream file.name)

これはStream String. splittakeUntilそしてlastそれを変更しないでください。では、 は何をしmapますか? mapは と非常によく似ていflatMapます: そのタイプはStream a → (a → b) → Stream bです。この場合、 aisStringbis は object type{name : String, comment : String}です。次に、そのオブジェクトのストリームを返します。これは、関数map全体が返すものです。flatMapステップアップbし、2 番目flatMapはオブジェクトであるため、最初flatMapの の関数もオブジェクトのストリームを返すため、ストリーム全体はStream {name : String, comment : String}.

Highland の遅延により、実際にはストリーミングや処理が開始されないことに注意してください。eachまたはtoArrayを使用thunkしてパイプラインを開始する必要があります。ではeach、オブジェクトでコールバックが呼び出されます。コメントで何をしたいかによっては、flatMapもっと多くするのが最善かもしれません (たとえば、コメントをファイルに書き込んでいる場合)。

まあ、エッセイを書くつもりはありませんでした。お役に立てれば。

于 2015-07-09T10:35:36.600 に答える