Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I extend a class from a gem?

I wrote a gem with some basic logic that I wanted to share. I publish it, install it, use it.

There are additional functions which I think are case-specific to my project. I want to add additional methods using the same class name because it's familiar and everything is easy for me to keep track of mentally.

How can I install a gem, then add methods to it without conflict? I have in the past overwritten methods defined in gems (notably Devise methods), but never tripped upon needing to expand the class itself.

like image 890
notaceo Avatar asked May 08 '14 22:05

notaceo


1 Answers

You just open the class and add methods. If you know the name of the class and where it is in the module hierarchy, then you just create another file that defines the same class and start adding methods. Since it's the same class name the methods will get added to the other class.

It's probably similar to what you did with Devise.

So if I have class Bar in a gem, and it's inside a module called Foo

# in the gem
module Foo
  class Bar
    def foobar
      'foobar!'
    end
  end
end

To add a method called baz to this class, without modifying the gem source code, then in your application just create a new file, declare the class inside its module again, and start adding stuff.

# in some other file in your app
module Foo
  class Bar
    def baz
      'foobar baz!'
    end
  end
end

 > f = Bar.new
 > f.foobar
=> 'foobar!'
 > f.baz
=> 'foobar baz!'

Since there can only be one copy of a class of a given name per module, then simply declaring the class again adds functionality to the existing class.

If you want to instead give some new class the baz method without changing the functionality of all Bar object instances in your app, then extend Bar instead. This will have the effect that your new class will have all Bar functionality, plus the new functionality, without modifying the functionality of Bar instances you may be using elsewhere in your app.

class NewClass < Foo::Bar
  def baz
    'foobar baz!'
  end
end

 > nc = NewClass.new
 > nc.foobar
=> 'foobar!'
 > nc.baz
=> 'foobar baz!'
like image 93
jefflunt Avatar answered Sep 21 '22 13:09

jefflunt