This is really late, but here's how you can find where a method is defined:
http://gist.github.com/76951
# How to find out where a method comes from.
# Learned this from Dave Thomas while teaching Advanced Ruby Studio
# Makes the case for separating method definitions into
# modules, especially when enhancing built-in classes.
module Perpetrator
def crime
end
end
class Fixnum
include Perpetrator
end
p 2.method(:crime) # The "2" here is an instance of Fixnum.
#<Method: Fixnum(Perpetrator)#crime>
If you're on Ruby 1.9+, you can use source_location
require 'csv'
p CSV.new('string').method(:flock)
# => #<Method: CSV#flock>
CSV.new('string').method(:flock).source_location
# => ["/path/to/ruby/1.9.2-p290/lib/ruby/1.9.1/forwardable.rb", 180]
Note that this won't work on everything, like native compiled code. The Method class has some neat functions, too, like Method#owner which returns the file where the method is defined.
EDIT: Also see the __file__
and __line__
and notes for REE in the other answer, they're handy too. -- wg
I'm going to heavily quote the Object documentation here, because I think it has some great explanations. I encourage you to read it, and also the documentation for these methods as they're overridden in other classes, like String.
Side note: if you want to try these out for yourself on different objects, use something like this:
class Object
def all_equals(o)
ops = [:==, :===, :eql?, :equal?]
Hash[ops.map(&:to_s).zip(ops.map {|s| send(s, o) })]
end
end
"a".all_equals "a" # => {"=="=>true, "==="=>true, "eql?"=>true, "equal?"=>false}
==
— generic "equality"
At the Object level, ==
returns true only if obj
and other
are the same object. Typically, this method is overridden in descendant classes to provide class-specific meaning.
This is the most common comparison, and thus the most fundamental place where you (as the author of a class) get to decide if two objects are "equal" or not.
===
— case equality
For class Object, effectively the same as calling #==
, but typically overridden by descendants to provide meaningful semantics in case statements.
This is incredibly useful. Examples of things which have interesting ===
implementations:
- Range
- Regex
- Proc (in Ruby 1.9)
So you can do things like:
case some_object
when /a regex/
# The regex matches
when 2..4
# some_object is in the range 2..4
when lambda {|x| some_crazy_custom_predicate }
# the lambda returned true
end
See my answer here for a neat example of how case
+Regex
can make code a lot cleaner. And of course, by providing your own ===
implementation, you can get custom case
semantics.
eql?
— Hash
equality
The eql?
method returns true if obj
and other
refer to the same hash key. This is used by Hash
to test members for equality. For objects of class Object
, eql?
is synonymous with ==
. Subclasses normally continue this tradition by aliasing eql?
to their overridden ==
method, but there are exceptions. Numeric
types, for example, perform type conversion across ==
, but not across eql?
, so:
1 == 1.0 #=> true
1.eql? 1.0 #=> false
So you're free to override this for your own uses, or you can override ==
and use alias :eql? :==
so the two methods behave the same way.
equal?
— identity comparison
Unlike ==
, the equal?
method should never be overridden by subclasses: it is used to determine object identity (that is, a.equal?(b)
iff a
is the same object as b
).
This is effectively pointer comparison.
Best Solution
In general, methods that end in
!
indicate that the method will modify the object it's called on. Ruby calls these as "dangerous methods" because they change state that someone else might have a reference to. Here's a simple example for strings:This will output:
In the standard libraries, there are a lot of places you'll see pairs of similarly named methods, one with the
!
and one without. The ones without are called "safe methods", and they return a copy of the original with changes applied to the copy, with the callee unchanged. Here's the same example without the!
:This outputs:
Keep in mind this is just a convention, but a lot of Ruby classes follow it. It also helps you keep track of what's getting modified in your code.