Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect when a Ruby object is the right-hand side of a comparison?

Tags:

ruby

I want to create an object in Ruby that can lazily execute some code when it is accessed, e.g. when it is inspected or compared. It's easy enough to intercept messages with method_missing (which would handle object > 5), but this doesn't cover all attempts to access the object.

To illustrate:

class Proxy
  def initialize(obj)
    @object = obj
  end

  def do_something
    self
  end

  def do_something_else
    self
  end

  def method_missing(msg, *args)
    puts "I'm here #{msg}"
    # Do something here
    @object.send(msg, *args)
  end
end

Usage:

proxy = Proxy.new(5)
proxy.do_something.do_something_else

proxy > 2
# I'm here >
# true

2 > proxy
# ArgumentError: comparison of Fixnum with Proxy failed

I'm wondering if there's an implementation of Proxy such that 2 actually sees 5 instead of the object.

like image 304
c4am95 Avatar asked Dec 05 '25 07:12

c4am95


1 Answers

No, you can't "detect when a Ruby object is the right-hand side of a comparison." I'm going to infer from this, hopefully correctly, that the problem you're actually trying to solve is how to use a Ruby object in the right-hand side of a comparison with an object of a different type.

The answer is to define a coerce method. This method will be called automatically when the object is on the right-hand side of a comparison operator and an "incompatible" object is on the left-hand side. The LHS object will be supplied as an argument, and it's expected to return an array with two elements: "New" LHS and RHS values that are compatible. Using your Proxy example:

class Proxy
  def initialize(obj)
    @object = obj
  end

  def coerce(other)
    if other.is_a?(Fixnum)
      return [ other, @object.to_i ]
    end
    super
  end
end

proxy = Proxy.new(5)

2 > proxy
# => false

Of course, your coerce method will likely be more complex if you want your Proxy class to be able to "wrap" values other than Fixnums. For example, what will you do if @object is a String and other is a Float?

And, of course, this only handles when the object is the RHS. To make it work as the LHS as well you'll want to use the Comparable mixin.

like image 111
Jordan Running Avatar answered Dec 07 '25 23:12

Jordan Running



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!