On 11/26/05, Ross Bamford <rosco / roscopeco.remove.co.uk> wrote:
> Hi Sean,

Hi Ross,

> I guess if I
> wanted to pass a block in that way, I'd have to get a Proc for the
> closure? I've seen code like:
>
>        some_method(proc { |s| s.do_something })
>
> which seems a bit nasty to me.

Yes - you'd have to pass it as a regular argument.

> Nice one. Gotta get used to this 'effectively adding keywords' thing too.
> I've gotten around the fact that class definitions can call methods, now I
> need to get used to it being _my_ methods :)

A class definition is executable code. The ability to define methods
that execute within the class definition is one of the most powerful
techniques available in Ruby.

[snip stuff about a class being an instance of Class]
>
> This is where I am going around in circles. It's an instance of Class, but
> it also has a class, Class. So, Class.class == Class. Is that right ?

Yes. If it's any consolation, it took me a fair bit of head scratching
before the 'aha' moment ;)

> Hmm, I think I need to go back to the book on class variables. I can't
> quite see how they fit in, especially with respect to singleton class and
> stuff. Thanks for your explanation, though - it's just me :(

@@class_variables seem to be a bit of a hack to me (at least in 1.8.x).
The double '@' is deliberately ugly. They obey different scoping rules
to other variables in that they look for the nearest enclosing class
regardless of self.

This is a little test that (to me) shows how wacky the scoping rules
are for class variables:

class A
  @@foo = "class variable foo"
  @foo = "class instance variable foo"
  def self.evaluate(txt)
    instance_eval txt
  end
  def self.eval_block(&block)
    instance_eval &block
  end
end

begin
  p A.instance_eval { @@foo }
rescue => e
  puts e
end

@@foo = "hi"

p A.instance_eval { [self, @@foo, @foo] }
p A.evaluate("[self, @@foo, @foo]")
p A.eval_block { [self, @@foo, @foo] }

class B
  @@foo = "B's class variable foo"
  @foo = "B instance foo"
  def self.eval_block(&block)
    instance_eval &block
  end
end

p B.eval_block { [self, @@foo, @foo] }
__END__
uninitialized class variable @@foo in Object
[A, "hi", "class instance variable foo"]
[A, "class variable foo", "class instance variable foo"]
[A, "hi", "class instance variable foo"]
[B, "B's class variable foo", "B instance foo"]

I'd be grateful if anyone can explain this behaviour (i.e. why the
call to B.eval_block gets B's class variable but the call to A gets
the outer scope).

Regards,

Sean