[Crystal] 「自分が使いたいから」公開したライブラリ達

ここのところすっかりCrystalにどっぷりで，趣味に仕事にと汎用性のないCrystalのコードを書き散らかしているʕ•ᴥ•ʔAKJです。

とはいえ，普段は手元のMacBookでコードを書いて，それらを使うのは別のLinuxサーバ（複数）という環境のため，サーバ個別の機能はともかく共通部品をそれぞれのサーバへ展開するのが結構手間，という状況が出てきました。

CrystalにはRubyのGem（＋Bundler）に相当するShardという仕組みが標準で用意されていて，GitHubなどで公開されている標準添付以外のライブラリを，自分のプロジェクトへ比較的簡単に追加することができるのですが，自作のライブラリをShardとして公開するのも比較的簡単に行うことができます。実際，`crystal init lib` で作成される雛形上にコードを書いて，GitHubに公開したらそれだけで別プロジェクトからShardとして使えてしまった時はちょっとした感動モノでした。

そんなこんなで，最近では

1. 使いたい機能を単機能のライブラリとして実装
2. 「1.」をGitHubへ公開
3. 「2.」を別環境からShardとして利用

というサイクルができあがりつつあります。

私自身，仕事で使う細々したツールを書いてはいるもののプログラミング自体を飯の種にしている訳でもなく，以前は人目につく場所で自分のコードを公開することを躊躇しがちでしたが，この頃は「自分が使いたいから公開する」という流れも面白いかなと思い始めまています。

というわけで，せっかくの機会ですからこれまでにそうした流れで公開した自作ライブラリをいくつか紹介してみたいと思います。

## <i class="fa fa-github" aria-hidden="true"></i> [arcage/ip2country](https://github.com/arcage/ip2country)（IPアドレス→国名変換）

```rb
require "ip2country"

ip2c = IP2Country.new("ja")

ip2c.lookup("8.8.8.8") #=> "アメリカ合衆国"
```

IPv4アドレスからそのアドレスが割り当てられた国名を取得できます。

内部的には，各RIRが公開している `delegated-****-extended-latest` ファイルを利用してIPアドレスから ISO 3166-1 alpha-2 国名コードへ変換し，ISO 3166-1 alpha-2から国名の各言語表記への変換には <i class="fa fa-github" aria-hidden="true"></i> [umpirsky/country-list](https://github.com/umpirsky/country-list) のデータを使わせてもらってます。

`IP2Country.new` には ISO 639-1 言語コードで表記言語を指定でき（省略時は英語），標準では 日(`"ja"`)/英(`"en"`)/仏(`"fr"`)/独(`"de"`)/西(`"es"`)/葡(`"pt"`)/中(`"zh"`)/韓(`"ko"`) が使えます。

## <i class="fa fa-github" aria-hidden="true"></i> [arcage/crystal-logreader](https://github.com/arcage/crystal-logreader)（ログファイル読み込み）

```rb
require "logreader"

log = LogReader.new("/var/log/maillog")

log.each do |line|
  puts line
end
```

`LogReader.new`で指定したファイルを先頭から行単位で読み込み，ファイルの終わりまできたら1秒待って新しい行が追加されていないかをチェックする，という動作をします。

また，ファイルの内容を読みきってしまい，その後しばらく（デフォルトで5秒ほど）更新がない場合には，当初指定されたファイル名に対応するinode番号を調べて現在開いているファイルのinode番号と比較します。もし2つのinode番号が異なっていたら，現行ファイルを閉じて新しいファイルを開き直し，読み込みを継続します。

要するに，UNIX系（主にLinux）のシステムログを（ほぼ）リアルタイムに監視し，ログローテション後も読み込み継続するためのライブラリです。

## <i class="fa fa-github" aria-hidden="true"></i> [arcage/crystal-email](https://github.com/arcage/crystal-email)（メール送信）

```rb
require "email"

smtp_server = "192.168.1.25"

Email.send(smtp_server) do
  from    "taro@denchu.org",   "山田 太郎"
  to      "hanako@denchu.org", "山田 花子"
  subject "先日の件"
  message <<EOM
太郎です。

添付しましたのでご確認ください。
EOM
  attach  "/path/to/attached/file.doc"
end
```

RubyのTMailみたいにメール送信がしたくて作りました。内部的には自分が使いたい最低限のSMTP（ESMTP）コマンドを **TCPSocket** を使用して直接叩いています。

###【特徴】

- 宛先（To，Cc，Bcc）ヘッダへの複数アドレス指定
- 複数ファイルの添付
- サブジェクトやメッセージボディ，FromやToヘッダのメールボックス名などでの日本語（というかUTF-8）利用
- STARTTLS コマンドでSMTPセッションの暗号化
- STARTTLS 後の AUTH PLAIN コマンドによるSMTP認証

## <i class="fa fa-github" aria-hidden="true"></i> [arcage/crystal-patlite](https://github.com/arcage/crystal-patlite)（パトライト制御）

```rb
require "patlite"

patlite_host = "192.168.1.110"
patlite_port = 10000

patlite = Patlite::PHN.new(patlite_host, patlite_port)

# 赤点灯，黄点滅，警報短音に設定
patlite.set do
  red_on
  yellow_flash
  beep_short
end
```

[PATLITE](http://www.patlite.co.jp/)社製のネットワーク対応パトライトをPHNコマンドで制御します。

指定したパトライトの信号灯点灯状況や警報音の状況を取得したり，ネットワーク越しに信号灯を点灯したり警報音を鳴らしたりできます。

ただし，PHNコマンドの仕様上，設定可能なのは赤（red）/黄（yellow）/緑（green）3色のLEDライトそれぞれの点灯（on）/点滅（flash）/消灯（off）の3パターンと，警報音（beep）の短音（short）/長音（long）/消音（off）の3パターン，この組み合わせのみで，4色以上のLEDライトを搭載していても，赤黄緑以外のライトは制御できません。

いま手元にあるパトライトより新しいモデルが対応しているPSNコマンドだと，4色以上のLEDライトの制御に加えて，指定できる点滅パターンや警報音パターンも増えるっぽいので，もし今後新しいパトライトが手元に来るようならそっちも実装してみたい。