Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Open classes in a module

I know I can execute the following to add methods to the String class

class String
  def do_something
    puts self.size
  end
end

var = "test"
var.do_something

and this will return 4

I want to be able to have a module with a function that takes in a String, but be able to call the do_something method on this string (see below for example) - is it possible?

EDIT: Added sample code that is not working

module TestModule
  class String
    def do_something
      puts self.size
    end
  end

  def self.test(str)    
    str.do_something
  end
end

This gives the error: undefined method 'do_something' for "hello":String (NoMethodError)

like image 333
Aly Avatar asked Dec 22 '22 15:12

Aly


1 Answers

The way your code is written, you're defining a new class called TestModule::String. If you want to modify the built-in Ruby String class, you need to use the fully-qualified name of String (with the ""::") if you want to keep the declaration inside the module.

module TestModule
  class ::String
    def do_something
      puts self.size
    end
  end

  def self.test(str)  
    str.do_something
  end
end

Adding the "::" tells Ruby that the String class that you want is not part of the TestModule.

It's probably cleaner to just declare String outside of TestModule in the same file.

If you don't want to pollute the global String class, you could just modify the specific String instance that you want to add the method to.

module TestModule
  def self.test(str)  
    do_somethingify!(str)
    str.do_something
  end

  def self.do_somethingify!(str)
    unless str.respond_to? :do_something
      str.instance_eval do
        def do_something
          puts size
        end
      end
    end
  end      
end          
like image 132
hallidave Avatar answered Jan 11 '23 21:01

hallidave