I can't understand why accessing module's class variable fails in the following example:
module M
@@xyz = 123
end
M.class_variables # [:@@xyz]
M.class_variable_get :@@xyz # 123 , so far so good
class C
extend M
end
C.singleton_class.class_variables # [:@@xyz]
C.singleton_class.class_variable_get :@@xyz # NameError:
# uninitialized class variable @@xyz in Class
Can anybody explain why the class variable @@xyz
is suddenly inacessible/undefined in C
's singleton class?
Update: I re-tested the above code with different Ruby YARV versions and find it as a regression in the latest.
Update 2:
There was a change in definition of Module#class_variables
method in latest Ruby generation.
Ruby up to 1.9.3 the definition is
class_variables → array
Returns an array of the names of class variables in mod.
Ruby 2.0.0 latest stable version
class_variables(inherit=true) → array
Returns an array of the names of class variables in mod. This includes the names of class variables in any included modules, unless the inherit parameter is set to false.
So in latest Ruby incarnation, class_variables
returns by default also class variables of included modules. Just curious what's this feature for or if it still does concern modules "included" with include
and not extend
.
Can anybody explain ?
Extend is also used to importing module code but extends import them as class methods. Ruby will throw an error when we try to access methods of import module with the instance of the class because the module gets import to the superclass just as the instance of the extended module.
The only difference is where in the ancestor chain the module is added. With include , the module is added after the class in the ancestor chain. With prepend, the module is added before the class in the ancestor chain.
You can include a module in a class in your Rails project by using the include keyword followed by the name of your module.
module_function(*args) private. Creates module functions for the named methods. These functions may be called with the module as a receiver, and also become available as instance methods to classes that mix in the module. Module functions are copies of the original, and so may be changed independently.
Not sure if either of these are an answer, but I did find these
C::M.class_variables #=> ["@@xyz"]
# (but gives "warning: toplevel constant M referenced by C::M")
and
class D
include M
end
D.class_variables #=> ["@@xyz"]
(This from Ruby 1.8.7, don't have a later version to hand right now).
include
causes the module's instance methods to become instance methods of the class. According to Pickaxe, "It's almost as if the module becomes a superclass of the class that uses it".
Meanwhile, extend
is intend to add a module's methods to an object; when called in a class definition it's equivalent to self.extend
. It seems that they're not equivalent.
HTH.
This is not answer, just some comments to the question.
If we include module M
in class C
, C
gets class variables define in M
:
module M
@@xyz = 123
end
class C
include M
end
C.class_variables #=> [:@@xyz]
C.class_variable_get(:@@xyz) # 123
To call extend M
in class definition is equivalant as to call include M
in eigen class (or singleton class) of that class.
module M
@@xyz = 123
end
eigenclass = class C
class << self
include M
self
end
end
eigenclass.class_variables #=>[:@@xyz]
eigenclass.class_variable_get(:@@xyz) #=>NameError: uninitialized class variable @@xyz in Class
It seems the difference lies on that Ruby treat normal classes and eigen classes differently.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With