MarkdownをHTMLに変換するWebアプリをPythonで作ってみた

初Qiita... ども...

Markdown -> HTML変換する **markdown-server** というWebアプリケーションを作ってみた話をします。
ソースコード：https://github.com/ohbarye/markdown-server

# What is **markdown-server**?
MarkdownファイルをHTMLに変換して、text/html形式でレスポンスするだけのシンプルなWebアプリケーションです。デフォルトのMarkdown EngineはGithub flavored Markdownです。

## 動機
会社で手順書やTODOなどの個人的なメモはMarkdownで書いている(追記: 2015年まで在職した職場の話です)のですが、Excel大好きな会社なのでいざ他人に見せるとなると「Markdownって何？」ってところから始まったりします。
そこで、Markdownエディタ無い人に見せたり配布したりするのに良い方法がないかと思い作りました。

## How to use / とりあえず動かすには

python実行環境が必要です。開発/動作確認は2.7.9で行っています。
必須じゃないですが`git clone`できると早いです。

下記コマンドだけでサーバが起動します。

```bash
$ git clone https://github.com/ohbarye/markdown-server
$ cd markdown-server
$ pip install -r packages_requirements.txt
$ python start_server.py
```

サーバが起動したら下記アドレスにアクセスし、サンプルMarkdownファイルの変換結果を確認してみてください。

```bash
$ open http://localhost:8009/sample.md
```

## 例
こんな感じのMarkdownファイルが

~~~text:qiita.md
# PythonでMarkdownをHTML化

Github flavored Markdown で HTML化します。

## 使用したライブラリ

|No.|Name|Description|
|:-|:-|:-|
|1|markdown|Markdown -> HTML 変換ライブラリ|
|2|pygments|シンタックスハイライト用|
|3|bottle|Webアプリケーションフレームワーク|

## コードのシンタックスハイライト

\```python
import markdown as md

class MarkdownConverter(object):

    def convert(self,file_name):
        code = md.markdown(self.read_md(file_name), extensions=['gfm'])
        return self.write_html(file_name,code)

    def read_md(self,file_name):
        md_file = codecs.open(markdown_root + file_name,encoding=ms_encoding,mode='r')
        return md_file.read()

\```
~~~

こんな感じで描画されます。

![http:localhost/8009/sample.md](https://qiita-image-store.s3.amazonaws.com/0/30635/9003e20b-19d9-1b70-2eb7-4e34e595037d.png)


### 特徴 / 拡張方法
* markdown-server は`resources/markdown/[file_name]`に配置されたMarkdownファイルに対し、`http://host/[file_name]`の形式でルーティングを提供します。

* 変換されたファイルは`resources/html`ディレクトリに配置されます。生成されるHTMLファイルにCSSも組み込まれているので配布も容易です。

* ホスト名やポート番号などの環境変数は`env.py`にまとめています。適宜変更できます。

```python:env.py
ms_port        = '8009'
ms_host        = 'localhost'
```

* デフォルトの Markdown Engine は**Github flavored Markdown**です。異なるスタイルを適用したい場合は好みに応じてCSSファイルを差し替え、`env.py`を編集します。

```python:env.py
css_name       = 'github.css'
markdown_type  = 'gfm'
```

## 使用技術について

### 依存ライブラリ

主に下記ライブラリに依存しています。これらが依存するライブラリも含めた全体は[GitHubリポジトリ](https://github.com/ohbarye/markdown-server/blob/master/packages_requirements.txt)を参照してください。

|No.|Name|Description|
|:---|:---|:---|
|1|markdown|Markdown -> HTML 変換ライブラリ|
|2|pygments|シンタックスハイライト用|
|3|bottle|Webアプリケーションフレームワーク|

### markdown

Markdown変換ライブラリです。このサーバの機能は殆どこいつの働きです。
https://pypi.python.org/pypi/Markdown
Qiitaでもこの記事で使い方が紹介されています。
http://qiita.com/kimihiro_n/items/982c6fc0b3c7cf226799

基本的にこれだけで変換できます。

~~~py
import markdown as md
md.markdown("# markdown text")
~~~

マークアップの形式を変えたい場合は`extensions`を指定します。
下記はGithub Flavored Markdownの例です。

~~~py
import markdown as md
md.markdown("# markdown text", extensions=['gfm'])
~~~

ただし、上記コードだけではうまくGFMで変換されません。今回特にハマったのですが、markdownの変換の挙動は以下に述べるpygmentsのインストール有無で変わるとのことです。（マジか）

### pygments

Python製シンタックスハイライター。
http://pygments.org/
https://showa-yojyo.github.io/note/python-pygments.html

markdownの動きとpygmentsの関係は以下の記事にまとまっていました。

> シンタックスハイライトが効いていない。しかし、前回のエントリで MoinMoin に Markdown + py-gfm を組み込んだときはシンタックスハイライトがついていた。なんで？
>
これが気になっていろいろソース読んだりしたのだけど、答えは MoinMoin が pygments に依存しているから。pygments をインストールする前後で Markdown ライブラリは動きが変わる。
http://tototoshi.hatenablog.com/entry/2014/05/17/020241

ソースを見るとわかるのですが、今回はどこにも`import pygments`していません。GFMのためだけにインストールしただけです。

### bottle

Webアプリケーションフレームワークライブラリです。
http://bottlepy.org/docs/dev/index.html

PythonのWebアプリFWといえば**Django**ぐらいしか知らなかったのですが、[他にもいろいろある](http://qiita.com/shukotang/items/055058b33b553b48c164)んですね。

今回は"軽さ"を最重視して**bottle**を選びました。下記コードは公式からそのまま引っ張ってきたものですが、5行でHello worldできるという凄まじい軽量感です。

```py
from bottle import route, run, template

@route('/hello/<name>')
def index(name):
    return template('<b>Hello {{name}}</b>!', name=name)

run(host='localhost', port=8080)
```

今回は変換したHTMLをレスポンスするだけなのでテンプレート機能すら使っていません。
静的ファイルをレスポンスする為のメソッドは`static_file`です。

```py:start_server.py
return static_file(html_file_name, root=ms_root)
```

## 感想 -> Pythonって良いですね

普段はJavaメインで、スクリプト言語をほとんど書かないのでいろいろ新鮮でした。**pip**でのパッケージ管理 / **pyenv**での開発環境管理 / IDE使わない開発（今回は**Atom**)とか。

ちなみにPython歴は[**codecademy**](http://www.codecademy.com/)のPythonのコースを1週間で全部やったぐらいです。クセがなく書きやすい、簡単なスクリプトを書く上で変なハマりどころがなくて良い言語だと思いました。

社内でもMarkdownユーザが増えると嬉しいです。