Ruby: Class C Includes Module M; Including Module N in M Does Not Affect C. What Gives

Ruby: class C includes module M; including module N in M does not affect C. What gives?

In writing my question, inevitably, I came across an answer. Here's what I came up with. Let me know if I missed an obvious, much simpler solution.

The problem seems to be that a module inclusion flattens the ancestors of the included module, and includes that. Thus, method lookup is not fully dynamic, the ancestor chain of included modules is never inspected.

In practice, Array knows Enumerable is an ancestor, but it doesn't care about what's currently included in Enumerable.

The good thing is that you can include modules again, and it'll recompute the module ancestor chain, and include the entire thing. So, after defining and including Narf, you can reopen Array and include Enumerable again, and it'll get Narf too.

class Array
include Enumerable
end
p Array.ancestors
# => [Array, Enumerable, Narf, Object, Kernel]

Now let's generalize that:

# Narf here again just to make this example self-contained
module Narf
def narf?
puts "(from #{self.class}) ZORT!"
end
end

# THIS IS THE IMPORTANT BIT
# Imbue provices the magic we need
class Module
def imbue m
include m
# now that self includes m, find classes that previously
# included self and include it again, so as to cause them
# to also include m
ObjectSpace.each_object(Class) do |k|
k.send :include, self if k.include? self
end
end
end

# imbue will force Narf down on every existing Enumerable
module Enumerable
imbue Narf
end

# Behold!
p Array.ancestors
Array.new.narf?
# => [Array, Enumerable, Narf, Object, Kernel]
# => (from Array) ZORT!

Now on GitHub and Gemcutter for extra fun.

Inheriting class methods from modules / mixins in Ruby

A common idiom is to use included hook and inject class methods from there.

module Foo
def self.included base
base.send :include, InstanceMethods
base.extend ClassMethods
end

module InstanceMethods
def bar1
'bar1'
end
end

module ClassMethods
def bar2
'bar2'
end
end
end

class Test
include Foo
end

Test.new.bar1 # => "bar1"
Test.bar2 # => "bar2"

How to expose included private methods as public class methods?

It seems like the instance methods on FileUtils are all private (as mentioned in another answer here, that means they can only be called without an explicit receiver). And what you get when you include or extend is the instance methods. For example:

require 'fileutils'

class A
include FileUtils
end
A.new.pwd #=> NoMethodError: private method `pwd' called for #<A:0x0000000150e5a0>

o = Object.new
o.extend FileUtils
o.pwd #=> NoMethodError: private method `pwd' called for #<Object:0x00000001514068>

It turns out all the methods we want on FileUtils are there twice, as private instance methods and also as public class methods (aka singleton methods).

Based on this answer I came up with this code which basically copies all the class methods from FileUtils to FileManager:

require 'fileutils'

module FileManager
class << self
FileUtils.singleton_methods.each do |m|
define_method m, FileUtils.method(m).to_proc
end
end
end

FileManager.pwd #=> "/home/scott"

It's not pretty, but it does the job (as far as I can tell).

Add class to ruby module in runtime

This question is concerned specifically with adding a class at runtime. The class is to be created within an existing module, but, as will be seen, that is almost incidental and is of questionable utility.

Adding a class to a module at runtime

To assist in the construction of classes within a given module at runtime we might construct a method class_factory.

def class_factory(mod, class_name, consts, meths, instance_meths,
accessors)
class_obj = mod.const_set(class_name, Class.new)
consts.each { |const,val| class_obj.const_set(const,val) }
meths.each do |name,body|
class_obj.singleton_class.
instance_eval("define_method(:#{name}) #{body}")
end
instance_meths.each do |name,body|
class_obj.instance_eval("define_method(:#{name}) #{body}")
end
accessors.each do |accessor,inst_var|
class_obj.public_send(accessor, inst_var)
end
class_obj
end

Let's try it.

module M
end

class_obj = class_factory(
M,
"B",
{ 'A'=>7, 'D'=>'cat' },
{ greeting: '{ |n| "Cat\'s have #{n} lives" }' },
{ initialize: '{ |name| @name = name }',
say_name: '{ "My name is #{@name}" }' },
{ attr_accessor: "name" }
)
#=> M::B

class_obj == M::B
#=> true
M::B.constants
#=> [:A, :D]
class_obj.methods(false)
#=> [:greeting]
M::B.instance_methods(false)
#=> [:say_name, :name=, :name]
class_obj.greeting(9)
#=> "Cat's have 9 lives"
M::B.greeting(5)
#=> "Cat's have 5 lives"

instance = M::B.new "Lola" # or class_obj.new "Lola"
#=> #<M::B:0x000056cb6e766840 @name="Lola">
instance.say_name
#=> "My name is Lola"
instance.name
#=> "Lola"
instance.name = "Lo"
#=> "Lo"
instance.name
#=> "Lo"

It could be that your code may contain static expressions such as these, and the only dynamic part is the construction of the class.

On the other hand, the class may be used dynamically as well. For example:

mod = "M"
cl = "B"
name = "Lola"
meth = "say_name"

Then:

Object.const_get("#{mod}::#{cl}").new(name).public_send(meth)
#=> "My name is Lola"

or

class_obj.new(name).public_send(meth)
#=> "My name is Lola"

How best to reference dynamically-created classes

We have just seen various ways to reference a dynamically-created class. Depending on requirements, M::B versus class_obj and Object.const_get("#{mod}::#{cl}") versus class_obj. Clearly, the use of class_obj is simplest in both cases and has the additional advantage that references to class_obj need not be changed if, in future, M or B in M::B are changed.

Are the advantages to creating classes dynamically that are members of a module?

Recall that the main reason to create a class within a module is create a namespace, so that, for example, M1::C and M2::C do not create a name conflict. However, if we reference a dynamically-created class by its (unique) object (rather than its name, a constant) that is held by a variable (here class_obj) there is no need for the namespace. So the answer to the question I posed in this section is "no".

Moreover, if we reference a dynamically-created class by its object, there is no reason to assign a name to the class. We therefore could modify class_factory as follows:

def class_factory(consts, meths, instance_meths, accessors)
Class.new do
consts.each { |const,val| const_set(const,val) }
meths.each do |name,body|
singleton_class.
instance_eval("define_method(:#{name}) #{body}")
end
instance_meths.each do |name,body|
instance_eval("define_method(:#{name}) #{body}")
end
accessors.each do |accessor,inst_var|
public_send(accessor, inst_var)
end
end
end

class_obj = class_factory(
{ 'A'=>7, 'D'=>'cat' },
{ greeting: '{ |n| "Cat\'s have #{n} lives" }' },
{ initialize: '{ |name| @name = name }',
say_name: '{ "My name is #{@name}" }' },
{ attr_accessor: "name" }
)
#=> #<Class:0x000056cb6eaeefd0>

The object held by class_obj is called an anonymous class because it has no name (that is a constant).

class_obj.constants
#=> [:A, :D]
class_obj.methods(false)
#=> [:greeting]
class_obj.instance_methods(false)
#=> [:say_name, :name=, :name]

instance = class_obj.new "Billy-Bob"
#=> #<#<Class:0x000056cb6eaeefd0>:
# 0x000056cb6eb183d0 @name="Billy-Bob">
instance.say_name
#=> "My name is Billy-Bob"
instance.name
#=> "Billy-Bob"
instance.name = "BB"
#=> "BB"

Method-lookup path for Ruby

You can use ancestor reflection:

class C
def report
my_ancestors = self.class.ancestors
puts "my ancestors are: #{my_ancestors}"
method = my_ancestors[2].instance_method(:report)
method.bind(self).call
end
end

C.new.report
=> my ancestors are: [C, N, M, Object, PP::ObjectMixin, Kernel, BasicObject]
=> 'report' method in module M

Calling Ruby class methods from C++

First off, go is, as you've defined it, not a class method, but an instance method.

As an object oriented language, all ruby methods require a receiver, that is, an object that the method is invoked on. For instance methods, the receiver is an instance of the class, for class methods, the receiver is the class object itself.

The ? placeholder you have is the slot for the receiver of the method call.

If you want to leave it as an instance method, then you need to do this:

rb_funcall(a_CallTest_instance, rb_intern("go"), 0);

where a_CallTest_instance was an instance of CallTest you created using rb_class_new_instance().

If you make it into a class method:

class CallTest
def self.go
# ...
end
end

Then you need to use the CallTest class itself as the receiver:

rb_funcall(klass, rb_intern("go"), 0);

You can get a reference to the CallTest class using rb_const_get()

VALUE klass = rb_const_get(rb_cObject, rb_intern('CallTest'));

Use rb_cObject there, since CallTest is defined in the global context.

I'd suggest reading the chapter in the Pickaxe about extending ruby.

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.

Ruby: Raise error in Module if class method not found

Sounds like you want to make use of method_missing and define_method.

If you do use method_missing don't forget to:

  • call super for unhandled cases.
  • also implement a respond_to? method

look at this question, plus this and that.

Update:

It sounds the goal is to do static method checking like Java or c++ does. This is not really meaningful in ruby :-(

Since in ruby:

  • Each instance of an object has its own eigenclass. A given object may have the necessary methods mixed in at runtime. So just because Foo does not have a method at class load time is meaningless.
  • Frameworks like RoR hooks method_missing and dynamically create methods needed for the database query methods, so the method may exist (or not) when it is needed.

With regards to "class on load": A class definition is really executed. Try this:

class Foo 
p "Hi"
end

You will see "Hi" the first and only the first time Foo is used. This is how things like devise hook into do their magic.

class User < ActiveRecord::Base
# **CALL 'devise' method**
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable

# **CALL attr_accessible method**
attr_accessible :email, :password, :password_confirmation
end

So maybe by private convention have developers add a check_class method call to the bottom of the classes in question?

I understand the intent but it seems like fighting the way ruby is designed to work.

As a mostly Java person I appreciate the frustration. Let me guess: repeated cases of code getting pushed to production that had missing methods? :-P

Update2:

wrt onload In ruby barring use of frozen a class get new methods defined all the time. ( Or an instance can get new methods defined just for that instance. ) so checking for a method's nonexistence is only a snapshot check and not as definitive a check as a static language brings to the table. This is ruby's very own Halting problem

Is extend self the same as module_function?

module_function makes the given instance methods private, then duplicates and puts them into the module's metaclass as public methods. extend self adds all instance methods to the module's singleton, leaving their visibilities unchanged.

module M
extend self

def a; end

private
def b; end
end

module N
def c; end

private
def d; end

module_function :c, :d
end

class O
include M
include N
end

M.a
M.b # NoMethodError: private method `b' called for M:Module
N.c
N.d
O.new.a
O.new.b # NoMethodError: private method `b' called for O
O.new.c # NoMethodError: private method `c' called for O
O.new.d # NoMethodError: private method `d' called for O


Related Topics



Leave a reply



Submit