昨日の記事でCommonLispで複数のクラスを継承したときの設定をしたいという事でMOPで実装をこころみたのですが、どうも困難そうだったので一度Rubyで実装をこころみました
class UnionRule def initialize(modules, action_proc) @modules = modules @proc = action_proc @@UnionRule = [] end def match?(modules) res = true @modules.each do |mod| if !modules.include?(mod) res = false break end end return res end def run(klass) @proc.call(klass) end def self.define_union_rule(modules, action_proc) inst = self.new(modules, action_proc) @@UnionRule << inst end def self.run_match_rules(klass) modules = klass.included_modules @@UnionRule.each do |rule| if rule.match?(modules) rule.run(klass) end end end end module Feature def self.included(klass) UnionRule.run_match_rules(klass) end end module AnotherFeature def self.included(klass) UnionRule.run_match_rules(klass) end end UnionRule.define_union_rule([Feature, AnotherFeature], lambda{|klass| puts "#{klass} included Feature and AnotherFeature" puts "Adding instance method foo" klass.class_eval do def foo() puts "#{self}->Foo" return 10 end end }) class Container include Feature include AnotherFeature end hoge = Container.new() puts hoge.foo()
実行すると
Container included Feature and AnotherFeature Adding instance method foo #<Container:0x007f9d3a03b608>->Foo 10
と出力されて、きちんとContainerクラスにfooメソッドが追加されている事がわかります。
この場合の問題はUnionRule#run_match_rulesを明示的に各moduleのincludedで呼びださなければいけない点です。ここを解消すればかなり良いとおもうのですが...