[html-pipeline]テキストデータを加工して、HTMLで安全に出力する方法

## 概要
先日、html-pipelineのgemを使う機会があったので、備忘録も兼ねて、
本gemの使い方について、書いていきたいと思います。(´ε｀)
使い方は簡単なんですが、日本語の解説ページがあんまり無かったので、掲載(^o^)／

Webフォーム等から入力されたテキストデータをサニタイズ(タグのエスケープや削除とか)し、
ちょっと加工して、HTMLとして表示させたい場合があると思います。
-　CMS的なサイトでフォームでコンテンツを入力させて、Webページとして表示させたい
-　http://〜〜のリンクがあったらハイパーリンクで表示したい
-　タグ等は文字として表示させたい
-　Youtubeとかのリンクがあったら、埋め込みのような形で表示したい

こんなことをやってくれるのがgem html-pipeline です。
`https://github.com/jch/html-pipeline`

## 環境
Rails 5.0.1
Ruby 2.3.1

## html-pipelineで何ができるのさ？
冒頭にも書きましたが、html-pipelineを使うことで、
テキストデータを加工して、html出力することができます。

html-pipelineには「フィルター」という概念があり、例えば、
「http://〜をリンクとして表示したいな」と思ったら、そのフィルターを設定することで、
テキストデータの中から文字列を見つけて、aタグで囲んでくれたりします。

フィルターの種類はgithubのページに記載されていますが、例として以下のようなフィルターがあります。
リンク作ったり、マークダウンをhtmlにしたり、youtubeの埋め込みタグ作ったりです。
例えば、httpはリンクにして、youtubeへのリンクは埋め込んで表示させたいなら、フィルターを２つを指定します。

```
（gitbubのページから一部抜粋） 
MentionFilter - replace @user mentions with links
AutolinkFilter - auto_linking urls in HTML
EmojiFilter - everyone loves emoji!
MarkdownFilter - convert markdown to html
PlainTextInputFilter - html escape text and wrap the result in a div
html-pipeline-nico_link - An HTML::Pipeline filter for niconico description links
html-pipeline-youtube - An HTML::Pipeline filter for YouTube links
```

## 使い方
**1.ベースとなるhtml-pipelineのインストール**
githubのinstallationに書いてあります。
Genfileに
`gem 'html-pipeline'`
を入れて、
`$ bundle install`


**2.フィルターの選定**
どのフィルターを使うか選びましょう。
Githubの「Filters」または「3rd Party Extensions」からチョイスします。


**3.依存関係のあるgemのインストール**
*まず、Filtersの中からフィルターを選択したあなた！*
あなたが選択したフィルターを動作させるためには別途gemが必要かもしれません。

依存関係のあるgemは、「Dependencies」の章に書いてあります。
例えば、httpをリンクして表示したいなら、「AutolinkFilter」が必要で、
これを動作させるためには「rinku」というgemが別途必要です。
こんな感じで書いてありますね。
`AutolinkFilter - rinku`

また、依存関係のgemにはバージョンが指定されているものがあります！
以下のリンク先をチェックして、gemをインストールしましょう。
`Note: See Gemfile :test block for version requirements.`

*そして、3rd Party Extensionsからフィルターを選択したあなた！*
別途gemを入れる必要があります。リンク先に飛んでgemを入れましょう！
例えば、「html-pipeline-youtube」を選択した場合、
`html-pipeline-youtube`
というgemをインストールします。


**4.では使いましょう**
使い方は簡単です。
 １）html-pipelineのインスタンス生成
 ２）生成したインスタンスの引数にテキストを与える
　　３）テキストが出力されるのでhtml_safeとかしてviewで表示
以上！ｗ

少し詳しく書いていきます。
*1.html-pipelineのインスタンス生成*
HTML:Pipeline.newでインスタンスを生成しますが、その際に引数を2つ(a,b)与えます。
　　a：配列で適用するフィルターを記載
　　b：フィルターが必要なオプションをハッシュで指定

実際のコードはこんな感じ↓です。以下の例では２つのフィルターを定義しています。
bの引数は、AutolinkFilterのオプションです。
必要/設定可能なオプションは、「/lib/html/pipeline/」以下の[フィルター名.rb]に書かれています。

```
HtmlSanitizationPipeline = 
  HTML::Pipeline.new [
    HTML::Pipeline::YoutubeFilter,　　# aの適用フィルター
    HTML::Pipeline::AutolinkFilter
  ], {autolink: true, link_attr: 'target="_blank"'} # bのフィルターオプション
```

*2.生成したインスタンスの引数にテキストを与える*
以下のような感じでcallメソッドの引数としてテキストデータを与えます。
返り値のハッシュのoutputに結果が入りますので、それを出力すればOKです。
これらをヘルパーメソッドにして、viewから呼んであげれば色々使いまわせます。

```
result = HtmlSanitizationPipeline.call(テキストデータ)
result[:output].html_safe
```

## html-pipeline + 別メソッドで要件にあったものを

基本的な使い方は以上ですが、上記の例ではタグなどに囲まれた文字は、
文字として出力されず削除されてしまうと思います。
文字として出力するための（文字エスケープ）フィルターとしてhtml-pipelineには、
`PlainTextInputFilter - html escape text and wrap the result in a div`
が用意されていますが、今回これは使いませんでした。（微妙に出力結果が要件に合わず）

先日html-pipelineを使った際には、pipelineに渡す前にrailsのhtml_escapeメソッドで
タグ等をエスケープ処理した上で、pipelineにデータを渡す方法を選択しました。

```
result = HtmlSanitizationPipeline.call(html_escape(テキストデータ))
result[:output].html_safe
```

要件によってはresultに対してさらに加工が必要なこともありますが、その場合は、
split_paragraphsで行単位で処理するとか、railsのメソッドと組合せるとお手軽にできるかもです。

ではでは〜〜＼(^o^)／