Expected to Define. When Calling Class Inside a Module

Expected to define. When calling class inside a module

I had the same problem. It comes from the fact that you try to load /lib/blog/core/search/base.rb directly in application.rb with /lib/**/

Error I had:

Expected /[...]/myapp/lib/durative/base.rb to define Base (LoadError)

Directory structure:

lib/
--durative/
--base.rb

base.rb:

module Durative
class Base
def initialize(config)
@config = {}
end
#...
end
end

application.rb:

config.autoload_paths += Dir["#{config.root}/lib/**/"]

Here are the changes I made to make it work

Directory structure:

lib/
--durative.rb **(added)**
--durative/
--base.rb

durative.rb:

require 'durative/base'

base.rb (no change)

application.rb (changed):

config.autoload_paths += Dir["#{config.root}/lib/"]

Tell us if it worked for you too.

Why can't ruby classes inside modules have the same scope as regular classes?


I have a module with a class inside,

No, you don't. You have a module definition with a class definition inside, but that does not make the class a nested class. Ruby does not have nested classes.

Ruby is not Beta, Scala, or Newspeak, there are no nested classes in Ruby.

Nesting a module or class definition inside another module or class definition does not create nesting relationship between the two classes / modules. It only makes the constant which references the class / module part of the outer class' / module's namespace.

In other words, there is no difference between

module Foo
class Bar
end
end

and

class Quux
end

module Foo
Bar = Quux
end

Only the constant is nested, but not the object that is referenced by the constant.

but I find that the class inside can't reach any of the methods in the enclosing module without specifying the module path.

That is precisely because there is no "enclosing module". There is a lexically enclosing module definition but that does not create any form of relationship whatsoever between the Foo class and the MyMod module.

Another way to look at it is that the module_function doesn't seem to carry into the class.

I honestly don't understand what you mean by that, what it means for a method to "carry into a class", but Module#module_function is not magic. It does exactly what the documentation says it does: it takes an instance method of the module, copies it as an instance method of the singleton class of the module, and makes the original instance method private.

You can read its specification in the Ruby/Spec, it is fairly simple. Also, the Rubinius source code, both the basic version for booting the Rubinius kernel and the full version are fairly readable.

In the end, Module#module_function really does not do much more than

class Module
def module_function(*meths)
meths.each do |meth|
define_singleton_method(meth, &instance_method(meth).bind(self))
private meth
end

self
end
end

If you run this, you get an error on the "But I can't..." line of:

undefined local variable or method `meaning'

The reason is simple: neither the class Foo nor any of its superclasses has any method of that name, so of course you get an exception.

But if you remove the MyMod bits around the whole file, it has no problem accessing the outer method.

There is no "outer method". Ruby does not have Beta-like nested classes. That is really the fundamental cause of your misunderstanding. You expect Ruby to behave like Beta, but it just doesn't. Ruby takes inspiration from any languages, most notably (in rough order of importance) Smalltalk, Lisp, Perl, and Clu, but Beta is not among them.

This here works for a completely different reason:

def meaning
42
end

class Foo
def initialize
meaning
end
end

Methods that are defined at the top-level are implicitly defined as private instance methods of Object. This is because the default definee at the top-level is ::Object. Since Foo inherits from Object, method lookup will eventually find the meaning method defined in Object.

Is there an easy way to make these accessible without having to give the full path?

Inheritance. For example, Module#append_features, which is called by Module#include, makes the module the superclass of the including class, and thus all instance methods of the module become part of the method lookup ancestry chain.

An aside: if there is no nesting, then what does Module::nesting do? Well, yeah, that is an unfortunately named method. The term "nested class" or "nested module" has a well-defined meaning in OO going all the way back to Beta. But this method is about a completely different kind of nesting:

It refers to the lexical nesting of module definitions, and not to nesting of modules themselves.

For example, these module definitions all define the exact same module, but the definition text has different nesting:

module Foo
module Bar
module Baz
module Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar::Baz, Foo::Bar, Foo]
end
end
end
end

module Foo
module Bar
module Baz::Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar, Foo]
end
end
end

module Foo
module Bar::Baz
module Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar::Baz, Foo]
end
end
end

module Foo::Bar
module Baz
module Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar::Baz, Foo::Bar]
end
end
end

module Foo
module Bar::Baz::Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo]
end
end

module Foo::Bar::Baz
module Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar::Baz]
end
end

module Foo::Bar
module Baz::Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux, Foo::Bar]
end
end

module Foo::Bar::Baz::Qux
p Module.nesting
#=> [Foo::Bar::Baz::Qux]
end

Again, this is purely lexical nesting of the module definition. The module itself is not nested; the module itself is the same in all of these cases. This nesting only affects constant lookup.

Constants are looked up first lexically outwards in enclosing module definitions, then upwards the inheritance chain.

There is another instance where things can be nested: blocks create nested lexical scopes, whereas all other lexical scopes (script, module / class definition, and method definition) don't nest. In other words, blocks and only blocks have access to the local variables (and self) of their enclosing lexical scopes.

Is it possible to call a Module function from inside a class that is also in that module

In order to invoke M::helper you need to define it as def self.helper; end
For the sake of comparison, take a look at helper and helper2 in the following modified snippet

module M
class C < Struct.new(:param)
include M # include module to get helper2 mixed in
def work
M::helper(param)
helper2(param)
end
end

def self.helper(param)
puts "hello #{param}"
end

def helper2(param)
puts "Mixed in hello #{param}"
end
end

c = M::C.new("world")
c.work

Testing a ruby module class method not working

Reading the reference in this article which explains include, extend, and prepend and I found out that extends works with the Singleton class already so the self is unnecesary.

I made a small test with this code, which removes the self in the definition

module SomeModule
module Account
def account_info
raise NotImplementedError
end
end
end

class MockClass
extend SomeModule::Account
end

MockClass.account_info

And that raises NotImplementedError

When to use nested classes and classes nested in modules?

Other OOP languages have inner classes which cannot be instantiated without being bound to an upper level class. For instance, in Java,

class Car {
class Wheel { }
}

only methods in the Car class can create Wheels.

Ruby doesn’t have that behaviour.

In Ruby,

class Car
class Wheel
end
end

differs from

class Car
end

class Wheel
end

only in the name of the class Wheel vs. Car::Wheel. This difference in name can make explicit to programmers that the Car::Wheel class can only represent a car wheel, as opposed to a general wheel. Nesting class definitions in Ruby is a matter of preference, but it serves a purpose in the sense that it more strongly enforces a contract between the two classes and in doing so conveys more information about them and their uses.

But to the Ruby interpreter, it’s only a difference in name.

As for your second observation, classes nested inside of modules are generally used to namespace the classes. For instance:

module ActiveRecord
class Base
end
end

differs from

module ActionMailer
class Base
end
end

Although this is not the only use of classes nested inside of modules, it is generally the most common.

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.

Ruby: Is it possible to define a class method in a module?


module Common
def foo
puts 'foo'
end
end

class A
extend Common
end

class B
extend Common
end

class C
extend Common
end

A.foo

Or, you can extend the classes afterwards:

class A
end

class B
end

class C
end

[A, B, C].each do |klass|
klass.extend Common
end


Related Topics



Leave a reply



Submit