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

const_getができないけど文字列からクラスを取得したい

環境

$ crystal version
Crystal 0.15.0 [0f62400] (Fri Apr  1 16:59:50 UTC 2016)
$ crenv --version
crenv 1.0.0-16-g534d2c6

問題点

  • CLIを作ってるときにサブコマンドを1クラスにしたい
  • 入力に合わせてサブコマンドクラスのインスタンスをとってきたい
  • でもconst_getがない
    • 気がする。あったらすみません

対応策

  • 1つ1つ丁寧にcaseする
  • 1つ1つまごころをこめてhashにいれておく
  • マクロで解決する

楽に書きたい派なのでマクロでどうにかしている

確認

$ crystal src/tips/get_class_instance_by_string.cr
{"hoge" => #<Hoge:0x1061c2fd0>, "fuga" => #<Fuga:0x1061c2fc0>}
Hello, I'm hoge.
Hello, I'm fuga.

キモは当然マクロのところ。

module Register
  macro included
    Store.instance.add({{@type}}.new)
  end
end

abstract class Base
  macro inherited
    include Register
  end

  abstract def greet
end
  • RegisterがincludeされたらStoreに追加される
  • BaseがinheritされたらRegisterをincludeする

これによってinheritされたらStoreに登録するという処理を実現している。


とはいえこれだとHashの型制約の関係でクラスそのものを追加することができなかったりする。うーん。こまった。