Playing with the freedom that Ruby offers in its base features, I found rather easy to alias most operator used in the language, but the Regexp#~ unary prefix operator is trickier.
A first naïve approach would be to alias it in the Regexp class itself
class Regexp
alias hit ~@ # remember that @ stands for "prefix version"
# Note that a simple `alias_method :hit, :~@` will give the same result
end
As it was pointed in some answer bellow, this approach is somehow functionnal with the dot notation calling form, like /needle/.hit
. However trying to execute hit /needle/
will raise undefined method
hit' for main:Object (NoMethodError)`
So an other naïve approach would be to define this very method in Object
, something like
class Object
def ~@(pattern)
pattern =~ $_
end
end
However, this won’t work, as the $_
global variable is in fact locally binded and won’t keep the value it has in the calling context, that is $_
is always nil
in the previous snippet.
So the question is, is it possible to have the expression hit /needle/
to restitute the same result as ~ /needle/
?
CodePudding user response:
Works just fine for me:
class Regexp
alias_method :hit, :~ # both of them work
# alias hit ~ # both of them work
end
$_ = "input data"
/at/.hit #=> 7
~/at/ #=> 7
/at/.hit #=> 7
~/at/ #=> 7
CodePudding user response:
So, as the completed question now inhibits it, the main hindrance is the narrow scope of $_
. That’s where trace_var
can come to the rescue:
trace_var :$_, proc { |nub|
$last_explicitly_read_line = nub
#puts "$_ is now '#{nub}'"
}
def reach(pattern)
$last_explicitly_read_line =~ pattern
end
def first
$_ = "It’s needless to despair."
end
def second
first
p reach /needle/
$_ = 'What a needlework!'
p reach /needle/
end
p reach /needle/
second
p reach /needle/
$_ = nil
p reach /needle/
So the basic idea is to stash the value of $_
each time it is changed in an other variable that will be accessible in other subsequent calling context. Here it was implemented with a an other global variable (not locally binded, unlike $_
of course), but the same result could be obtained with other implementations, like defining a class variable on Object
.
One could also try to use something like binding_of_caller or binding_ninja, but my own approach of doing so failed, and also of course it comes with additional dependencies which have their own limitations.