0

I'm reading some book for ruby programming language and was wondering how something like this works

class String
  def word_count
    frequencies = Hash.new(0)
    downcase.scan(/\w+/) { |word| frequencies[word] += 1 }
    return frequencies
  end
end

I know there is a build-in string, I came from (C++) btw, So creating class string will make ambiguity when defining an object string x = new string(), I search about that and i found some concept is named refinement which is allowing us to modify and add functions to String class, I see them using keyword refine to make these things(according to the docs), but here my questions come, When i just put the above class on the irb and started to test it like that "amr adel".word_count, It gave me the correct result, I expected not to work at first, So if it works why could i even use refine in my code why don't i only create a class with same name of the built-in one and put additional function and modify functions, Are this way doing the refinement process implicitly?

I admit that ruby is amazing and so easy to work with, but i want to know things goes on.

If you could refer some articles or something it will be extremely appreciated Thanks

Amr Adel
  • 574
  • 1
  • 7
  • 18
  • 2
    The main point of confusion might probably be that with the code above, you are **not** creating a new class named `String` which effectively shadows the core `String` class. Instead, what actually happens is that you are altering the single core String class and add a new method. Thus, the method will be available on each and every strings. This is due to an important concept in Ruby called "open classes". The rather new concept of Refinements is an attempt to ensure that such extensions don't pollute the global namespace, e.g. when different libraries each try to add a `word_count` method. – Holger Just Jan 09 '18 at 16:09
  • Oh, this is clearer now, thank you very much @HolgerJust – Amr Adel Jan 10 '18 at 06:38

1 Answers1

2

From the ruby documentation:

You may activate refinements at top-level, and inside classes and modules. You may not activate refinements in method scope. Refinements are activated until the end of the current class or module definition, or until the end of the current file if used at the top-level.

The whole point of refinements (as opposed to just extending a core class) is that they are scoped.

In your code above, String#word_count will be defined everywhere - for example, if you have multiple files.

On the other hand, if you define that method as a refinement then it will only be defined in places where you are explicitly using it.

The motivation for this is that you can add/alter behaviour in one location without it impacting code elsewhere.

Tom Lord
  • 27,404
  • 4
  • 50
  • 77