読者です 読者をやめる 読者になる 読者になる

歩いたら休め

If the implementation is easy to explain, it may be a good idea.

【R】Rのライブラリ作成時に困ったこと×2

できるだけ簡単にRの定型作業が終わるよう、自作のライブラリを作って、簡単に引き継ぎ作業ができる状態を作りました。

(職場の優秀な先輩が、Rのコード資産を自分だけにしか使えず、定型作業をほかの人に引き継げずに闇を抱えてしまった姿を見てしまっているので…)

具体的には、

library(mylibrary)
yesterday <- Sys.Date() -1
mylibrary::getData(target_date = yesterday, date_term = 3)

という感じで、「昨日から3日分遡ったところまでのデータを取得する」という機能を作り、「期間や日付の引数を変えるだけで作業が終わりますよ」と伝える作戦です。

以前遊びで作ったのでスムーズに終わると思いきや、意外に穴にハマっていた時間が長かったので、自分がハマったポイントをメモしておきます。

日本語(マルチバイト文字列)の読み込みで失敗する

このように、日本語文字のあるコードは、ライブラリからコードを読み取る際にはでは失敗します。(source関数での読み取り等でも同様です)

aisatsu <- "ようこそ"

代わりに、エスケープした形でコードを書いてあげなければなりません。めんどくさいですね。

aisatsu <- "\u3088\u3046\u3053\u305d"

いちいちUTF-8をエスケープした形を探すのは面倒ですが、stringiライブラリを使えば簡単に見つけることができます。

library(stringi)
stringi::stri_escape_unicode("ようこそ")
#> [1] "\\u3088\\u3046\\u3053\\u305d"

notchained.hatenablog.com

ファイルパスの指定方法

今回書いたコードは、裏でデータベースにクエリを投げているので、sqlを以下のパスに置き、scan関数で文字列として読み込む実装にしました。

inst/sql/query.sql

こういうコードを書きました。

query_path <- 'inst/sql/query.sql'
sql <- scanQuery(query_path) # scanQuery関数は自作

しかし、このコードは2点間違いがあります。

まず、Rのライブラリの仕様として、instディレクトリ以下にあるものは、ライブラリの作成時にrootディレクトリに移動します。(というより、たくさんのファイルがrootディレクトリにあるとライブラリ作成時に不便なので、instディレクトリにわけられるようになっているらしい)

また、ライブラリ使用時のディレクトリから相対パス'inst/sql/query.sql'を探しに行ってしまいます。そのため、絶対パスで指定する必要があります。そのためにsystem.file関数を利用します。

# 自身のライブラリ名を指定してあげる
system.file(package = "mylibrary", "sql/query.sql")
# => [1] "C:/Users/takeshi/Documents/R/R-3.3.0/library/mylibrary/sql/query.sql"

まとめ

とりあえずライブラリを作れるようになりました。あとはtestthatを使えるようになって、テストコードも含めて運用できるようになりたいです。

Rはツールとしては便利だけど、マルチバイト文字列のところなど、プログラミング言語としてはもうちょっとしっかりしてほしいと思うことがよくあります…。

Rパッケージ開発入門 ―テスト、文書化、コード共有の手法を学ぶ

Rパッケージ開発入門 ―テスト、文書化、コード共有の手法を学ぶ