Let's write β

プログラミング中にできたことか、思ったこととか

複数のモジュールを同時includeした場合の処理を設定する

昨日の記事で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で呼びださなければいけない点です。ここを解消すればかなり良いとおもうのですが...