@drawohara
published on: 2014-07-24

=begin
it's quite common, in ruby, for modules to provide functionality via mixins.
for example:
=end
  module Mixin
    def foo
      42
    end
  end
  class C
    include Mixin
  end
  p C.new.foo #=> 42
=begin
althouge handy, the guts of the mixin, especially modules, can easily leak
into the target unintentially.
here the 'Util' module gets zippered in-between the Mixin and C:
=end
  reset!
  module Mixin
    module Util
      def Util.foo
        42
      end
    end
  end
  class C
    include Mixin
    p Util.foo #=> 42
    module Util
      def Util.bar
        42.0
      end
    end
    p Util.bar #=> 42.0
  end
=begin
this creates a challenge for the author's of mixins: how to keep code
organized *and* provide a module that is safe to mixin to any target.
two main approaches exist:
1) carve out the mixin seperately from the top-level namespace
=end
  reset!
  module M
    module Mixin
      def foo
        42
      end
    end
    module Util
    end
  end
  class C
    include M::Mixin
  end
  p C.new.foo #=> 42
  p C.const_defined?(:Util) #=> false
=begin
or
2) leverage const_missing to allow simple const aliases into a private namespace
=end
  reset!
  module M
    module Namespace
      module Util
        def foo
          42
        end
      end
    end
    def Mixin.const_missing(const)
      begin
        Namespace.const_get(const)
      rescue Object
        raise
      end
    end
    def foo
      Util.foo
    end
  end
  class C
    include M::Mixin
  end
  p C.new.foo #=> 42
  p C.const_defined?(:Util) #=> false
=begin
so, there you have it: please think carefully about dropping common names
inside your mixins as they absolute vommit all their internals into the
mixee.
=end
BEGIN {
  def reset!
    self.class.send :remove_const, :Mixin rescue false
    self.class.send :remove_const, :C rescue false
  end
}