Mixin for Mixins

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Mixin for Mixins

trans
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.

Reply | Threaded
Open this post in threaded view
|

Re: Mixin for Mixins

Josh Cheek
On Sun, Dec 25, 2011 at 10:48 PM, Intransition <[hidden email]> 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
Reply | Threaded
Open this post in threaded view
|

Re: Mixin for Mixins

trans


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

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,

Reply | Threaded
Open this post in threaded view
|

Re: Mixin for Mixins

trans
Oops, typo...

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