mrubyを触ってみた

最近ngx_mrubyを触っていて、RubyのTime#httpdateを使いたかったもののmrubyにはないということがあった。

そもそもmruby自体にも全然慣れていないという課題もあったので、このメソッドを実装することを目標にライブラリを作りながらmrubyに慣れるということをやってみた。

mrubyをビルドする

ビルド手順は非常に簡単で、mrubyのリポジトリをcloneしてmakeするだけで良い。

git clone https://github.com/mruby/mruby.git
cd mruby
make

bin/ ディレクトリ以下にいくつか実行ファイルが作られて試すことが出来て、irbのmruby版であるmirbというものも使うことが出来る。

~/c/s/g/m/mruby ❯❯❯ bin/mirb
mirb - Embeddable Interactive Ruby Shell

> p Time.now
2020-10-20 22:30:13 +0900
 => 2020-10-20 22:30:13 +0900
>

ライブラリの作り方

これで最低限mrubyを使う準備はできたので、次はライブラリを作っていく。

mrubyのライブラリはmrbgem(mgem)と呼ばれており、 mrbgem.rakemrblib/ など決まったファイル・ディレクトリ構造に従ってファイルを作成していくというものになっている。

~/c/s/g/c/mruby-time-library ❯❯❯ tree
.
├── LICENSE
├── README.md
├── mrbgem.rake
├── mrblib
│   └── mrb_time_library.rb
└── test
    └── mrb_time_library.rb

2 directories, 5 files

実装がある程度できたら動くかどうかテストをする準備をしていく。

テストの実行は少し特殊で、ライブラリのリポジトリではなくmrubyのリポジトリに以下のような build_config.rb というファイルを作成する。 conf.gemには作成しているライブラリのパスを指定する。

MRuby::Build.new do |conf|
  toolchain :gcc
  conf.gembox 'default'
  conf.gem '../mruby-time-library'
  conf.enable_test
end

そしてmrubyのリポジトリで rake test を実行することでライブラリのテストを走らせることが出来る。

そうすれば「ライブラリの実装とテストを修正し続けて rake test を実行する」というサイクルで開発をすすめることができる。

GitHub ActionsでCIする

手元環境の準備が整ったので、今度はリポジトリ上でCIできるようにする。

mrubyのライブラリはTravis CIを使っていることも多いけれど、せっかくなのでGitHub Actionsでやれるようにした。

CIでやる場合もmrubyのリポジトリでbuild_config.rbを使って指定するというのは変わらずだけど、手元のパスではなくGitHub上のリポジトリとブランチを指定するのでそこを工夫して書き換える必要がある。

ただし、ActionsのトリガーではブランチへのコミットとPRとでは作業ブランチの取得方法が微妙に異なるのでビルド前にいい感じにブランチ名を取っておくというのも必要。

      - name: get branch name
        if: github.event_name != 'pull_request'
        run: echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_ENV
      - name: get pull request branch name
        if: github.event_name == 'pull_request'
        run: echo "BRANCH_NAME=$(echo $GITHUB_HEAD_REF)" >> $GITHUB_ENV

この BRANCH_NAME を使ってbuild_config.rbを作ってrake testをしてやれば良い。

      - name: Rake test
        env:
          TEMPLATE: |
            MRuby::Build.new do |conf|
              toolchain :gcc
              enable_debug
              conf.enable_bintest
              conf.enable_test
              conf.gembox 'default'
              conf.gem :github => '${{ github.repository }}', :branch => '${BRANCH_NAME}'
            end
        run: |
          printf "${TEMPLATE}" > build_config.rb
          cd mruby
          env MRUBY_CONFIG=../build_config.rb rake test

そうして完成したワークフローは以下。

https://github.com/cohalz/mruby-time-library/blob/master/.github/workflows/test.yml

ライブラリを作った

以上で、httpdateを含むtimeライブラリの特定のフォーマットの文字列にするメソッド(インスタンスメソッド)を使えるようにするライブラリを作成できた。

github.com

~/c/s/g/m/mruby ❯❯❯ bin/mirb
mirb - Embeddable Interactive Ruby Shell

> Time.now.httpdate
 => "Tue, 20 Oct 2020 14:44:03 GMT"
>

文字列をパースするメソッドに関しては、mrubyにはデフォルトでは正規表現が使えないというのもあり実装を後回しにしているけど、既に欲しくなってきたので近いうちに作りたい。