d20pfsrdDiscordボットスクレーパーの抽象化と展開

Aug 16 2020

私は、不和チャットでd20pfsrdルールブックへのリンクをリッスンし、それらが偉業か魔法かをチェックし、ページをスクレイプしてフォーマットし、フォーマットされたテキストとしてチャットに戻す不和ボットを作成しました。私がチェックしているページは十分に定型的であるため、使用しているcheerioセレクターはおそらくかなり脆弱ですが、ほとんどの場合は機能しているようです。ただし、テキストフォーマッタは醜い獣であり(ロジックはおそらく一意ですが)、axios呼び出しでもクリーンアップを使用できます。

私の問題は次のとおりです。適切に一般化すれば、コードの40%がリファクタリングされて存在しなくなる可能性があると思いました。私の解決策は、おそらくスプレッド演算子の乱用として説明できる何かをすることでした。

async function getPage(msg, url){
  let message = "placeholder";
  await axios.get(url).then( (response) => {
      message = responder(...selectResponder(url), response);
    } 
    ).catch((error) => {
      console.error(error.message);
    });
  sendMessage(message, msg);
  
}

1週間後、関数が逆方向に読み取られるように関数を記述したことに気づきましたか?美学はさておき、これはそれがうまくいく方法です:

function selectResponder(siteUrl){
  if (siteUrl.startsWith("https://www.d20pfsrd.com/feats/")){
      return feats.featsConfig;
    } else if (siteUrl.startsWith("https://www.d20pfsrd.com/magic/")){
      return magic.magicConfig;
  }
}

function responder(parser, formatter, messageFormatter, response){
    const replyData = parser(response.data);
    const formattedData = formatter(replyData);
    return messageFormatter(formattedData);
}

アイデアは、私が分離できる限り多くのユニークなロジックがmagic.jsとfeats.jsに可能な限り存在するということです。このセクションをクリーンアップするにはどうすればよいですか?githubリポジトリはここにあり、プロジェクト全体についてフィードバックをお待ちしています。ここで大きなifブロックを作成し、axios呼び出しを複製するのは奇妙だと思ったので、そのほとんどを実行しました。

client.on('message', msg => {
  

  if(validateUrl(msg.content)){
    const siteUrl = encodeURI(msg.content);
    getPage(msg, siteUrl);
  }
  

});

また、ラズベリーパイにどのように展開したかについてこの要点を書きました。それはうまくいくので、それを改善する方法についての提案をいただければ幸いです

大まかに言うと、このプログラムは次のとおりです。

  1. メッセージを聞く
  2. メッセージを検証します
  3. メッセージURLでページコンテンツを取得します
  4. ページコンテンツを解析します
  5. ページコンテンツを再フォーマットします
  6. ページのコンテンツをメッセージに変換します
  7. メッセージを送信します

回答

1 TedBrownlow Aug 16 2020 at 10:57

これが私がそれをする方法です。パーサーが消費するページに関するロジックを、そのパーサーのコードに移動します。また、ヘルパーファイルをオブジェクトに整理すると、渡す変数の数の複雑さを軽減できますが、それは個人的な好みの問題です。

class SpecificPageParser {
    match(url) {
        return (
           url.startswith('https://www.d20pfsrd.com/magic/') &&
           !url.endsWith('/magic/')
        );
    }
    format(response) {
        // do your parsing stuff
        const formatted = {...response,'extra':'info'};
        return formatted;
    }
}

const responders = [new SpecificPageParser(),new SomeOtherParser()];

async function getPage(msg, url){
    try {
        const responder = responders.find(responder=>responder.match(url));
        if (!responder) return;
        const response = await axios.get(url);
        const message = responder.format(response);
        sendMessage(message, msg);
    }
    catch(error) {
        console.error(error);
    }
  }
```