内容
Rubyのメソッドには記号を利用できたり、括弧を省略することで
あたかも言語に組み込まれた構文のように記述できます。
このようなテクニックをミミックメソッドと呼びます。
ミミック=擬態。ドラクエ世代には分かりやすいですね。
Useクラスを継承しているようにみえるケース
実際はUseメソッドが返却するクラスを継承している
# encoding: UTF-8 require 'pp' class Hoge def say puts "hoge" end end class Hage def say puts "hage" end end class Hige def say puts "hige" end end def Use(class_name) puts class_name return eval("#{class_name}") end class ChildHoge < Use 'Hoge' end ChildHoge.new.say class ChildHage < Use 'Hage' end ChildHage.new.say class ChildHige < Use 'Hige' end ChildHige.new.say
出力
Hoge hoge Hage hage Hige hige
構文を曲げてサブルーチンを実装可能にしてみる
# encoding: UTF-8 require './my_kernel' Sub hoge(param) {|p| puts "hoge_" + p } hoge("test")
出力
きちんと動作もします。
hoge_test
VBのサブルーチンライクな宣言をしています。
実際のところはSub,hoge,paramはすべてメソッドとして認識されています。
method_missingでそれらをKernelのフィールドに保存しておき、Subが見つかった時点で
保存しておいたフィールドを元にKernelのインスタンスメソッドを動的に定義しています。
以下、動的定義部分のコード
# encoding: UTF-8 module Kernel attr_accessor :sub_factors, :sub_block def method_missing(method_name, *args, &block) puts "aaa:#{method_name.to_s}" puts "bbb:#{args.to_s}" if method_name == :Sub sub_code =<<EOS def #{@sub_factors[1].to_s}(#{@sub_factors[0].to_s}) @sub_block.call #{@sub_factors[0].to_s} end EOS eval(sub_code, binding) else @sub_factors ||= [] @sub_factors << method_name @sub_block = block end end end
※あくまで、こんなことが出来る、という話で実用レベルのコードではありません