Trying to patch net/http and have it only apply to one service class. Refinements seem to be the way to go. The monkey patch below works but the refinement doesn't. Is this a namespace issue? The project is on ruby 2.3.0 but have tried with 2.4.1 as well and only the monkey patch seems to get applied.
With a monkey patch:
module Net
class HTTPGenericRequest
def write_header(sock, ver, path)
puts "monkey patched!"
# patch stuff...
end
end
end
Service.new.make_request
# monkey patched!
With a refinement:
module NetHttpPatch
refine Net::HTTPGenericRequest do
def write_header(sock, ver, path)
puts "refined!"
# patch stuff...
end
end
end
class Service
using NetHttpPatch
end
Service.new.make_request
# :(
UPDATE:
This seems to be similar scope wise? Obviously more complex things are happening when net/http makes a request does it lose scope then?
module TimeExtension
refine Fixnum do
def hours
self * 60
end
end
end
class Service
using TimeExtension
def one_hour
puts 1.hours
end
end
puts Service.new.one_hour
# 60
UPDATE UPDATE:
nvm, I see what's happening now :) have to keep your brain from mixing using
up with how mixins work.
module TimeExtension
refine Fixnum do
def hours
self * 60
end
end
end
class Foo
def one_hour
puts 1.hours
end
end
class Service
using TimeExtension
def one_hour
puts 1.hours
end
def another_hour
Foo.new.one_hour
end
end
puts Service.new.one_hour
# 60
puts Service.new.another_hour
# undefined method `hours' for 1:Fixnum (NoMethodError)
Is this a namespace issue?
It is a scope issue. Refinements are lexically scoped:
class Service
using NetHttpPatch
# Refinement is in scope here
end
# different lexical scope, Refinement is not in scope here
class Service
# another different lexical scope, Refinement is *not* in scope here!
end
Originally, there was only main::using
, which was script-scoped, i.e. the Refinement was in scope for the entire remainder of the script. Module#using
came later, it scopes the Refinement to the lexical class definition body.