Casper wrote:
1. class MyController < ActionController::Base
2. helper :my_helper
3. end
I see this construct in Ruby on Rails a lot, and I don't know what is
going on in line 2.
Is this invoking a method called "helper" with the argument
":my_helper"? And if so, when does this get invoked?
Thanks.
You are on the money. I will attempt to explain, but you should read the PickAxe for the full Ruby goodness.
class sdgksjdgk
...
end
Is just a way of scoping your code. In particular, it redefines self, it creates a new lexical scope (that is, a new binding for local variables), it tells class variables (@@foo) where to hook up to, and it tells method definitions where to hook up to. Run `ruby -e"p self" ` and you'll discover that you're always inside a class...end block.
So
class Blob
puts "Hello!"
end
Prints "Hello!" How does it do that? Well, you're trying to call "puts" which really means you're trying to call "self.puts". What's self? Well, let's find out:
a = class Blob
self #like defs and blocks, class returns the last thing evaluated
end
=> Blob
a.class
=> Class
Self is the Class object named Blob. So when you type "puts" inside a class block, you're calling the instance method Blob.puts. Where does it get puts from? Well, Blob is a Class, and Class inherits Object, and Object includes Kernel, and Kernel has a puts method defined on it.
When you write
class Blob
def murh
puts "Hello!"
end
end
you're referring to an entirely different self.puts, of course. When "murh" actually gets invoked, self will be the Blob instance it gets invoked on, instead of the Class instance named Blob. But when the method is actually defined, Ruby knows to define it as an instance method of whatever class...end block it's inside.
So, when you call helper :my_helper, bingo, you're calling a method. Specifically, Blob.helper. Not Blob#helper, which is the instance method, where self would be some instance of Blob -- rather this something akin to Class#helper. (When I say "something akin to" I'm referring to singleton classes. That's a whole 'nother email, though.)
Where is it getting helper from? Well, in short, it's getting it from ActionController::Helpers::ClassMethods in action_controller/helpers.rb. The long version involves explaining what singleton classes are.
Hope that helps.
Sidenote - Adanced Rubyage:
Earlier I said that class...end does more than redefine self. This is important. Notice that, of the following two, the first works but the second doesn't:
#1:
class Moo
@@fun = 0
def Moo.fun
@@fun += 1
puts @@fun
end
end
#2:
class Moo
@@fun
end
def Moo.fun
@@fun += 1
puts @@fun
end
Here's another example where the scope of a given thing is not dependent on self, but dependent on what class...end block I'm inside.
class Borg
def blong
def frooz
puts 'Hi!'
end
end
end
a = Borg.new; b = Borg.new
a.frooz #=> Error
a.blong
a.frooz #=> Hi!
b.frooz #=> Hi!
If the 'def' keyword were dependent upon self, then the above would not work. Notice that, when 'def blong' is run, self is the Class object named Borg. When 'def frooz' is run, self is the Borg object assigned to a.
Rather, a 'def' keyword is tied to what class it's in. See the following wacky example:
class A
end
class B
def A.moo
def moo
puts 'mooo'
end
end
end
a = A.new
b = B.new
A.moo
a.moo #=> Error
b.moo #=> mooo
But if you find a legitimate reason to do shit like that, please let me know. I'm quite curious.
BTW, if you read a couple of threads back, class...end isn't the only way to establish such a context. There's also Class.new and Module#class_eval -- running 'def' inside those is like running it inside a proper class...end block.
Oh boy. I'm feeling kinda light-headed now...
Devin