Mixin for Mixins

Going through some old code snippets and came across this clever bit. Back
then I was planning to use this for Facets, before I finally determined
that using mixins wasn't actually the best approach for a core extensions
library.

  module Extension
    def self.included(base)
      name = base.name.split('::').last
      core = eval("::#{name}")
      core.send(:include, base)
    end
  end

Example:

    module Facets
      module String
        include Extension

        def drippy
          puts "Drippy #{self}"
        end
      end
    end

    "Hello".drippy

Just thought I'd share.

Why do you invoke the included method by including the Extension into
Facets::String? I see this all over the place (esp in Rails) but don't get
why. It's just an ultra fancy way to invoke a method, but it pollutes
String's ancestry and makes it nonobvious what's happening. This code
doesn't also extend in the included hook, but I see that a lot, too (e.g.
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/model.rb#L17
).

How about something like this as an alternative:

# With included hook, pollutes string
module CoreExtension
  def self.included(base)
    name = base.name.split('::').last
    core = Object.const_get name
    core.send(:include, base)
  end
end

module Facets
  module String
    include CoreExtension

    def drippy
      "Drippy #{self}"
    end
  end
end

"Hello".drippy # => "Drippy Hello"
String.ancestors.include? CoreExtension # => true

# Same functionality, but more clear and doesn't add CoreExtension to
ancestry
module CoreExtension
  def self.<<(base)
    name = base.name.split('::').last
    core = Object.const_get name
    core.send(:include, base)
  end
end

module Facets
  module String
    CoreExtension << self

    def drippy
      "Drippy #{self}"
    end
  end
end

"Hello".drippy # => "Drippy Hello"
String.ancestors.include? CoreExtension # => false

···

On Sun, Dec 25, 2011 at 10:48 PM, Intransition <transfire@gmail.com> wrote:

Going through some old code snippets and came across this clever bit. Back
then I was planning to use this for Facets, before I finally determined
that using mixins wasn't actually the best approach for a core extensions
library.

  module Extension
    def self.included(base)
      name = base.name.split('::').last
      core = eval("::#{name}")
      core.send(:include, base)
    end
  end

Example:

    module Facets
      module String
        include Extension

        def drippy
          puts "Drippy #{self}"
        end
      end
    end

    "Hello".drippy

Just thought I'd share.

Why do you invoke the included method by including the Extension into
Facets::String? I see this all over the place (esp in Rails) but don't get
why. It's just an ultra fancy way to invoke a method, but it pollutes
String's ancestry and makes it nonobvious what's happening. This code
doesn't also extend in the included hook, but I see that a lot, too (e.g.

https://github.com/rails/rails/blob/master/activerecord/lib/active_record/model.rb#L17
).

Fair point. You might want to pollute String with the CoreExtension mixin.
OTOH, it makes it easy to identify that it was extended as such, e.g.

  String.ancestors
  => [String, CoreExtension, Comparable, Kernel, BasicObject]

And since there are no instance methods in it I don't think it hurts
anything.

How about something like this as an alternative:

Actually, if we used #append_features instead of #include, we could prevent
the inclusion, but still use `include` to apply the extended features,

···

On Monday, December 26, 2011 2:33:02 AM UTC-5, Josh Cheek wrote:

Oops, typo...

"Fair point. You might *NOT* want to..."