Overriding instance methods of a class by mixing in a module - ruby

Given a class A and a module B, mixin the instance methods of B so that it overrides the correspnding instance methods of A.
module B
def method1
"B\#method1"
end
def method2
"B\#method2"
end
end
class A
def method1
"A\#method1"
end
def method2
"A\#method2"
end
# include B does not override instance methods!
# (module gets mixed into the superclass)
end
puts A.new.method1 # want it to print out "B#method1"
puts A.new.method2 # want it to print out "B#method2"

Module#include inserts the module M as a superclass of the class C. So, you can't override C's methods in M, rather it's the other way around: C's methods override M's methods. (Technically speaking, Ruby doesn't make M a superclass of C, rather it creates an invisible Include Class ⟦M′⟧ whose method table and constant table point to M's method table and constant table, and makes that class the superclass, but this distinction is not important for this particular question.)
In Ruby 2.0, there is a new method, Module#prepend which, just as the name implies, prepends M to C's ancestors, in other words, makes M a subclass of C.
So, in short: you can't, at least not yet.

You could remove each of B's methods from A before including B.
class A
def method1
"A\#method1"
end
def method2
"A\#method2"
end
B.instance_methods(false).each { |method|
remove_method(method) if instance_methods(false).include?(method)
}
include B
end
Or from within B:
module B
def method1
"B\#method1"
end
def method2
"B\#method2"
end
def self.append_features(mod)
instance_methods(false).each { |method|
mod.send(:remove_method, method) if mod.instance_methods(false).include?(method)
}
super
end
end

Related

Why private class methods are not allowed in ruby classes?

I came across this error while in development.
class ABC
def self.method_1
method_2
p "method_1"
end
private
def method_2
p "method_2"
end
end
ABC.method_1 # `method_1': undefined local variable or method `method_2' for ABC:Class (NameError)
But if I do it like this, then it works
def self.method_1
method_2
p "method_1"
end
def self.method_2
p "method_2"
end
private_class_method :method_2
end
ABC.method_1
Please help me in understanding this.
In Ruby, the default implicit receiver of a message send, if you do not explicitly specify a receiver, is self.
Also, the default definee of a method definition expression, if you do not explicitly define a definee, is the closest lexically enclosing module definition.
In your first example, method1 is defined with an explicit definee of self, which at that point in the execution is the class ABC itself. This means that method1 is a class method of class ABC, which is actually just a singleton method of ABC, which in turn is just an instance method of ABC's singleton class.
method2 is defined without an explicit definee, which means it will be defined on the default definee. The closest lexically enclosing class or module definition in this case is the class definition of ABC, so method2 is defined as an instance method of ABC.
In other words: method1 and method2 are defined in two completely different classes.
Now, when you call ABC.method1, you are sending the message method1 to the explicit receiver ABC. This works, because method1 is found in ABC's singleton class.
Inside of method1, you are calling method2 without an explicit receiver. That means, the message is sent to the implicit receiver self, which is ABC in this case. So, it is roughly equivalent (module access restrictions) to ABC.method2.
BUT there is no definition of method2 in either the singleton class of ABC er the class of ABC (which is Class) or any of its superclasses (Module, Object, Kernel, BasicObject) because method2 is defined in ABC itself.
Therefore, method2 cannot be found in the method lookup chain.
In the second example, both methods are defined in the same class, namely both methods are defined in ABC's singleton class. Therefore, method2 is in the method lookup chain when called inside of method1.
In fact, your first example is actually not substantially different from this:
class Foo
def method 1
method2
end
end
class Bar
def method2; end
end
foo = Foo.new
foo.method1
#Jorg's answer is correct, but this might be easier to read. As Jorg pointed out, the use of the "self" applies to the class object, not the specific instance of it. basically mixing and matching the "self" and not-"self" entries is hard work, and you shouldn't try to cross the streams. the "self" and non-"self" objects will act as completely different classes.
class
class ABC
def method_1
method_2
p "method_1"
end
def self.method_3
method_4
p "method_3"
end
private
def method_2
p "method_2"
end
def self.method_4
p "method_4"
end
end
output
> ABC.new.method_1
"method_2"
"method_1"
=> "method_1"
> ABC.method_3
"method_4"
"method_3"
=> "method_3"

What is the difference between `Class` and `class`

While creating a class, we use the keyword class like:
class Abc
Z = 5
def add
puts "anything here"
end
end
In console, Abc.class # => Class
How does Abc internally become a class? What is the difference between class and Class?
It would be great if anyone could explain how class constants and method are internally called, and if a method is not defined, then how we get the exception "undefined class method". What is the internal logic behind it?
There are three different things here:
class is a keyword, which is used to define or reopen a class
Object#class is a method, which returns the class of a given object
Class is the class which all classes are an instance of (including Class itself)
ndn's answer gives a nice overview of the different things "class" could refer to.
To answer your specific question:
How does Abc internally become a class?
Almost like any other object.
class Abc
end
is equivalent to:
Abc = Class.new do
end
It creates a new instance of Class and assigns it to the constant Abc.
To see what the different "class" things in Ruby mean, check out my other answer.
As for how methods are looked up:
There are multiple places a method can come from:
The class of the object
The parent of the class of the object
Modules, which are included/prepended
The singleton class of the object
The order of lookup is the following:
If it exists, the singleton class
Prepended modules
Methods defined in the class
Included modules
Recursively, the above rules for the parent class
There are a few things that have to be noted here:
If multiple modules are included/prepended, they will be looked up in the reverse order of how they were included/prepended
If a module was already included/prepended in one of the parrents, it won't be included/prepended again
If using these rules the method was not found til the very start of the hierarchy (BasicObject), the ancestor chain is searched again for a different method, called method_missing
BasicObject#method_missing is defined so that it throws a NoMethodError and that is where the error comes from
module M1
def foo
puts 'Defined in M1'
end
end
module M2
def foo
puts 'Defined in M2'
end
end
class C
include M1
prepend M2
def foo
puts 'Defined in C'
end
def method_missing(method_name)
puts 'Method missing' if method_name == :foo
end
end
c = C.new
# singleton method
def c.foo
puts "Defined in c's singleton"
end
puts c.singleton_class.ancestors
# => [#<Class:#<C:0xa2d0f8>>, M2, C, M1, Object, Kernel, BasicObject]
# ^ the singleton class,
# the prepended module,
# the C class itself,
# the included module,
# the rest of the hierarchy
# (Object is the implicit parent of all classes with no explicit parent)
with class Abc you define a class.
Abc.class is returning the Type, and the type of Abc is a Class
another example:
1337.class
=> Fixnum
"hi babe!".class
=> String
12.55.class
=> Float
(1..12).class
=> Range
so as you can see, each "datatype" is a class. in your case Abc is also a Datatype. And for the end of that chain, the class of a class is Class! :-)
Answering second par of the question, undefined class method happens when method you called is not present in such class - classes are just objects in Ruby, and as such they have their own set of methods. Ruby has several ways to define class methods, most common is probably
class Klass
def self.klass_method
...
end
end
the other is
class Klass
# some ordinary instance methods here
class << self
def klass_method
# this is class method
end
end
end
Some Rubyists prefer the latter, as it keeps all class methods in single block, but they are equivalent.

Usage of "self", mixin methods, and exposed methods

This is some code that I use in a class called Game:
def play
puts "There are #{#players.length} players in #{#title}."
#players.each do |n|
puts n
end
#players.each do |o|
GameTurn.take_turn(o)
puts o
end
end
It uses a line of code that references a module called GameTurn. Within GameTurn, I have a method called self.take_turn:
require_relative "die"
require_relative "Player"
module GameTurn
def self.take_turn(o)
die = Die.new
case die.roll
when 1..2
o.blam
puts "#{o.name} was blammed homie."
when 3..4
puts "#{o.name} was skipped."
else
o.w00t
end
end
end
I'm a little confused why we use "self" and the difference between exposed methods and mixin methods in modules. I asked this "instance methods of classes vs module methods"
Is take_turn really an exposed method? Even though we're feeding into the take_turn method an object from the player class, is this method still considered a module method that we're using directly? Is this not considered a mixin method? We are feeding into the take_turn method an object from another class, so isn't it mixing in with other classes?
Also, I am still trying to figure out when/why we use the term "self"? It just seems weird that we need to define the method take_turn within the GameTurn module using the term "self". It seems like it should be defined without "self" no?
Ok, from the start:
self always returns the object in which context it is executed. So here:
class A
self #=> A
end
In ruby, you can define methods on objects in flight, you can for example do:
o = Object.new
o.foo #=> NameError
def o.foo
:foo
end
o.foo #=> :foo
Classes and modules are just objects as everything else, hence you can define methods on them as well:
def A.method
'class method'
end
A.method #=> 'class_method'
However it is much easier and more convinient to define it within the class body - because of self, which always returns the class itself:
class A
def self.foo
:foo
end
end
self returns A, so this can be read as:
class A
def A.foo
:foo
end
end
The good thing about this is that if you decide to change class name, you only need to do it on top, next to class - self will take care of the rest.
Within the method self is always the receiver of the method. So:
o = Object.new
def o.method
self
end
o.method == o #=> true
It might be however pretty confusing from time to time. Common confusion come from the code:
class A
def get_class
self.class
end
end
class B < A
end
b = B.new
b.get_class #=> B
even though get_class is defined on class A, self refers to the receiver of a method, not the method owner. Hence it evaluates to:
b.class #=> B
For the same reason self within class methods always points to the class the method is executed on.

Ruby : Invoke overridden method of parent class, in child class

Say I have class B derived from class A
Is it possible to invoke overrided method of A like this?
class A
def method1
end
def method2
end
end
class B < A
def method1
### invoke method2 of class A is what I want to do here
end
def method2
end
end
# not exactly duplicate to How do I call an overridden parent class method from a child class? , but we seem want to do the same thing.
I'm assuming here that B is supposed to inherit from A and you simply made a typo in your example code. If this is not the case, there is no way to do what you want.
Otherwise you can do what you want using reflection by binding A's method2 instance method to your current B object and calling it like this:
class A
def method1
end
def method2
end
end
class B < A
def method1
A.instance_method(:method2).bind(self).call
end
def method2
end
end
Note though that you shouldn't pull out the big black-magic-guns like this unless you really need to. In most cases redesigning your class hierarchy so that you don't need to do this is the better alternative.
You can create a synonym for parent method using alias statement and call it from the overriden method:
class A
def method1
puts '1'
end
def method2
puts '2'
end
end
class B < A
alias parent_method1 method1
alias parent_method2 method2
def method1
parent_method2
end
def method2
end
end
b = B.new
b.method1 # => 2
The answer of #sepp2k is technically correct, however I would like to explain why this technique is not appropriate in my opinion (so the question is technically interesting, but leads to the wrong goal):
Ruby does not allow to call super.method2 in the context of method1called in an instance of B, because it is just wrong to do it. Class inheritance should be used when your instances are specializations of the superclass. That includes that you normally only expand behavior, by calling super and doing something additionally before or after that call.
There are languages like Java and others, that allow to call super for another method, and that leads to something similar to spaghetti code, but the object-oriented way. No one understands when which methods are called, so try to avoid it.
So try to find the reason why you want to change the call, and fix that. If your method1 in A is wrong implemented in B, then you should not subclass is.

Why does including this module not override a dynamically-generated method?

I'm trying to override a dynamically-generated method by including a module.
In the example below, a Ripple association adds a rows= method to Table. I want to call that method, but also do some additional stuff afterwards.
I created a module to override the method, thinking that the module's row= would be able to call super to use the existing method.
class Table
# Ripple association - creates rows= method
many :rows, :class_name => Table::Row
# Hacky first attempt to use the dynamically-created
# method and also do additional stuff - I would actually
# move this code elsewhere if it worked
module RowNormalizer
def rows=(*args)
rows = super
rows.map!(&:normalize_prior_year)
end
end
include RowNormalizer
end
However, my new rows= is never called, as evidenced by the fact that if I raise an exception inside it, nothing happens.
I know the module is getting included, because if I put this in it, my exception gets raised.
included do
raise 'I got included, woo!'
end
Also, if instead of rows=, the module defines somethingelse=, that method is callable.
Why isn't my module method overriding the dynamically-generated one?
Let's do an experiment:
class A; def x; 'hi' end end
module B; def x; super + ' john' end end
A.class_eval { include B }
A.new.x
=> "hi" # oops
Why is that? The answer is simple:
A.ancestors
=> [A, B, Object, Kernel, BasicObject]
B is before A in the ancestors chain (you can think of this as B being inside A). Therefore A.x always takes priority over B.x.
However, this can be worked around:
class A
def x
'hi'
end
end
module B
# Define a method with a different name
def x_after
x_before + ' john'
end
# And set up aliases on the inclusion :)
# We can use `alias new_name old_name`
def self.included(klass)
klass.class_eval {
alias :x_before :x
alias :x :x_after
}
end
end
A.class_eval { include B }
A.new.x #=> "hi john"
With ActiveSupport (and therefore Rails) you have this pattern implemented as alias_method_chain(target, feature) http://apidock.com/rails/Module/alias_method_chain:
module B
def self.included(base)
base.alias_method_chain :x, :feature
end
def x_with_feature
x_without_feature + " John"
end
end
Update Ruby 2 comes with Module#prepend, which does override the methods of A, making this alias hack unnecessary for most use cases.
Why isn't my module method overriding the dynamically-generated one?
Because that's not how inheritance works. Methods defined in a class override the ones inherited from other classes/modules, not the other way around.
In Ruby 2.0, there's Module#prepend, which works just like Module#include, except it inserts the module as a subclass instead of a superclass in the inheritance chain.
If you extend the instance of the class, you will can do it.
class A
def initialize
extend(B)
end
def hi
'hi'
end
end
module B
def hi
super[0,1] + 'ello'
end
end
obj = A.new
obj.hi #=> 'hello'

Resources