Override a Method Inside a Gem from Another Gem

Override a method inside a gem from another gem

It's impossible to override an entire Ruby class in that manner, but I think it is possible to prevent the original class from loading...if it's using autoload. I was curious, so I checked out https://github.com/sstephenson/sprockets/blob/master/lib/sprockets.rb, and yes, Sprockets is using autoload.

autoload :Base, "sprockets/base"

Importantly, that doesn't load the code. It simply tells Ruby that if/when an undefined constant called "Sprockets::Base" is ever encountered, to load it from the specified file. Your patch defines Sprockets::Base before it is ever called anywhere, thus preventing the original file from loading.

When you moved your patch to the Rakefile, something in Rails had already referenced Sprockets::Base, loading the original code. Your patch then applied cleanly on top.

I've never actually used autoload, so I'm not sure how cases like this are supposed to be handled. I'm betting though, that this would work:

Sprockets::Base
class Sprockets::Base
def digest
...

By referencing the class first, you should force Ruby to load the original class. Then you can safely go about the business of overriding one of its methods.

Overriding a module method from a gem in Rails

What you are doing will work, but your code needs to look like this:

module WillPaginate
module Finder
module ClassMethods
def paginate_by_sql(sql, options)
# your code here
end
end
end
end

In other words, go into finder.rb, delete everything except the module headers and the method you want to override, then save to a file in lib and include in environment.rb. Voila, instant monkey patch!

How to override a method of a class from a gem in Rails?

Create a .rb file in config/initializers directory with the following code:

Youtube::Display.class_eval do
def find(id, options = {})
# Code here
end
end

Override initialize method of a gem?

Instead of overwriting the method, you can move your custom implementation into a separate module and prepend it to the Queue class:

# config/initializers/queue_extension.rb

module QueueExtension
def initialize(name, redis_or_options = {})
# Custom logic

super # <- as needed, invokes the original Redis::Unique::Queue#initialize
end
end

Redis::Unique::Queue.prepend(QueueExtension)

Using prepend puts the code "in front" of the existing code.

If Redis::Unique::Queue is not available at that point, you might have to require it.

How can one override a class method inside a module inside a gem?

Try

OmniAuth::Configuration.class_eval do
def add_camelization(name, camelized)
...
end
end

Overwriting a dependency gem class which inherits from a parent class

No, you can't actually change the parent class without basically rewriting the subclass. If you only have two methods in each class that's probably fine, but Ruby classes use single-inheritance, so you can't re-assign a subclass to a different superclass without redefining it. You can, however, do any of the following:

  1. Re-open the class and redefine its methods.
  2. Prepend a module to redefine the behavior of existing methods.
  3. Add or modify methods for the singleton class, or on a singleton instance of that class.
  4. If your class is inheriting from Delegator, you can change the delegate class with #__setobj__.

Since you haven't really defined a use case, it's hard to tell which method would be best for you. Once the parent class is defined, though, it stays defined, so you'll have to do whatever you're trying to do another way.



Related Topics



Leave a reply



Submit