Ruby ではメソッド内で定数を定義することは通常できない。
例:
def k K = 1 end # /Users/aereal/Dropbox/sketches/const.rb:2: dynamic constant assignment # K = 1 # ^
ちなみに dynamic constant assignment
は「メソッドの定義内で定数を定義できない」という意味でしかなく、以下の定義はすべて有効であり警告も出力されない ( Ruby 2.2.4 )。
if rand(10).floor.even? N = 0 else N = 1 end M = $M if rand(10).floor.even? K = 1 end # 定数 `K` を参照すると 1/2 の確率で NameError 例外が発生する。
定数なので静的な文脈で定義すればよいのだけれども、既に定義済みの定数を動的に書き換えたいことがある。たとえば OpenSSL::SSL::VERIFY_PEER
など……。
さてメソッド内で定数を定義する方法はいくつか考えられる。
define_method
を使う
self.class.send(:define_method, :k) { K = 1 }
Kernel#.require
で定数を定義する別ファイルを読み込む
const.rb:
K = 1
k.rb:
def k require 'const' K end
おわり
メタプログラミングすればだいたいなんとかなる Ruby のことなので、だいたいメタプログラミングなどでなんとかなった。
堅牢さが欲しいと思いつつも、いざとなればメタプログラミングでこじあけられるということは、ブラックボックスである部分が少なくなるということであり、いろいろなライブラリを組み合わせてアプリケーションを書くときにはけっこう助かることも多いですね。