[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Accessing class constants from within a module?

Jos Backus

12/2/2004 4:01:00 AM

Any idea how I can access a class constant from within a module when that
module is include'd in the class? I.o.w. how do I make this work?

lizzy:~% cat m
module Debug
def debug(level, msg)
puts msg unless level > DEBUG # XXX DEBUG is wrong!
end
end

class C1
include Debug
DEBUG = 1
def foo
debug(1, "this is foo")
end
end

class C2
include Debug
DEBUG = 2
def bar
debug(1, "this is bar")
end
end

C1.new.foo
C2.new.bar
lizzy:~% ruby m
m:3:in `debug': uninitialized constant Debug::DEBUG (NameError)
from m:11:in `foo'
from m:23
lizzy:~%

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
_/ _/ _/
_/ _/_/_/
_/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'


6 Answers

Michael C. Libby

12/2/2004 4:57:00 AM

0

On Thu, 2004-12-02 at 13:00 +0900, Jos Backus wrote:
> Any idea how I can access a class constant from within a module when that
> module is include'd in the class? I.o.w. how do I make this work?
>
> lizzy:~% cat m
> module Debug
> def debug(level, msg)
> puts msg unless level > DEBUG # XXX DEBUG is wrong!
> end
> end
>
> class C1
> include Debug
> DEBUG = 1
> def foo
> debug(1, "this is foo")
> end
> end
>
> class C2
> include Debug
> DEBUG = 2
> def bar
> debug(1, "this is bar")
> end
> end
>
> C1.new.foo
> C2.new.bar
> lizzy:~% ruby m
> m:3:in `debug': uninitialized constant Debug::DEBUG (NameError)
> from m:11:in `foo'
> from m:23
> lizzy:~%
>

You probably don't want to do that anyway. If you change to Debug::DEBUG
in the class definitions, you'll be modifying a constant which can only
have one value at a time. You want two different values (and you can't
really tell the module to figure out which class constant is which
without a lot of headaches), so maybe just set it as a default instance
variable in your new objects?

Here is code that seems to do what you want:

# debug needs error checking in case @debug_level is nil
module Debug
def debug(level, msg)
puts msg unless level > @debug_level
end
end

class C1
include Debug
def initialize
@debug_level = 1
end
def foo
debug(1, "this is foo")
end
end

class C2
include Debug
def initialize
@debug_level = 2
end
def bar
debug(1, "this is bar")
end
end

C1.new.foo
C2.new.bar

-Michael Libby






Joel VanderWerf

12/2/2004 5:55:00 AM

0

Jos Backus wrote:
> Any idea how I can access a class constant from within a module when that
> module is include'd in the class? I.o.w. how do I make this work?

Use dynamic lookup, rather than lexical lookup:

> module Debug
> def debug(level, msg)
> puts msg unless level > DEBUG # XXX DEBUG is wrong!
puts msg unless level > self.class::DEBUG
> end
> end


Jos Backus

12/2/2004 7:21:00 AM

0

On Thu, Dec 02, 2004 at 01:56:49PM +0900, Michael C. Libby wrote:
> You probably don't want to do that anyway. If you change to Debug::DEBUG
> in the class definitions, you'll be modifying a constant which can only
> have one value at a time. You want two different values (and you can't
> really tell the module to figure out which class constant is which
> without a lot of headaches), so maybe just set it as a default instance
> variable in your new objects?

Joel's solution was what I was looking for originally (thanks Joel!) but your
solution admittedly works well too. Thanks for that, Michael.

Another approach I tried was using a class variable but that doesn't work
either, presumably because it is likewise trying to find @@debug in Debug, not
the including class:

lizzy:~% cat n
module Debug
def debug(level, msg)
puts msg unless level > @@debug
end
end

class C1
@@debug = 1
include Debug
def foo
debug(1, "this is foo")
end
end

class C2
@@debug = 1
include Debug
def bar
debug(2, "this is bar")
end
end

C1.new.foo
C2.new.bar
lizzy:~% ruby n
n:3:in `debug': uninitialized class variable @@debug in Debug (NameError)
from n:11:in `foo'
from n:23
lizzy:~%

Cheers,
--
Jos Backus _/ _/_/_/ Sunnyvale, CA
_/ _/ _/
_/ _/_/_/
_/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'


Jos Backus

12/2/2004 7:27:00 AM

0

On Thu, Dec 02, 2004 at 02:55:04PM +0900, Joel VanderWerf wrote:
> Jos Backus wrote:
> >Any idea how I can access a class constant from within a module when that
> >module is include'd in the class? I.o.w. how do I make this work?
>
> Use dynamic lookup, rather than lexical lookup:
>
> >module Debug
> > def debug(level, msg)
> > puts msg unless level > DEBUG # XXX DEBUG is wrong!
> puts msg unless level > self.class::DEBUG
> > end
> >end

It's things like these in Ruby that make my head spin :) But it does make
sense: at time of invocation we want to say either C1::DEBUG or C2::DEBUG,
depending on the invoking method. `::' can be preceded by any expression
yielding a class, in this case self.class. This evaluates to either C1 or C2,
as appropriate, and voila.

Thanks guys!

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
_/ _/ _/
_/ _/_/_/
_/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'


Michael C. Libby

12/2/2004 11:08:00 AM

0


On Thu, 2004-12-02 at 16:21 +0900, Jos Backus wrote:

> Joel's solution was what I was looking for originally (thanks
> Joel!) but your solution admittedly works well too. Thanks for
> that, Michael.

I like the self.class::CONSTANT expression better myself because it
keeps the object instances cleaner. I just didn't think it would be
thateasy and went for the first thing that might work that came to mind.

Next time I'm going to be thinking, "ok, I know Ruby has an
easier/faster/cleaner way to express this." :)

-Michael Libby



Jos Backus

12/2/2004 4:52:00 PM

0

On Thu, Dec 02, 2004 at 08:08:11PM +0900, Michael C. Libby wrote:
>
> On Thu, 2004-12-02 at 16:21 +0900, Jos Backus wrote:
>
> > Joel's solution was what I was looking for originally (thanks
> > Joel!) but your solution admittedly works well too. Thanks for
> > that, Michael.
>
> I like the self.class::CONSTANT expression better myself because it
> keeps the object instances cleaner. I just didn't think it would be
> thateasy and went for the first thing that might work that came to mind.

Your solution has the advantage that you can control debugging on a per-object
basis. Depending on the state of the object, while debugging, this can
sometimes be handy.

> Next time I'm going to be thinking, "ok, I know Ruby has an
> easier/faster/cleaner way to express this." :)

My words exactly :)

> -Michael Libby

Cheers,
--
Jos Backus _/ _/_/_/ Sunnyvale, CA
_/ _/ _/
_/ _/_/_/
_/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'