Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Basic metaprogramming: extending an existing class using a module?

I'd like part of my module to extend the String class.

This doesn't work

module MyModule
  class String
    def exclaim
      self << "!!!!!"
    end
  end
end

include MyModule

string = "this is a string"
string.exclaim

#=> NoMethodError 

But this does

module MyModule
  def exclaim
    self << "!!!!!"
  end
end

class String
  include MyModule
end

string = "this is a string"
string.exclaim

#=> "this is a string!!!!!"

I don't want all the other functionality of MyModule to be marooned in String. Including it again at the highest level seems ugly. Surely there is a neater way of doing this?

like image 371
djb Avatar asked Aug 30 '11 11:08

djb


2 Answers

The exclaim method in your first example is being defined inside a class called MyModule::String, which has nothing to do with the standard String class.

Inside your module, you can open the standard String class (in the global namespace) like this:

module MyModule
  class ::String
    # ‘Multiple exclamation marks,’ he went on, shaking his head,
    # ‘are a sure sign of a diseased mind.’ — Terry Pratchett, “Eric”
    def exclaim
      self << "!!!!"
    end
  end
end
like image 137
Lars Haugseth Avatar answered Nov 03 '22 16:11

Lars Haugseth


I'm not sure I've understood your question but why don't open string in a file, say exclaim.rb, and then require it when you need it:

exclaim.rb

  class String
    def exclaim
      self << "!!!!!"
    end
  end

and then

require "exclaim"

"hello".exclaim

But maybe I'm missing something?

like image 30
lucapette Avatar answered Nov 03 '22 18:11

lucapette