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.
Ruby method for +=
The +=
operator is not associated to any method, it is just syntactic sugar, when you write a += b
the Ruby interpreter transform it to a = a + b
, the same is for a.b += c
that is transformed to a.b = a.b + c
. Thus you just have to define the methods x=
and x
as you need:
class Plane
def initialize
@moved = 0
@x = 0
end
attr_reader :x
def x=(x)
@x = x
@moved += 1
end
def to_s
"moved #{@moved} times, current x is #{@x}"
end
end
plane = Plane.new
plane.x += 5
plane.x += 10
puts plane.to_s
# => moved 2 times, current x is 15
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>
Overriding instance variable array's operators in Ruby
I think you're looking for this:
class Test
def initialize
@myarray = []
class << @myarray
def <<(val)
puts "adding #{val}" # or whatever it is you want to do first
super(val)
end
end
end
attr_accessor :myarray
end
There's a good article about this and related topics at Understanding Ruby Singleton Classes.
Can I implement += in my class to increase a contained value?
Since c += 100
is just a sugar for c = c + 100
, you can't escape overwriting c
. BUT you can overwrite it with a similar object (and not with fixnum, as in your question).
class Container
def initialize(value = 0)
@value = value
end
def + (other)
Container.new(@value + other)
end
def get
@value
end
end
c = Container.new(100)
c += 100
c.get # => 200
Can Ruby define some generic operator?
There is a fixed set of operators in Ruby, some of which are syntactic sugar for message sends and can thus be overridden.
You can't add new operators. In Ruby, the fixed set of operators is part of the language syntax, and Ruby doesn't allow Ruby code to change the syntax of the language. If you want to add a new operator, you will have to convince matz to change the language specification, and you will have to convince the developers of Rubinius, JRuby, YARV, MagLev, and MRuby to implement this change.
Overridable
These desugar into message sends and thus can be overridden by implementing the corresponding methods.
- unary prefix
+foo
→foo.+@()
, ergo:def +@; end
-foo
→foo.-@()
, ergo:def -@; end
!foo
→foo.!()
, ergo:def !; end
~foo
→foo.~()
, ergo:def ~; end
- binary infix
foo + bar
→foo.+(bar)
, ergo:def +(other) end
foo - bar
→foo.-(bar)
, ergo:def -(other) end
foo * bar
→foo.*(bar)
, ergo:def *(other) end
foo / bar
→foo./(bar)
, ergo:def /(other) end
foo % bar
→foo.%(bar)
, ergo:def %(other) end
foo ** bar
→foo.**(bar)
, ergo:def **(other) end
foo >> bar
→foo.>>(bar)
, ergo:def >>(other) end
foo << bar
→foo.<<(bar)
, ergo:def <<(other) end
foo & bar
→foo.&(bar)
, ergo:def &(other) end
foo ^ bar
→foo.^(bar)
, ergo:def ^(other) end
foo | bar
→foo.|(bar)
, ergo:def |(other) end
foo < bar
→foo.<(bar)
, ergo:def <(other) end
foo > bar
→foo.>(bar)
, ergo:def >(other) end
foo <= bar
→foo.<=(bar)
, ergo:def <=(other) end
foo >= bar
→foo.>=(bar)
, ergo:def >=(other) end
foo == bar
→foo.==(bar)
, ergo:def ==(other) end
foo === bar
→foo.===(bar)
, ergo:def ===(other) end
foo != bar
→foo.!=(bar)
, ergo:def !=(other) end
foo =~ bar
→foo.=~(bar)
, ergo:def =~(other) end
foo !~ bar
→foo.!~(bar)
, ergo:def !~(other) end
foo <=> bar
→foo.<=>(bar)
, ergo:def <=>(other) end
- n-ary "around-fix"
foo[bar, baz]
→foo.[](bar, baz)
, ergo:def [](a, b) end
foo[bar, baz] = quux
→foo.[]=(bar, baz, quux)
, ergo:def []=(a, b, c) end
foo.(bar, baz)
→foo.call(bar, baz)
, ergo:def call(a, b) end
Non-overridable
These don't desugar into message sends.
- unary prefix
defined?
- binary infix
foo && bar
foo and bar
foo || bar
foo or bar
foo = bar
- compound assignment
foo ||= bar
foo &&= bar
Sort-of overridable
You can't override these independently, but they (at least partially) translate into other operators that can be overridden.
- unary prefix
not foo
→foo.!()
, ergo:def !; end
- compound assignment
foo ω= bar
→foo = foo ω bar
for any ω ∉ {||
,&&
}
are Ruby's logical operators methods, like binary operators are?
These are the operators that cannot be (re)defined:
- &&, || (AND, OR)
- .., ... (range)
- ?: (ternary)
- rescue
- = (and **=, &&=, &=, *=, +=. -=, <<=, >>= , ||=, |=, ^=)
- defined?
- not
- and, or
- if, unless, while, until
The others, like (incomplete list) !, ~, +, -, **, *, /, %, >>, ==, != are implemented as methods and can be redefined.
Override for an array instance variable in class
class Player
attr_accessor :moves
def initialize
@moves = []
@moves.define_singleton_method(:<<) do |value|
raise Exception if include?(value)
push(value)
end
end
end
You can add methods only specific to a given object using the Object#define_singleton_method
. Ruby is really flexible when it comes to meta programming.
However such tools should be used sparingly. I don't know your specific situation, but you are probably better off not giving direct access to @moves
. The best approach might be to define methods in Player
that create an indirect and more restrictive interface to the internal representation and give you more control.
Related Topics
No Such File to Load - Readline
Installing Jekyll Without Root
How to Use Define_Method to Create Class Methods
Running a Command from Ruby Displaying and Capturing the Output
Matching Balanced Parenthesis in Ruby Using Recursive Regular Expressions Like Perl
Looking For Suggestions For Building a Secure Rest API Within Ruby on Rails
Error: Mime-Types-Data Requires Ruby Version >= 2.0
Ruby on Rails: Advanced Search
What Are the Benefits of the New Hash Syntax in Ruby 1.9
How to Replace a Hash Key with Another Key
Difference Between Ruby and Ruby on Rails
How to Avoid Nomethoderror For Nil Elements When Accessing Nested Hashes
Nomethoderror When Trying to Invoke Helper Method from Rails Controller
How to Use "Rvm --Default" on Macosx
Validation Failed: Upload File Has an Extension That Does Not Match Its Contents
How to Add an Array to Another Array in Ruby and Not End Up With a Multi-Dimensional Result