Simple ruby language question

ok, i've got some module and it has some instance variables i want to
be set by the classes extending the module, and aparently i'm not doing
this correctly:

module A
  def test
    raise 'ARG' if !@blah
    @blah
  end
end

class B
  include A
  extend A
  @blah = 'YES!'
end

irb(main):025:0> b = B.new
=> #<B:0x136376c>
irb(main):026:0> b.test
RuntimeError: ARG
        from (irb):9:in `test'
        from (irb):26

can anyone tell me what the syntax should be? how do i set @blah in the
B class so that its available to the test method

Hi --

ok, i've got some module and it has some instance variables i want to
be set by the classes extending the module, and aparently i'm not doing
this correctly:

module A
def test
   raise 'ARG' if !@blah
   @blah
end
end

class B
include A
extend A
@blah = 'YES!'
end

irb(main):025:0> b = B.new
=> #<B:0x136376c>
irb(main):026:0> b.test
RuntimeError: ARG
       from (irb):9:in `test'
       from (irb):26

can anyone tell me what the syntax should be? how do i set @blah in the
B class so that its available to the test method

When using instance variables, you have to match each one precisely to
the object whose instance variable it is. The @blah in @blah = 'YES!'
belongs to the class object B. The @blah inside test belongs (or will
belong, upon execution) to whatever object is calling "test". Unless
that object is the class object B, its @blah will be different (even
if it's an instance of B).

So if you want them to match up, you have to call test on the class
object B:

   B.test

That will run "test" with B as the receiver, so you'll see B's
instance variable @blah. (By the way, it's a good idea not to name
your test methods "test", because there's already a method with that
name in Kernel, so sometimes you'll get behavior you don't expect.
That's not the issue here, though.)

David

···

On Mon, 20 Mar 2006, MichaelEconomy@gmail.com wrote:

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! Ruby for Rails

In class B, you are attepmting to use an instance variable as if it
were a class variable. To set @blah to a value when its instantiated,
you'll need to stick that line in the constructor:

class B
  include A
  extend A

  def initialize
    @blah = 'YES!'
  end
end

Also, you dont need to both include and extend A inside B. Use extend
when you want to use the modules methods as class methods:

module X
  def classy
    puts "Yup, I'm classy"
  end
end

class Y
  extend X
end

Y.classy
=> Yup, I'm classy

You can also extend an instance of an object:

s = "Holy shniekes"
s.extend(X)
s.classy
=> Yup, I'm classy

Use include when you want to "mix-in" the modules methods with the
instance methods defined in the class:

module X
  def classy
    puts "Yup, I'm classy"
  end
end

class Y
  include X
end

Y.new.classy
=> Yup, I'm classy

Hope that helps :slight_smile:

- Scott

MichaelEconomy@gmail.com wrote:

ok, i've got some module and it has some instance variables i want to
be set by the classes extending the module, and aparently i'm not doing
this correctly:

module A
  def test
    raise 'ARG' if !@blah
    @blah
  end
end

class B
  include A
  extend A
  @blah = 'YES!'
end

irb(main):025:0> b = B.new
=> #<B:0x136376c>
irb(main):026:0> b.test
RuntimeError: ARG
        from (irb):9:in `test'
        from (irb):26

can anyone tell me what the syntax should be? how do i set @blah in the
B class so that its available to the test method

Try this one:

module A
   def test
     raise 'ARG' if !@blah
     @blah
   end
end

class B
   include A

   def initialize
     @blah = 'YES!'
   end
end

b = B.new
p b.test

Module#include will make module methods to become instance ones. Object#extend adds methods to an instance (to the class B in this case, you could say then B.test)

consider also:

class A
     @a=4
end

p A.class_eval{@a}
=> 4

which means that @a is an instance variable of class object, not an instance variable of class instance.

lopex

Marcin Mielżyński wrote:

It can be easily seen who is the default receiver (class object or instance object) by doing this:

class A
     p self

     def initialize
         p self
     end
end

A.new

lopex

Marcin Mielżyński wrote:

module A
  def test
    raise 'ARG' if !@blah
    @blah
  end
end

class B
  include A

  def initialize
    @blah = 'YES!'
  end
end

b = B.new
p b.test

You can even automate this with proper use of initializers:

module A
   def initialize(*a,&b)
     super
     @blah = "set"
   end

   def test
     raise 'ARG' if !@blah
     @blah
   end
end

class B
   include A
end

class C
   include A

   def initialize(x)
     super()
     @another_member = x
   end
end

>> B.new.test
=> "set"
>> C.new(1).test
=> "set"

Module#include will make module methods to become instance ones. Object#extend adds methods to an instance (to the class B in this case, you could say then B.test)

Adding to that, usually the OP should decide whether to do one or another.

Kind regards

  robert