今まで、いろんなところで仕事をしてきたわけですけど、タイムカードを押すというのは前職が初めてでした。外部のタイムカードサービスのUIが意味不明だし、人事とか管理職はタイムカードデータを眺めるのに勤務時間をわりと使っているようで、いろいろ無駄なシステムでした。労使共に時間無駄すぎるだろう。なので個人的に自動化していた:

  • xidleでアイドルタイムを調べる
  • 平日朝、アイドルタイムが突然減ったら出勤とみなす
  • 平日夕、アイドルタイムが0から5分に増えたら退勤とみなす
  • Seleniumを使ってタイムカードサイトにログイン、打刻

この通り、勤務時間のチートはしていません。

ロジックはOCamlで書いて、seleniumを使うところだけPythonのスクリプトを使ってました。

この度、個人的にheadless Chromeでwebアクセスしたくなったので、またseleniumを使うかと思ったのですが、Pythonよくわかってないし、OCamlからseleniumを呼び出そうと思って使ったのが、OCamlからPythonを呼び出せるライブラリ Lymp https://github.com/dbousque/lymp です。

昔自分でも ( ゚∀゚)o彡°O’PyCaml http://bitbucket.org/camlspotter/opycaml というライブラリを書いたことがあるんですが、メンテしてないし、何か新しいものがないかなと思って検索に引っかかりました。

Lympは ( ゚∀゚)o彡°O’PyCaml のようにPython C APIは使わない100%OCamlのライブラリで、PythonインタプリタとBSONでお話するようになっています。なので、メモリ管理周りのクラッシュはなさそうなのが良いと思いました。

LympのAPIはPython C APIとだいたい同じなのでC APIとか ( ゚∀゚)o彡°O’PyCaml を書いた人には使うのは簡単です。Python部分は型が潰れてしまっていて残念な感じですが、Pythonってそもそも型ついてないから残念ですよね。だから没問題です。

Selenium使ってChromeにWebページを開かせるコードも簡単に書けます:

let py = Lymp.init "."

(* from selenium import webdriver *)
let webdriver = Lymp.get_module py "selenium.webdriver"

(* driver = webdriver.Chrome('/usr/local/Caskroom/chromedriver/2.41/chromedriver') *)
let driver = Lymp.get_ref webdriver "Chrome"
    [ Pystr "/usr/local/Caskroom/chromedriver/2.41/chromedriver" ]

(* driver.get('https://camlspotter.gitlab.io') *)
let () = Lymp.call driver "get" [Pystr "http://camlspotter.gitlab.io"]

let () = Lymp.close py

というわけでLympは便利そう。トラブってもOCamlとPythonがBSONでお話ししているので、Python C API使っているものよりは、OCaml側かPython側でprintfデバッグすることですぐ問題がわかるはずです。

で、早速 named argument 周りの扱いでバグを見つけました。このパッチがないとNamed argumentでreferenceを使った時にPython側でdereferenceしてくれません: https://github.com/dbousque/lymp/pull/15 (これは最新バージョンには取り入れられています)

本気出せばOCamlのクラスタイプ宣言からPythonのオブジェクトのメソッド呼び出しコード導出とか簡単にできますね。もしそういう必要があればいつか作ります。