From: Josh Cheek Date: 2011-12-26T16:33:02+09:00 Subject: Re: Mixin for Mixins --f46d043d66d9a614f304b4f9c6f7 Content-Type: text/plain; charset=ISO-8859-1 On Sun, Dec 25, 2011 at 10:48 PM, Intransition 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 ). 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 --f46d043d66d9a614f304b4f9c6f7--