After years of working with ruby, I finally came across a good need for ruby refinement!
# frozen_string_literal: true
module TimeMongoInspect
refine Time do
def inspect
strftime("Time.parse('%Y-%m-%d %H:%M:%S %z')")
end
def to_s
strftime("Time.parse('%Y-%m-%d %H:%M:%S %z')")
end
end
end
using TimeMongoInspect
a = { time: Time.now }
puts a.inspect
The desired output is
{:time=>Time.parse('2023-08-29 00:39:08.546338569 +0000')}
In case someone is curious, I want to be able to cut-n-paste output into code, however, I need the date to be properly interpetted as a real Time class..
ChatGPT said to also refine Array and Hash
module TimeMongoInspect
refine Time do
def inspect
"Time.parse('#{strftime('%Y-%m-%d %H:%M:%S %z')}')"
end
def to_s
inspect
end
end
refine Hash do
def inspect
"{" + self.map { |k, v| "#{k.inspect}: #{v.inspect}" }.join(", ") + "}"
end
end
refine Array do
def inspect
"[" + self.map { |v| v.inspect }.join(", ") + "]"
end
end
end
However, I thought this was making the problem even more complicated and was the wrong way to go.
What is the correct way to do this?
The issue is that refinements are lexically scoped.
Meaning they apply only to code you write in the same script.
If you refine Time#inspect
. Every call to Time#inspect
from the same file/script will use your refined method.
If you call Time.now.inspect
directly you will see that.
However, the refinement has no effect on code not in your script. For example Hash#inspect
is not defined in your code. It's defined elsewhere that does not have your refinement. Therefore any Time#inspect
called from there does not use your refinement.
Your options:
Hash#inspect
and if you want Array#inspect
in your refinement and live with the complexity.Time#inspect
globally without refinements and live with the side-effects.