Casper said:
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