Send to KindleRuby Forensics
This guest post is contributed by Elise Huard, who is based in Brussels, Belgium and is the owner of Jabberwocky, a solutions company mostly focused on Rails. She has worked with a few other technologies before falling in love with Rails and Ruby about 3 years ago and going freelance to work with Ruby full time. She contributes to open source projects as much as she can, and has given talks at a few Ruby and Rails conferences. She’s a jack of all trades, loves reading, tinkering, food, travel, learning, and people out of the ordinary.
Say you want to use a library, but no or very little documentation is available, and you don’t feel like diving into the code right away.
Well, you picked the right language. Ruby is blessed with what is called introspection: if you ask a Ruby program/class/module politely, it will tell you almost anything about itself. This post will tell you some tricks I use on a daily basis.
module Layer
FILLINGS = [:chocolate, :meringue, :jam, :cream, :strawberry]
def fill(filling)
puts "fill with #{filling}"
end
end
class Cake
include Layer
attr_accessor :calories
def ice
@calories = @calories + 200
end
def eat
puts "nom"
end
def self.bake
return new
end
end
class CheeseCake < Cake; end
Say you have a class, but you’d like to know what method it defines.
Cake.public_instance_methods
Won’t be that useful, because Ruby objects (with some exceptions like BasicObject) have got a whole lot of methods out of the box. Rather, use:
Cake.public_instance_methods - Object.public_instance_methods => [:calories, :calories=, :ice, :eat, :fill]
If you want one particular method, and you have an idea of which name it should have:
(Cake.public_instance_methods - Object.public_instance_methods).grep(/eat/)
Will show if your instinct was right or not.
The same can be done for class methods, of course:
(Cake.methods - Object.methods) => [:bake]
(public_class_methods also works.)
Note: this won’t show you the dynamic methods, like find_by_X for ActiveRecord. The class doesn’t know it has these kind of methods in itself. They’re executed on the fly when the program hits method_missing. You’d have to look at the classes’ method_missing method to find out.
Then there’s the case where you’d like to know, exactly, where a method was defined. Ruby gives us the ‘method‘ method, which takes a symbol as an argument.
Cake.new.method(:fill) => #<Method: Cake(Layer)#fill>
Which tells us it was defined in the Layer module, included in the Cake class.
Cake.new.method(:eat) => #<Method: Cake#eat>
Sometimes, you want to know which other classes your class was descended from – including mixed in modules. The ancestors method will show you:
CheeseCake.ancestors => [CheeseCake, Cake, Layer, Object, Kernel, BasicObject]
Should you want to know about any constants, there’s a method for that too:
Cake.constants => [:FILLINGS]
All these methods have a good chance of giving you the information you want. When used in irb, together with a little experimentation, they can really help you find the code you’re looking for.
I hope you found this article valuable. Feel free to ask questions and give feedback in the comments section of this post. Thanks!
Do read these awesome Guest Posts:
- An introduction to eventmachine, and how to avoid callback spaghetti
- The Testing Mindset
- An Introduction to Desktop Apps with Ruby
- The Ruby movement
- Almost everything is an object (and everything is almost an object!)
- So… you’re new to Ruby!
- Incorporating Web APIs to spark computer programming exercises
- 14 Ways To Have Fun Coding Ruby
- Writing modular web applications with Rack
- How to Learn Ruby (or any programming language)
Technorati Tags: Ruby, Programming, Elise Huard, Ruby for Noobs, Ruby beginners, Ruby Forensics
Posted by Elise Huard
{ 11 comments… read them below or add one }
Cake.new.method(:fill) was a new learning
Thanks!
The infos above deserve a cheatsheet
Heh, I guess this is a kind of cheat sheet
It’s pretty basic compared to some of the other guest posts, but I figured it might be helpful to beginning rubyists.
Hi Elise,
I’ve created a simple gem called ‘reflectorr’ (https://rubygems.org/gems/reflectorr) that can help with the question: ‘Which methods can I use here?’
For me this is an extra aid for understanding how things (like rails) can be used to the extreme.
C+++
Hi Christiaan, thanks for that gem, I didn’t know about it !
I think it’s not a bad thing for people to know which ruby features they can use, though.
Elise,
you’re right, I’m certain this can be of help for many rubyists.
C+++
Thanks for posting this! I already knew some of it but I never thought about subtracting Object.methods. Very clever!
There is another way of getting methods by providing a “false” to include_super parameter:
Cake.public_instance_methods(false)
=> ["ice", "calories", "eat", "calories="]
This will although also miss the method from Layer. So:
Cake.included_modules.map {|mod| mod.public_instance_methods(false) unless mod == Kernel}.compact
=> [["fill"]]
Anyway, there is room for improvement
Nice, I didn’t know that ! thanks for sharing this, always happy to learn.
Hello. I think you can avoid the hassle of subtracting `Object.public_instance_methods` and `Object.methods` by passing `false` to `public_instance_methods` and `methods` respectively: `Cake.public_instance_methods(false)` and `Cake.methods(false)` This should return only the methods defined in the receiver.
Thanks for the article, I learned a few things I didn’t know.
Thanks for sharing ! previous commenter also mentioned that.
{ 32 trackbacks }