第17章 カスタムオブジェクトを作る: メタプログラミング
Ruby
Published: 2019-07-04

「Rubyによるデザインパターン」の読書メモです。

test.rb

class CompositeBase
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def self.member_of(composite_name)
    code = %Q{
      attr_accessor :parent_#{composite_name}
    }
    class_eval(code)
  end

  def self.composite_of(composite_name)
    member_of composite_name

    code = %Q{
      def sub_#{composite_name}s
        @sub_#{composite_name}s = [] unless @sub_#{composite_name}s
        @sub_#{composite_name}s
      end

      def add_sub_#{composite_name}(child)
        return if sub_#{composite_name}s.include?(child)
        sub_#{composite_name}s << child
        child.parent_#{composite_name} = self
      end

      def delete_sub_#{composite_name}(child)
        return unless sub_#{composite_name}s.include?(child)
        sub_#{composite_name}s.delete(child)
        child.parent_#{composite_name} = nil
      end
    }
    class_eval(code)
  end
end

class Tiger < CompositeBase
  member_of(:population)
  member_of(:classification)
end

class Jungle < CompositeBase
  composite_of(:population)
end

class Species < CompositeBase
  composite_of(:classification)
end

tony_tiger = Tiger.new('tony')
se_jungle = Jungle.new('southeastern jungle tigers')
se_jungle.add_sub_population(tony_tiger)

p tony_tiger.parent_population.class

species = Species.new('P. tigers')
species.add_sub_classification(tony_tiger)
p tony_tiger.parent_classification.class

出力結果

$ ruby test.rb
Jungle
Species

まとめ

メタプログラミングは、必要なコードを取得するためのもっとも簡単な方法になりうるアイディアで、キーボードでコードをすべて書くのではなく、実行時にプログラムに基づいて作り出すというやり方によるものです。