Why Are Constants from Extended Module Not Available in Class Methods Declared with Self

Why are constants from extended module not available in class methods declared with self.?

In Ruby, constant lookup is not the same as method lookup. For method lookup, calling foo is always the same as calling self.foo (assuming it isn't private). Calling a constant FOO is very different from self::FOO or singleton_class::FOO.

Using an unqualified constant (e.g. FOO) will do a lookup in the currently opened modules. A module is opened with module Mod, class Klass, class << obj, or module_eval and variants. When defining m1, these are B, and then B.singleton_class. When defining m2, only B is opened.

module Foo
X = 42
class Bar
def self.hello
X
end
end
end

In this code, Foo::Bar.hello will return 42, even though X is not a constant of Bar, its singleton class or ancestor. Also, if you later add a constant X to Bar, then that value will be returned. Finally, the following definition is not equivalent:

module Foo
X = 42
end

class Foo::Bar
def self.hello
X
end
end

Foo::Bar.hello # => uninitialized constant Foo::Bar::X

Indeed, when hello is defined, only the class Foo::Bar is opened, while in the previous example, both Foo and Foo::Bar where opened.

A last example, to show the difference an explicit scope can have with inheritance:

class Base
X = 42
def self.foo
X
end
def self.bar
self::X
end
end

class Parent < Base
X = :other
end

Parent.foo # => 42
Parent.bar # => :other

In your case, you probably want to include your module, instead of extending it, no?

Otherwise, you could use singleton_class::VAR, your code will work as you expect it.

module A
VAR = 'some_constant'
end

class B
extend A

class << self
def m1
puts singleton_class::VAR # not necessary here, as singleton_class is opened
end
end

def self.m2
puts singleton_class::VAR # necessary here!
end
end

B.m1 # => OK
B.m2 # => OK

(In Ruby) allowing mixed-in class methods access to class constants

This seems to work:

#! /usr/bin/env ruby

module CommonMethods
def shout_my_constant
puts self::Const.upcase
end
end

class NonInstantiableClass
Const = "hello, world!"
class << self
include CommonMethods
end
end

NonInstantiableClass.shout_my_constant

HTH

In Ruby, in a method defined in class self, why can't a constant defined on the superclass be access without self?

You have encountered a common Ruby gotcha - constant lookup.

The most important concept in constant lookup is Module.nesting (unlike in method lookup, where the primary starting point is self). This method gives you the current module nesting which is directly used by the Ruby interpreter when resolving the constant token. The only way to modify the nesting is to use keywords class and module and it only includes modules and classes for which you used that keyword:

class A
Module.nesting #=> [A]

class B
Module.nesting #=> [A::B, A]
end
end

class A::B
Module.nesting #=> [A::B] sic! no A
end

In meta programming, a module or class can be defined dynamically using Class.new or Module.new - this does not affect nesting and is an extremely common cause of bugs (ah, also worth mentioning - constants are defined on the first module of Module.nesting):

module A
B = Class.new do
VALUE = 1
end

C = Class.new do
VALUE = 2
end
end

A::B::VALUE #=> uninitialized constant A::B::VALUE
A::VALUE #=> 2

The above code will generate two warnings: one for double initialization of constant A::VALUE and a second for reassigning the constant.

If it looks like "I'd never do that" - this also applies to all the constants defined within RSpec.describe (which internally calls Class.new), so if you define a constant within your rspec tests, they are most certainly global (unless you explicitly stated the module it is to be defined in with self::)

Now let's get back to your code:

class SubExample < SuperExample
puts Module.nesting.inspect #=> [SubExample]

class << self
puts Module.nesting.inspect #=> [#<Class:SubExample>, SubExample]
end
end

When resolving the constant, the interpreter first iterates over all the modules in Module.nesting and searches this constant within that module. So if nesting is [A::B, A] and we're looking for the constant with token C, the interpreter will look for A::B::C first and then A::C.

However, in your example, that will fail in both cases :). Then the interpreter starts searching ancestors of the first (and only first) module in Module.nesting. SubrExample.singleton_class.ancestors gives you:

[
#<Class:SubExample>,
#<Class:SuperExample>,
#<Class:Object>,
#<Class:BasicObject>,
Class,
Module,
Object,
Kernel,
BasicObject
]

As you can see - there is no SuperExample module, only its singleton class - which is why constant lookup within class << self fails (print_constant_fails).

The ancestors of Subclass are:

[
SubExample,
SuperExample,
Object,
Kernel,
BasicObject
]

We have SuperExample there, so the interpreter will manage to find SuperExample::A_CONSTANT within this nesting.

We're left with print_constant_works_2. This is an instance method on a singleton class, so self within this method is just SubExample. So, we're looking for SubExample::A_CONSTANT - constant lookup firstly searches on SubExample and, when that fails, on all its ancestors, including SuperExample.

self.included – including class methods from a module in Ruby

What's the difference between the two examples?

The first code block adds the class methods in ClassMethods to the including class and calls the scope method on it as well. The second one does neither of these things and will result in a NoMethodError because the module has no scope class method. self.some_class_method will not be available on the including class once the module is included.

For the full story on how module inclusion works in Ruby, read my answer here:

Inheriting class methods from modules / mixins in Ruby

What's the point of self.included if a module's sole purpose is to be included?

Inclusion is not the only purpose of modules. They are also used for other things such as namespacing or simply storing various class methods that are then callable on the module itself.

Why doesn't Ruby include class methods automatically?

Theoretically Ruby could automatically add all class methods defined in a module to the including class, but in practice that would be a bad idea, because you would not get to choose anymore whether you want to include class methods — all class methods would be included every time, whether or not they are intended to be included. Consider this example:

module M
def self.class_method
"foo"
end

def self.configure_module
# add configuration for this module
end
end

class C
include M
end

Here, the configure_module method is obviously not supposed to be added to C, as its purpose is to set the configuration for the module object. Yet, if we had auto-inclusion for class methods, you would not be able to prevent it from being included.

But all instance methods are already included! How is that okay then?

Instance methods in a module are only really useful if they are included into a class, since modules cannot have instances, only classes can. So in a module every instance method is expected to be included somewhere to work.

A "class" method on a module is different, because it can be called on the module itself, so it can be used just fine regardless of whether it's also added to the including class. That is why it is better that you have a choice there.

Cython's Extension module's class's methods not visible/give a name Error when mentioned

Here is a simple example to help you get started with cython classes. First, I create my setup.py file, which I use to compile my cython .pyx file by calling python setup.py build_ext --inplace.

from distutils.core import setup
from Cython.Build import cythonize
from distutils.core import Extension

extensions = [
Extension("mylist", sources=["mylist.pyx"], libraries=[], extra_compile_args=["-w"]),
]
setup(
ext_modules = cythonize(extensions)
)

Next, I would write up a .pxd file. Like I mentioned in the comments, this is basically a header file that defines all of the "c-side" class properties and methods that you want to access that were defined with cdef or cpdef. An example mylist.pxd would look like this:

cdef class MyList:
cdef public list _base_list
cpdef append(self, object item)
cpdef pop(self, int index=*)#Note: * is used in place of default values
cpdef get_data(self)

Now we are ready to create our mylist.pyx file that actually does the work. To keep things simple, I will implement our cython list using python lists (which is pretty nonsensical performance-wise but will avoid the need to delve into arrays, which are a little trickier). The code might look like this:

cdef class MyList:

def __cinit__(self):#__cinit__ is preferred for cdef class constructors
self._base_list = []

cpdef append(self, object item):
self._base_list = self._base_list + [item]

cpdef pop(self, int index=-1):
self._base_list.pop(index)

cpdef get_data(self):
return self._base_list

Once this is all compiled, you can use this silly MyList class in python. Here is MyList in action in a main.py file:

from mylist import MyList

a = MyList()
a.append("apple")
a.append("banana")
a.append("tomato")
a.append("pear")
a.pop(2)#one of these fruit is not like the others...
print a.get_data()

Let me know if you are having issues compiling or running this example. I tested this on my laptop using Python 2.7 and the latest Cython master (version 0.26b0).

Ruby module include, can't access included methods, only constants

The following is a common way to mix a module containing constants, instance methods, and class methods into a class, but it can also be used to include constants and class methods of one module in another module, which is what you want to do. It uses the "callback" or "hook" method Module#included. Object#extend adds the instance methods in the module that is the argument to the module that is extend's receiver. Below it makes the instance methods (here just one) in Public::C_Meths class methods in the module Child.

module Parent
module I_Meths
PARENT_CONST = 'parent const'
end

module C_Meths
def cmeth
'cmeth'
end
end

def self.included(mod)
mod.include(I_Meths)
mod.extend(C_Meths)
end
end

module Child
include Parent
end

Child::PARENT_CONST
#=> "parent const"
Child.cmeth
#=> "cmeth"

It's more common to use this construct to mix a module containing constraints, instance methods and class methods into a class.

Suppose we were to add the instance method:

def imeth
'imeth'
end

to the module Parent::I_Meths and include Parent in a class:

class A
include Parent
end

then

A::PARENT_CONST
#=> "parent const"
A.cmeth
#=> "cmeth"
A.new.imeth
#=> "imeth"

Class instance variable initialize in extended module

You could move the variable initialization into the included callback:

module MyModule
def self.included(base)
base.extend ClassMethods
base.include InstanceMethods
base.count = 0
end

module ClassMethods
attr_accessor :count
end

module InstanceMethods
def register
self.class.count += 1
end
end
end

Scope of Constants in Ruby Modules

The USER_KEY you declared (even conditionally) in Auth is globally known as Auth::USER_KEY. It doesn't get "mixed in" to including modules, though including modules can reference the key in a non-fully-qualified fashion.

If you want each including module (e.g. ApplicationController) to be able to define its own USER_KEY, try this:

module Auth
DEFAULT_USER_KEY = 'user'
def self.included(base)
unless base.const_defined?(:USER_KEY)
base.const_set :USER_KEY, Auth::DEFAULT_USER_KEY
end
end
def authorize
user_id = session[self.class.const_get(:USER_KEY)]
end
end

class ApplicationController < ActionController::Base
USER_KEY = 'my_user'
include Auth
end

If you're going to go to all this trouble, though, you might as well just make it a class method:

module Auth
DEFAULT_USER_KEY = 'user'
def self.included(base)
base.extend Auth::ClassMethods
base.send :include, Auth::InstanceMethods
end
module ClassMethods
def user_key
Auth::DEFAULT_USER_KEY
end
end
module InstanceMethods
def authorize
user_id = session[self.class.user_key]
end
end
end

class ApplicationController < ActionController::Base
def self.user_key
'my_user'
end
end

or a class-level accessor:

module Auth
DEFAULT_USER_KEY = 'user'
def self.included(base)
base.send :attr_accessor :user_key unless base.respond_to?(:user_key=)
base.user_key ||= Auth::DEFAULT_USER_KEY
end
def authorize
user_id = session[self.class.user_key]
end
end

class ApplicationController < ActionController::Base
include Auth
self.user_key = 'my_user'
end

Why are constants declared inside an array, and assigned to other constants, accessible as Class constants in Ruby?

First, what happens when the following code is executed:

PARENTS = [
FATHER = :father,
MOTHER = :mother
]
  • PARENTS = ... attempts to set the constant PARENTS. But in order to do so, it has to evaluate the right-hand side of the assignment:

    • [...] attempts to create an array. But in order to do so, it has to evaluate its arguments:

      • FATHER = :father sets the constant FATHER to :father. The result of this assignment is :father which becomes the first argument.
      • MOTHER = :mother sets the constant MOTHER to :mother. The result of this assignment is :mother which becomes the second argument.

So in chronological order:

  1. The constant FATHER is set to :father
  2. The constant MOTHER is set to :mother
  3. An array with elements :father and :mother is created
  4. The constant PARENTS is set to that array

Your code is equivalent to:

FATHER = :father
MOTHER = :mother
PARENTS = [FATHER, MOTHER] # or [:father, :mother]

By declaring the constants inside of an array, I would expect them to to be scoped inside the array. Please cite the relevant docs in your answer.

You can use Module.nesting to determine the current nesting, i.e. where a constant will be defined in: (more examples in the docs)

class Example
p outer_nesting: Module.nesting
PARENTS = [
p(inner_nesting: Module.nesting)
]
end

Output:

{:outer_nesting=>[Example]}
{:inner_nesting=>[Example]}

As you can see, an array literal doesn't affect the current nesting. Constants in both locations will be defined under Example.

If you really wanted to declare the constants "inside" the array (i.e. inside the array's singleton class), you could do some like this:

class Example
PARENTS = []
class << PARENTS
FATHER = :father
MOTHER = :mother
PARENTS.push(FATHER, MOTHER)
end
end

p Example.constants #=> [:PARENTS]
p Example::PARENTS.singleton_class.constants #=> [:FATHER, :MOTHER]

The above is just for demonstration purposes, there's no need to actually do that.

Rails: Use constants from model for define instance methods into Concern

You can use self.included hook to get a reference to the including class at include time.

module StatesHelper
extend ActiveSupport::Concern

def self.included(base)
base::STATES.each do |state|
define_method "#{state}?" do
self.state == state
end
end
end
end

class Item
STATES = %w(active disabled).freeze
include StatesHelper
end

item = Item.new
item.respond_to?(:active?) # => true
item.respond_to?(:disabled?) # => true


Related Topics



Leave a reply



Submit