Overriding the == operator in Ruby
In Ruby ==
is just a method (with some syntax sugar on top allowing you to write foo == bar
instead of foo.==(bar)
) and you override ==
just like you would any other method:
class MyClass
def ==(other_object)
# return true if self is equal to other_object, false otherwise
end
end
override the = operator in ruby
Sorry, you can't do this. When you write foo = bar
, you're just assigning a variable, not calling any method. It's only something.foo = bar
that desugars to a method call, and just like everywhere else, the receiver of that method call is the thing before the dot.
list of ruby operators that can be overridden/implemented
Here's a table of the Ruby operators.
The ones that are methods and overloadable are:
[ ] [ ]= Element reference, element set
** Exponentiation
! ~ + - Not, complement, unary plus and minus (method names for the last two are +@ and -@)
* / % Multiply, divide, and modulo
+ - Plus and minus
>> << Right and left shift
& Bitwise `and'
^ | Bitwise exclusive `or' and regular `or'
<= < > >= Comparison operators
<=> == === != =~ !~ Equality and pattern match operators (!= and !~ may not be defined as methods)
The table was from the 2001 Pickaxe book, but that's the same table as in the Ruby 1.9 Pickaxe book -- no reason to believe that this set of infix operators will ever change.
Overriding == equality operator works only in one direction
It's not possible without changing other classes. Basically a == b
equals a.==(b)
. So you need to override ==
operator for the second class if you want to make it work.
Overload = operator ruby?
Of course you can! It would help to google for Ruby's spaceship operator.
You need to include Comparable
module, and then implement the method. Take a look at simple example of overwriting <=>
: http://brettu.com/rails-daily-ruby-tips-121-spaceship-operator-example/
I'll take an example from the article:
class Country
include Comparable
attr_accessor :age
def initialize(age)
@age = age
end
def <=>(other_country)
age <=> other_country.age
end
end
For overloading the <=>
you don't need to include Comparable
module, however by including it, it "mixins" some useful methods to your Country
class with which you can perform comparisons.
Let's see some examples:
country1 = Country.new(50)
country2 = Country.new(25)
country1 > country2
# => true
country1 == country2
# => false
country1 < country2
# => false
country3 = Country.new(23)
[country1, country2, country3].sort
# => [country3, country2, country1]
But, if the Comparable
module was not included:
country1 > country2
# => NoMethodError: undefined method `>' for #<Country:...>
Good luck!
Ruby: overload operator behaviour for some cases only
Both approaches posted here so far are a legacy Rails way, which is plain wrong. It relies on the fact that the class has no method called plus
and nobody will reopen the class to create a method called plus
. Otherwise things will go mad.
The correct solution is Module#prepend
:
Integer.prepend(Module.new do
def + other
case other
when Fixnum then special_behaviour
else super(other)
end
end
end)
How do you override the ruby case equality operator? (===)
The expression after the 'case' keyword is the right hand side of the === expression, and the expression after the 'when' keyword is on the left hand side of the expression. So, the method that is being called is String.===, not A.===.
A quick approach to reversing the comparison:
class Revcomp
def initialize(obj)
@obj = obj
end
def ===(other)
other === @obj
end
def self.rev(obj)
Revcomp.new(obj)
end
end
class Test
def ===(other)
puts "here"
end
end
t = Test.new
case t
when Revcomp.rev("abc")
puts "there"
else
puts "somewhere"
end
How can I override the .. and ... operators of Ruby Ranges to accept Float::INFINITY?
I don't think that what you want to do is a correct way of solving such issue.
What I would suggest instead, is to simply override the end_date
method in model:
def end_date
super == Float::INFINITY ? DateTime::Infinity.new : super
end
This basically says if end_date
in db is Float::INFINITY
return DateTime::Infinity.new
as end_date
, otherwise return what's in database.
question on overriding + operator in ruby
You should not mutate the object when implementing +
operator. Instead return a new Point Object:
class Point
attr_accessor :x, :y
def initialize(x,y)
@x, @y = x, y
end
def +(other)
Point.new(@x + other.x, @y + other.y)
end
def to_s
"(#{@x}, #{@y})"
end
end
ruby-1.8.7-p302:
> p1 = Point.new(1,2)
=> #<Point:0x10031f870 @y=2, @x=1>
> p2 = Point.new(3, 4)
=> #<Point:0x1001bb718 @y=4, @x=3>
> p1 + p2
=> #<Point:0x1001a44c8 @y=6, @x=4>
> p3 = p1 + p2
=> #<Point:0x1001911e8 @y=6, @x=4>
> p3
=> #<Point:0x1001911e8 @y=6, @x=4>
> p1 += p2
=> #<Point:0x1001877b0 @y=6, @x=4>
> p1
=> #<Point:0x1001877b0 @y=6, @x=4>
Related Topics
Which Algorithm Does Ruby's Sort Method Use
Ruby on Rails Error "Cannot Load Such File -- Less"
Why Pg::Uniqueviolation: Error: Duplicate Key Value Violates Unique Constraint
How to Track Down a Memory Leak in My Ruby Code
How to Get the Line of Code That Triggers a Query
Extracting the Last N Characters from a Ruby String
Rails 4 How to Ignore Pending Migrations
Should One Use Dashes or Underscores When Naming a Gem with More Than One Word
Where in the Ruby Language Is %Q, %W, etc., Defined
How to Measure the Size of a Ruby Object
Executing User-Supplied Ruby Code on a Web Server
Tell the End of a .Each Loop in Ruby
How to Get the Target of a Symlink
Rendering a Partial from a Controller in Rails