# = Module Macros
#
# A macro construction for creating dynamic mixins.
#
# == Example
#
#   module Mixin
#     macro { |options| %{
#       def hello
#         puts 'Hello from #{options[:name]}'
#       end
#     } }
#   end
#
#   class MyClass
#     include Mixin, :name => 'tml'
#   end
#
#   m = MyClass.new
#   m.hello -> 'Hello from tml'
#
# == Author
#
#   Based on original code by George Moschovitis <gm@navel.gr>
#
class Module

  def macro( &blk )
    (@macros ||= []) << blk
  end

  def macros ; @macros ||= [] ; end

  alias_method :include_without_macros, :include

  def include(*args)
    options = args.last.is_a?(Hash) ? args.pop : {}
    for mod in args
      mod.append_dynamic_features( self, options )
    end
    include_without_macros(*args)
  end

  # Note: Is this the best name for this callback?
  def append_dynamic_features( base, options )
    macros.each do |m|
      base.class_eval m.call( options )
    end
  end

  alias_method :extend_without_macros, :extend
  
  def extend(*args)
    options = args.last.is_a?(Hash) ? args.pop : {}
    for mod in args
      mod.extend_dynamic_object( self, options )
    end
    extend_without_macros(*args)
  end

  # Note: Is this the best name for this callback?
  def extend_dynamic_object( base, options )
    macros.each do |m|
      (class << base; self ; end).class_eval m.call( options )
    end
  end

end