Sometimes we'd like to monkey patch some classes/modules from external
libraries for many reasons including bug fixes until a new library
version is released or maybe we need to change the default behavior of
some class. For instance, the active_record_migrations gem will allow
migrations to be used as an independent project and it supports changing
the default location for the migrations from "db/migrate" to something
else. But "db/migrate" is hard coded in some method:
https://github.com/rails/rails/blob/master/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb#L11
That means the only option for active_record_migrations is to override
"create_migration_file" by copying the original implementation and
allowing the path to be customized:
https://github.com/rosenfeld/active_record_migrations/blob/master/lib/active_record_migrations/generators/migration.rb
A bit ugly and fragile solution, I know, but I can't think of another
option since my PR has been ignored in the last months but it doesn't
matter for what I'm requesting. This is just an example to demonstrate
that sometimes we're forced to monkey patch some classes to support some
features.
For this particular case no monkey patch was required and inheritance
was used instead but in other cases we don't have this option.
In such cases having something like Object#preextend could be helpful in
how we manage such patches by isolating them in separate modules.
Instead of reopening a class to change some class method we could add
the alternative implementation in a separate module and call #preextend
in a similar way we do with prepend. I've requested this feature to Ruby
itself and Boris came with a simple enough implementation that maybe
could be added to ActiveSupport if you agree:
https://bugs.ruby-lang.org/issues/6452
Suggested implementation by Boris Stitnicky:
class Object
def preextend m
singleton_class.prepend m
end
end
Pretty simple, right?
module LibraryImpl
def self.library_method
'original impl'
end
end
module MyPatch
def library_method
original_impl = super
"#{original_impl} => patched impl"
end
end
LibraryImpl.preextend MyPatch
assert LibraryImpl.library_method == 'original impl => patched impl'
What do you think?
--
You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Core" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to rubyonrails-core+unsubscribe@googlegroups.com.
To post to this group, send email to rubyonrails-core@googlegroups.com.
Visit this group at http://groups.google.com/group/rubyonrails-core.
For more options, visit https://groups.google.com/d/optout.