Reputation: 2390
Is there a simple way to extend a functionality of a standard library class like String
inside a module without affecting anything outside of it? Example (won't work):
module Foo
class String
def hello
"hello #{self}!"
end
end
class Bar
def greet name
name.hello
end
end
end
Result I'm looking for:
Foo::Bar.new.greet 'Tom' #=> hello Tom!
'Tom'.hello #=> NoMethodError
I'm aware of solutions like creating MyString < String
with desired functionality, but I would rather not call MyString.new('foo')
every time I want to use a string inside the module.
I realise this may not be considered good practice, I'm just looking to expand my understanding of the language.
Upvotes: 2
Views: 617
Reputation: 1050
Write a class of the same name then use require_relative
(or similar method) to include it.
class Date
def itis
puts "It is " + self.to_s
end
Example:
[1] pry(main)> require_relative 'date.rb'
=> true
[2] pry(main)> require 'date'
=> true
[3] pry(main)> Date.new(2018, 10, 9).itis
It is 2018-10-09
=> nil
Upvotes: 0
Reputation: 52357
What you're looking for is Refinement:
Refinements are designed to reduce the impact of monkey patching on other users of the monkey-patched class. Refinements provide a way to extend a class locally.
module Foo
refine String do
def hello
"hello #{self}!"
end
end
end
puts 'Tom'.hello
#=> undefined method `hello' for "Tom":String
using Foo
puts 'Tom'.hello
#=> hello Tom!
Using refinement inside Bar
class:
# Without refinement
class Bar
def greet(name)
name.hello
end
end
puts Bar.new.greet('Tom')
#=> undefined method `hello' for "Tom":String
# With refinement
class Bar
using Foo
def greet(name)
name.hello
end
end
puts Bar.new.greet('Tom')
#=> hello Tom!
For the complete info about scoping, method lookup and stuff look into docs link I've provided :)
P.S. Be aware, that Rubinius developers are philosophically opposed to Refinements and thus will never implement them (c) Jörg W Mittag.
Upvotes: 3