
Issue #20093 has been updated by Eregon (Benoit Daloze). tagomoris (Satoshi Tagomori) wrote in #note-4:
I never want to recommend someone to use `class_eval` for monkey patching.
Why not? For clarity, I mean `class_eval` with a block so there are no syntax highlighting hurdles and no extra runtime parsing. It is the existing way to be explicit this is reopening an existing class, and it fails clearly if the class was not defined before. The only downside I see is that doesn't make it easy to define and access constants defined under that class/module. A possibility in that case is to use `class_eval(String)`. I guess the motivation for this proposal is #19744? ---------------------------------------- Feature #20093: Syntax or keyword to reopen existing classs/modules, never to define new classs/modules https://bugs.ruby-lang.org/issues/20093#change-105887 * Author: tagomoris (Satoshi Tagomori) * Status: Open * Priority: Normal ---------------------------------------- `class A` and `module B` will reopen existing class A or module B to add/re-define methods if A/B exists. Otherwise, these will define the new class/module A/B. But, in my opinion, the code of `class A` for patching existing classes doesn't work expectedly when `A` is not defined beforehand. It expects other codes to define `A` before being called. For example: ```ruby # string_exclude.rb class String def exclude?(string) !include?(string) end end ``` This code expects that there is the `String` class, and it has the `include?` method. This code doesn't work if the file is loaded in the way below: ```ruby load('string_exclude.rb', true) ``` This code doesn't raise errors and will define an almost empty class (only with a method `exclude?` to raise NameError). It should be unexpected for every user. So, I want to propose a new syntax to reopen the existing class/module or raise errors if the specified class/module is not defined. ```ruby class extension String def exclude?(string) !include?(string) end end # adds #exclude? to String class class extension Stroooong def exclude?(string) !include?(string) end end # will raise NameError (or something else) ``` Some additional things: * `class extension String` (and `module extension String`) causes a compile error (SyntaxError) on Ruby 3.3. So we have space to add a keyword between class/module and the class/module name. * I don't have a strong opinion about the keyword name `extension`. An alternative idea is `reopen`. -- https://bugs.ruby-lang.org/