Home > Enterprise >  In Ruby, how can the Regexp#~ unary operator be aliased?
In Ruby, how can the Regexp#~ unary operator be aliased?

Time:11-30

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.

  • Related