Why do people use `Module.send(:prepend, …)`?
Asked Answered
C

1

6

I'm learning how to use Module.prepend instead of alias_method_chain in my Ruby code, and I've noticed that some people use send to call it (example):

ActionView::TemplateRenderer.send(:prepend,
    ActionViewTemplateRendererWithCurrentTemplate)

While others call it directly (example):

ActionView::TemplateRenderer.prepend(ActionViewTemplateRendererWithCurrentTemplate)

And, although I haven't seen anyone use this style, I suspect from the documentation that you could even write this in the module you're prepending from:

module ActionViewTemplateRendererWithCurrentTemplate
    # Methods you're overriding go here

    prepend_features ActionView::TemplateRenderer
end

Is there some difference between these three styles? Is there a reason to favor one over the others?

Carbonation answered 3/1, 2017 at 8:47 Comment(2)
Probably people still write it this way because of 'old habits', since #include and #prepend used to be private methods before Ruby 2.1.Signalment
prepend_features is a hook method that is called by prepend and generally not intended nor designed to be called directly.Tactic
A
12

Module#prepend was added to Ruby version 2.0.0.

It was originally added as a private method, with the intended use case being in the following format:

module Foo
  # ...
end

class Bar
  prepend Foo

  # ... The rest of the class definition ...
end

However, it soon became apparent that in many cases people wanted to prepend a module to a class without defining any other aspects of the class (in that section of code). Hence, the following pattern became common:

Bar.send(:prepend, Foo)

In Ruby version 2.1.0, this issue was addressed by making Module#prepend a public method - so you can now simply write this as:

Bar.prepend(Foo)

However, note that if you are writing a library that is required to support Ruby 2.0.0 (even though official support ended on 24th Feb 2016), then you must unfortunately stick to the old .send(:prepend, ...) approach.

Module#include (which has been in the Ruby language since its inception) was also a private method in version <= 2.0.0, and was made public in 2.1.0.

Achlorhydria answered 3/1, 2017 at 9:7 Comment(1)
Thanks for the history! I never realized include and prepend were made public, and I've been legacy-coding them with .send for too long.Nestor

© 2022 - 2024 — McMap. All rights reserved.