From: dblack@... Date: 2006-10-12T04:06:18+09:00 Subject: Re: Singleton Class Constants Hi -- On Thu, 12 Oct 2006, jdance@gmail.com wrote: > David Black wrote in Ruby For Rails (page 341): > >> (There's also a subtle difference between these two approaches to >> defining a singleton method, involving the scope of constants, but that's an >> arcane point. For the most part, you can treat them as equivalent.) For the answer to your last question: > What is the "arcane point" about singleton methods and constants? see the recent thread on '"def self.method" vs "class << self; def method"'. (It's the example with the top-level vs. class-specific contants.) > The subject of singleton methods and constants has recently gotten me > into trouble. Here is a simplified example: > > module ExtendMeFirst > BAR = 3 > end > > module ExtendMeSecond > def print_bar > puts BAR > end > end > > class A > extend ExtendMeFirst > extend ExtendMeSecond > end > > A.print_bar #=> NameError: uninitialized constant ExtendMeSecond::BAR > > Now, I somewhat understand why this doesn't work - the constants are in > different scopes. The challenge is to get around this problem and use > the constant BAR from ExtendMeFirst in module ExtendMeSecond. We > discovered that what we needed to was access the singleton class's > constants, but there is basically no easy way to do this, since there > is no "singleton_class" method in Object/Kernel (which has been > discussed a long time ago on this list). We eventually added one: > > class Object > def singleton_class > class << self; self; end > end > end > > And then doing this allowed us to get to the constant: > > module ExtendMeSecond > def print_bar > puts singleton_class::BAR > end > end > > Is there a better way to do this? I don't think there's any way that doesn't involve some kind of coupling, since you're basically printing one module's constant from another module (using "module" as class-or-module). The way you've done it presupposes that ExtendMeSecond will indeed be mixed in to a singleton class subsequent to the mixing in of ExtendMeFirst. You could, instead, cut out one leg of the journey and just say: def print_bar puts ExtendMeFirst::BAR end which is a different kind of coupling, but really isn't inherently worse than calling Math::PI or any other constant from another module. David -- David A. Black | dblack@wobblini.net Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3] DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4] [1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com [2] http://dablog.rubypal.com | [4] http://www.rubycentral.org