NimでSlackegoを作り直した
以前にPythonでSlackをエゴサーチするツールSlackegoを作りましたが、Nimでそれを作り直しました。
リポジトリはこちらです。Windowsには対応していません。
Table of Contents
経緯
先週NimでGitHubのリポジトリ検索ツールを作りました。
ただ、これは実用的なものではなく勉強のために作成したモノに過ぎません。
私が新しい言語を学ぶときにほぼ例外なく作成するモノです。
Nimを学んだ大きな理由の1つがPythonで作成モノの置き換えです。
Jumeauxは私が本気で作成中のPython製ツールですが、置き換えには少々ヘビーです。
そこで、先日作成したSlackegoを置き換えることにしました。
本記事の内容
本記事ではSlackegoをNimで実装することで得た知見を紹介します。
いずれもNimを使い始めた方向けの内容になっていると思います。
Slackegoの経緯については下記記事を参照して下さい。
また、使い方はGitHubのREADMEをご覧下さい。
利用パッケージ
Slackegoで利用したパッケージの紹介を簡単にします。
前回説明したものは説明しません。
json
jsonをobjectと相互変換する為に使っています。
間にJsonNode
という型が含まれます。
以下の変換を使用しています。
Before | 変換に使ったもの | After | 主な用途 |
---|---|---|---|
ファイルパス | parseFile | JsonNode | jsonファイルの読みこみ |
string | parseJson | JsonNode | 文字列をjsonに変換したいとき(http get) |
object | %* | JsonNode | objectをjsonとしてパースしたいとき |
JsonNode | getBool | bool | jsonのbool要素を取り出したいとき |
JsonNode | getStr | string | jsonのstring要素を取り出したいとき |
JsonNode | $ | string | jsonをワンラインの文字列に変換したいとき (http post) |
JsonNode | pretty | string | jsonを人間が読める文字列に変換したいとき |
本当はNimYAMLを使いたかったのですがビルドが通らなくて諦めました…
dotenv
環境変数を定義したファイル、.env
を読みこんで環境変数にセットする為に使います。
import os
import dotenv
if fileExists(".env"):
initDotEnv().load()
.env
が存在しない場合は無視したいので、osモジュールのfileExists
を使用しています。
uri
RFC3936に従いURIのクエリをパースするため、encodeUrl
を使用します。
import uri
# ..中略..
proc search*(word: string, after: DateTime): SearchResult =
assertToken()
let
token = getEnv("SLACK_TOKEN")
afterDate = after.format("yyyy-MM-dd")
query = encodeUrl(fmt"{word} after:{afterDate}")
times
日時を扱うためにDateTime
型を利用します。
yyyy-MM-dd
表記に変換するためformat("yyyy-MM-dd")
を使用しています。
$
はyyyy-MM-ddThh:mmzzz
にフォーマットされてしまうので使用できませんでした。
現在時刻から1日+minutes分前のDateTime型を生成するには以下のようにします。
let t: DateTime = now() - 1.days - minutes.minutes
options
みんな(多分)大好きOption
型です。
プロシージャ | 意味 |
---|---|
some(val) | valを値としてOptionで包む |
none(T) | T 型の値ナシとしてOptionで包む |
isSome | 値が存在する場合にtrue を返す |
get | 値を取得する. 存在しない場合はエラー |
Option(val)
みたいにしたらval
を判定してsome(val)
かnone(T)
のどちらかを返却してくれるともっと楽なのですが..。
今回は使用しませんでしたが、unsafeGet
, map
, filter
, flatten
, flatMap
も便利ですね。
terminal
ターミナル/コンソールでエラー表示をするために使用しています。
エラーを表示してプログラムを終了させる関数error
をutil.nim
に作りました。
import os
import terminal
proc error*(msg: string, code: int = 1) =
styledWriteLine(stderr, fgRed, "Error: ", msg, resetStyle)
quit(code)
styledWriteLine
は標準出力に赤色でメッセージを出力します。
strutils
文字列を数値型に変換するために使用しています。
実際に使用したのはparseFloat
ですがよく使うプロシージャもあわせて紹介します。
プロシージャ | 変換後の型 | 備考 |
---|---|---|
parseInt | int | - |
parseFloat | float | - |
parseBool | bool | y,yes,true,1,onがtrue. n,no,false,0,offがfalse |
parseEnum | enum | デフォルト値を指定するとinvalidの時に採用される |
他にも文字列を置換するreplace
が使われています。
その他
Slackegoの実装とは関係ありませんがハマったことです。
1..n表記でsequenceを作成する
sequtilsのtoSeq
を使用します。
toSeq(1..100).filterIt(it > 90)
Get propert
Pythonにおけるget propertyのようなものをNimで使う方法です。
Propertiesを使います。
import strutils
import times
type Message* = object
username*: string
text*: string
permalink*: string
channel*: Channel
ts: string
proc unixTime*(m: Message): int {.inline.} = m.ts.parseFloat.int
proc dateTime*(m: Message): DateTime {.inline.} = m.unixTime.fromUnix.inZone(local())
上記のMessage.ts
は外部モジュールに公開されていません。
代わりにunixTime
とdateTime
が公開されており、それぞれint
型、DateTime
型を返却します。
Method call syntaxの記法を使うことでプロシージャ呼び出しではなくプロパティのように表記が可能です。
Method call syntaxはNimが持つ非常に興味深い機能の1つであり、ルーチン呼び出しの糖衣構文です。
これまでにも何度か登場していますが説明するのはこれが初めてになります。
通常の呼び出し方 | Method call syntax |
---|---|
days(1) | 1.days |
parseFloat(“1.23”) | “1.23”.parseFloat |
int(parseFloat(“1.23”)) | “1.23”.parseFloat.int |
isZone(fromUnix(123456789), local()) | 123456789.fromUnix.isZone(local()) |
Nimにはclassが無いのでobjectにMethod call syntaxでプロシージャを定義していく流儀なのでしょうか..。
総括
Pythonで作成したSlackegoをNimに移植しました。
yamlからjsonへの変更など移植しきれない部分もありましたが、ほとんどの機能はキレイに移植することができたと思います。
Python版のSlackegoもリポジトリは残してありますので興味がありましたらご覧下さい。
構成や書き方が多少変わっていますが大筋に変更は無いはずです。