Reputation: 87
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.
Upvotes: 3
Views: 89
Reputation: 106037
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.
Upvotes: 1