Question

I'm working on a ruby project in which we are planning to do some operations with ruby strings. Some operations are simple (like counting the number of words) and others more complex (like checking if a given string is in the correct language).

A possible way to implement this is by patching the String class with extra methods, without modifying any existing methods, and adding behaviors like "some string".word_count and "some string".cjk?.

Another approach, based on FileUtils is to create a class or module full of methods and always use string as parameters, like OddClassName.word_count("some string") and OddClassName.cjk?("some string"). We like the first better because of readability.

I understand that monkey patching a basic class as described in the first alternative can have name clashes. However, if this is the main application, not a library, should I worry with it at all?

So, the questions are:

  • Is adding methods to ruby base classes a bad practice? If yes, is that in all cases or only in some cases?
  • What is the best approach to accomplish this?
  • What could be the name of 'OddClassName'?

Please suggest any alternatives.

Was it helpful?

Solution

Monkey patching isn't considered to be a bad practice unless you are writing odd methods that do not have PatchedClass-related behavior (for example, String.monkeyPatchForMakingJpegFromString is rather bad, but Jpeg.fromString is good enough.)

But if your project is rather large, the libraries that you use in it may happen to have colliding patches, so you may have one more problem with all these patching stuffs. In Ruby 2.0, refinements come to an aid. They work as follows: you define a module, refine your (even core) class in it, and then use that module where it's necessary. So, in your code it works as:

YourClass.new.refinedMethodFromCoreClass #=> some result

But

CoreClass.refinedMethodFromCoreClass

produces undefined method exception.

That's all monkey patching stuff: monkey patching is useful and convenient, but refinements add some features, that make your code more secure, maintainable and neat.

OTHER TIPS

I'd use a new class, call it Doc or something because getting the word count and checking languages sounds like operations for documents.

Let it take a string as a constructor parameter and have modifications chain to return a new Doc. Also give it a to_s method that returns the string.

class Doc
  def initialize(str)
    @str = str
  end

  def to_s
    @str
  end

  define word_count, cjk?, etc.
end

Doc.new("Some document").word_count
# => 2
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top