Understanding the `include` statement behavior for "subsequent" mixin modules - ruby-on-rails

I am trying to understand the include statement behavior when used in multiple Mixins. That is, I have these statements:
class Article < ActiveRecord::Base
include DoubleIncludedModule
include AModule
# ...
end
module AModule
include DoubleIncludedModule
# ...
end
module DoubleIncludedModule
# ...
end
How many times will be the DoubleIncludedModule included in the Article class? That is, since the "subsequent" inclusion of the DoubleIncludedModule (first in the Article class and then in AModule included by the Article class itself), will be the "double inclusion" issue automatically handled by Ruby or will the DoubleIncludedModule (wrongly) included two times?
Of course, I would like to include the DoubleIncludedModule module only one time. How can I make that (maybe by using some Ruby on Rails methods) the proper way?

I'll answer with an example:
module A
def self.included base
puts "A included in #{base}"
end
end
module B
include A
def self.included base
puts "B included in #{base}"
end
end
class C
include A
include B
end
p C.ancestors
prints
A included in B
A included in C
B included in C
[C, B, A, Object, Kernel, BasicObject]
As we can see, A is included only once into C. Though technically it was included twice since it was included into B which was also included into C. Does this matter? Probably not. Each still only occurs once in the ancestor chain, and any methods would've been overridden with equivalent implementations—i.e., essentially a no-op. Unless you're doing something exotic with the included hook, you're unlikely to notice anything.

Related

Ambiguity in Ruby class name resolution

I recently did some code refactoring in a Rails codebase in which I converted some code that defined some classes like this (class bodies elided):
foo/user_bar.rb:
module Foo
class UserBar; end
end
foo/sub_user_bar.rb:
module Foo
class SubUserBar < UserBar; end
end
...to:
In foo/bar/user.rb:
module Foo
module Bar
class User; end
end
end
In foo/bar/sub_user.rb:
module Foo
module Bar
class SubUser < User; end
end
end
This introduced a subtle problem in that there was already an existing top-level class called User (a Rails model), and SubUser was being derived from that, not from User in the same module. I'm guess that this is because the order that Rails loads classes is unpredictable...?
Anyway, I found that I could disambiguate by declaring the SubUser class like this:
class SubUser < self::User
...which seems to work, although I couldn't find any examples of it in a modest amount of searching. It does look a little weird, though. And now I'm concerned that I really ought to be doing this for every class in my module, just in case a top-level class with the same name is ever introduced.
There are two styles of in-module class declarations throughout my company's codebase:
class A::B::Foo; end
And:
module A; module B; class Foo; end; end; end
I've always preferred the latter method since it allows for access to other names in the module without fully-qualified names, but now I've found that there's potentially a trap when I use it. So what's the best practice here?
Don't declare classes within a module; always use fully qualified names (class A::B::C::Foo < A::B::C::Bar)
Declare classes in a module but always fully qualify superclass names (module A; module B; module C; class Foo < A::B::C::Bar)
Declare classes in a module and use unqualified names but always use self:: when extending a class in the same module
Declare classes in a module and use unqualified names but stay aware of possible name collisions in the top-level namespace (seems risky)
Or do Ruby and/or Rails offer some other, cleaner way to resolve the issue?
Generally where there's ambiguity you specify full namespace paths:
module Foo
module Bar
class SubUser < Foo::Bar::User; end
end
end
That might seem verbose, but it's also specific and unambiguous.
Where you want to refer to literal top-level User you'd specify ::User.
Modules are identified by constants.1 The resolution of module look-ups is therefore determined by the procedure for looking up constant references. According to "The Ruby Programming Language", by David Flanagan and Yukihero Matsumoto, 1st Ed. 2008 (p. 261-262), constant look-ups are performed in the following order, where mod is the innermost module that encloses the reference to the constant:
mod.
the next enclosing module, continuing until there are no more enclosing modules. (Top-level/global constants are not considered at this step). The class method Module::nesting returns an array of modules that are so searched, in the order in which they are searched.
the elements of mod.ancestors, in index order (i.e., the inheritance hierarchy).
top-level constant definitions.
the value returned by the method Module#const_missing, with mod being the receiver and the constant expressed as a symbol being the argument, provided the method has been defined.
Let's see what we may learn by inserting puts Module.nesting.inspect and puts ancestors statements into the code.
module Foo
class UserBar
puts "nesting for UserBar=#{Module.nesting.inspect}"
puts "#{self}.ancestors=#{ancestors}"
end
end
# nesting for UserBar=[Foo::UserBar, Foo]
# Foo::UserBar.ancestors=[Foo::UserBar, Object, Kernel,
# BasicObject]
module Foo
class SubUserBar < UserBar
puts "nesting for SubUserBar=#{Module.nesting.inspect}"
puts "#{self}.ancestors=#{ancestors}"
end
end
# nesting for SubUserBar=[Foo::SubUserBar, Foo]
# Foo::SubUserBar.ancestors=[Foo::SubUserBar,
# Foo::UserBar, Object, Kernel, BasicObject]
module Foo
module Bar
class User
puts "nesting for User=#{Module.nesting.inspect}"
puts "#{self}.ancestors=#{ancestors}"
end
end
end
# nesting for User=[Foo::Bar::User, Foo::Bar, Foo]
# Foo::Bar::User.ancestors=[Foo::Bar::User, Object, Kernel,
# BasicObject]
module Foo
module Bar
class SubUser < User
puts "nesting for SubBar=#{Module.nesting.inspect}"
puts "#{self}.ancestors=#{ancestors}"
end
end
end
# nesting for SubBar=[Foo::Bar::SubUser, Foo::Bar, Foo]
# Foo::Bar::SubUser.ancestors=[Foo::Bar::SubUser,
# Foo::Bar::User, Object, Kernel, BasicObject]
This tells us that if there is a class User that is not contained within Foo (as in Rails), that class would the subject of references to User in the classes Foo::UserBar and Foo::SubUserBar, but not in Foo::Bar::User or Foo::Bar::SubUser. This understanding should help in organising modules to avoid namespace problems.
1 As classes are modules, whenever I reference "module" below I am referring to classes as well as modules that are not classes.

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

I read this post: Ruby modules - included do end block – but still don't get when you would use the self.included do ... end block in a module.
The post says that code in the block will be ran when you include the module, but what's the point of that if a module's sole purpose is to be included? Wouldn't that code need to be run anyway? That block doesn't need to be there in order for that code to be run, right?
What would be the difference between the two below:
module M
def self.included(base)
base.extend ClassMethods
base.class_eval do
scope :disabled, -> { where(disabled: true) }
end
end
module ClassMethods
...
end
end
vs.
module M
def self.some_class_method
...
end
scope :disabled, -> { where(disabled: true) }
end
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.
module M
# self.included is the hook which automatically runs when this module is included
def self.included(base)
puts 'this will be printed when this module will be included inside a class'
base.extend ClassMethods
base.class_eval do
scope :disabled, -> { where(disabled: true) }
end
end
def print_object_class
self.class.name # here self will be the object of class which includes this module
end
module ClassMethods
def print_class_name
self.name # Here self would be the class which is including this module
end
end
end
I tried to modify the above module to help you understand how a module(concern) can be helpful in code reusability
self.included is a hook which runs automatically when a module is included inside a class.
any method declare in the module ClassMethods will become class methods for the class including this module
any method declare outside the module ClassMethods will become instance methods for the class including this module
For Ex suppose there is a class Product and you have included the module in it
class Product < ActiveRecord::Base
include M
puts 'after including M'
end
If you try this example in you rails console you will notice that as soon as the module M gets included in class Product included hook of module run and
this will be printed when this module will be included inside a class this is printed on console
after that after including M this will be printed on the console.
Also you can try following commands
Product.disabled # a scope with name 'disabled' is avaialble because of including the module M
Product.print_class_name # Outputs => 'Product' This method is available to class with the help of module M
Product.new.print_object_class #Outputs => 'Product'
It also offers reusability, include this module M in any class and that class gets access to all those methods described in the module.
Whereas your second example is a mere example of basic module
module N
def self.abc
puts 'basic module'
end
end
Now abc method define in module can be accessible using only this module
N.abc # outputs 'basic module'
class Product < ActiveRecord::Base
include N
end
Product.abc #raises exception, No method found on class Product
Product.new.abc #raises exception, No method found on object of class Product
I hope this may help you understand the concept of module better.
Please let me know if you still have any doubts.

Difference between redefining self.included and passing block to included

What's the difference between
module A
def self.included(klass)
puts klass
end
end
and
module A
include ActiveSupport::Concern
included do
puts self
end
end
Which one is a better and which one to use when?
Both snippets produce the same result. However, there is a small but important difference.
The first code is pure Ruby. It means it will work without any dependency.
The second piece of code depends on ActiveSupport that is an external dependency. If you want to use it you need to include the gem in your project. In a Rails application, there is almost no overhead because the application already depends on ActiveSupport. But in a non-Rails application, it may not be convenient.
Moreover, ActiveSupport::Concern does a lot more than simply adding some syntactic sugar for the Ruby included hook. In fact, the primary scope of such module was to manage multiple dependencies between modules.
In the Rails codebase it's very common to define small piece of features into separate modules. A good example is ActiveSupport itself. However, you may have that the feature A may require some feature defined in the module B, so if you include B in your code, then the module should make sure to require and mix also A, otherwise your code will crash.
It also implements a very common pattern based on the included hook: class-level extensions. The following Ruby code
module A
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def bar
"bar"
end
end
end
class Foo
include A
end
Foo.bar
# => "bar"
becomes
module A
extend ActiveSupport::Concern
module ClassMethods
def bar
"bar"
end
end
end
class Foo
include A
end
Foo.bar
# => "bar"
My personal advice is to avoid using the ActiveSupport::Concern if
You don't need to use its advanced features
The code you are writing, can be easily written with a few code with no dependency on Concern
The app does not already include ActiveSupport as dependency
In your second piece of code, included is called once during when A is defined. It does not do anything unless you had defined included to do something. The block passed to included would have no effect unless you had overwritten included to take a block and do something with it. In short, your second piece of code does not make sense.

inject/access methods from a parent module inside a model

In Rails I have the following structure
#.../models/A.rb
module A
def m
end
end
#.../models/a/B.rb
class A::B < ActiveRecord::Base
end
This automatically places A as a parent of B. Is there a way to do something like B.m without modifying B? I know that I could do something like B.parent.m and from there create aliases, but then i would have to change B.
I'm looking to somehow inject a code present in A into B, but I don't know where this automatic association is done behind the scenes.
Something like
module A
module C
def mc
end
end
def placed_as_parent (child) # supposing this is the method called to put this module as a parent
super child
child.include(C) #this is what I would like to do
end
end
The question behind it is that I have a module which is already being shared among several models of that folder and I would like to put some common stuff for the models in there without have to manually include/extend a module in each of my models
[[EDITED]]
I'm not being clear with my question. In rails 3 if you do
rails generate active_record:model A::B
it will generate the files
#.../models/A.rb
module A
def self.table_name_prefix
'a_'
end
end
#.../models/a/B.rb
class A::B < ActiveRecord::Base
end
So if I open a console and type
A::B.table_name # -> 'a_b'
A::B.table_name_prefix # -> ''
A::B.parent # -> A
A.table_name_prefix # 'a_'
This happens automatically without any include/extend in the model B. What I want is to include more stuff in A and access it from B, without changing anything on B as i described earlier.
To be honest I'm not sure I fully understand your question but I'll give it a shot anyway.
There is a hook in the Module class that allows you to get a reference to the class the module is being included into. Thus, you could then do virtually anything with it.
An example:
module A
# you can change the class' behavior here
def self.included(klass)
puts "included in #{klass}"
end
end
And then to use it:
class B
include A #this causes the included hook in the module to be called
end
Is this what you're after?
The OP wrote:
The question behind it is that I have a module which is already being shared among several models of that folder and I would like to put some common stuff for the models in there without have to manually include/extend a module in each of my models
Here's what I would do:
module Stuff1
...
end
module Stuff2
...
end
module StuffIWantInSeveralModels
include Stuff1, Stuff2
end
class X < ActiveRecord::Base
include StuffIWantInSeveralModels
end
class Y < ActiveRecord::Base
include StuffIWantInSeveralModels
end
Then when you want to add a new module to several of your models, you only have to write an "include" statement in one place (in the StuffIWantInSeveralModels module).
Each module should be in its own file in the lib directory, with the file name matching the name of the module so Rails auto-loading will work (e.g. stuff_i_want_in_several_models.rb).
Does this achieve what you wanted?

Is it possible to reverse the included module in a class?

You include the modules in classes to extend the class functionality in terms of both adding class methods and instance methods to that particular class.
module M
def self.class_method_from_module
'from class_method_from_module'
end
def instance_method_from_module
'from instance_method_from_module'
end
end
class C
include M
def self.class_method
'from class_method'
end
def instance_method
'from instance_method'
end
end
puts C.class_method => 'from class_method'
puts C.class_method_from_module => 'from class_method_from_module'
puts C.new.instance_method => 'from instance_method'
puts C.new.instance_method_from_module => 'instance_method_from_module'
Now even after removing the module M from the memory with the following:
Object.send(:remove_const, :M) #remove the module M
puts C.class_method_from_module => 'from class_method_from_module'
puts C.new.instance_method_from_module => 'instance_method_from_module'
instead of method missing. Why is that? What is the best way to remove the functionality added by a module to a class?
The details vary by implementation, but I know that at least in JRuby and MRI 1.8 there is a construct called an Include Class that is inserted in to the inheritance chain of a class when a Module is extended or included. The Module therefore won't be garbage collected, since the Include Class still refers to it, and the methods will still be on your class. There are some great articles by Patrick Farley on this and related topics in his blog.
So, to "remove" a module, you could individually undefine each method that came from the module, but that's a pretty unwieldy mechanism for that purpose. If using a gem is acceptable to you, it would probably be better would be to use Mixology, which was designed specifically for the purpose of adding and removing modules dynamically.
When you include a mixin in a class, you are effectively adding the methods defined in the module to the class, or replacing methods in the class with those in the module that have the same name. The class does not have any tie to the module, which is why 'undefining' the M module won't affect class C. All that does is prevent you from mixing in M beyond that point.
You could use undef_method to remove methods from class C, but that will have side effects, potentially -- if a method was overriden by including a module, you will not get the original back, for instance. Undefining a class method is kind of ugly.
C.send(:undef_method, :instance_method_from_module)
class << C
self
end.send(:undef_method, :class_method_from_module)

Resources