What is best practice to extend class in Ruby? - ruby

I want to understand difference between following
module XYZ
class A
end
class B
end
end
Does class C inherit both class A and B, or I have to extend it using < ?
module YZZ
include XYZ
class C < A
end
end
What happens when I do following? Does it now include all classes, or just class A ?
module YZZ
extend XYZ
class C < A
end
end
What is the best way to extend class C from A ?
How can I extend class C using both A and B ?
How can I only include class A?

Ad 1., yes, C inherits both A and B when you use #include. #extend applies to class methods.
Ad 2. class C < A, think about it that A is merely a constant, that is assigned an object
of instance Class as value. So, of course, C becomes its subclass.
Ad 3. When you use #extend inside the 'module' statement, self is the module itself, and XYZ
basically gets included in its sigleton class.
As for your three bulleted questions in the end, I do not understand the first one. What is "extend class C from A"? Will class C < XYZ::A do? As for the second bulleted question, you can extend C "using both A and B" simply by C.extend( XYZ ). As for "how can you only include class A", there is no simple way to only include part of a module. If you plan to include class A separately, if it has its own concern to solve even without B, put it in a separate module and include that one. That's called separation of concerns. If you just want to cherry-pick, you could do:
module Something
A = XYZ::A
end
And there you have a constant Something::A pointing to the same class as XYZ::A.

This should work:
module XYZ
class A
end
class B < A
end
end
Then for including the XYZ module and extending C from A:
module ABC
include XYZ
class C < A
end
end

Related

In Ruby, is it possible to have both Parent and child class in different Module

Is it possible to inherit a class which is in a separate module like Python allows? is there any other alternative that could be done without changing the structure drastically
File 1->
Module X
Class Y
end
end
File 2->
require relative 'path/to/File 1'
Module A
Class B
end
end
I want to inherit Y into B
It's possible like this,Parent class Hello is in module One and child class Hi is in module Two.
module X
class Y
def call_me
puts 'Hello Class'
end
end
end
module A
class B < X::Y
def call_me
puts 'Hi Class'
end
end
end
A::B.new.call_me
output
Hi Class
Is it possible to inherit a class which is in a separate module like Python allows?
Classes aren't "in modules", so the "module" part of your question is actually irrelevant. The rest of your question essentially boils down to "Is it possible to inherit a class", which is possible.
Constants can be namespaces within modules, but that does not create any relationship whatsoever between the class and the module. In your example, the class referenced by the constant Y is not in the module referenced by the constant X and the class referenced by the constant B is not in the module referenced by the constant A.
The constant Y is namespaced inside the module referenced by the constant X, but that only creates a relationship between the constant and the module, not between the class referenced by the constant and the module.
You can prove the fact that there is no relationship easily by simply assigning the class to a different variable:
foo = X::Y
class A::B < foo; end
Note: please don't let the default value of Class#name fool you. The default value of Class#name is indeed the full path of the first constant that the class is assigned to, even if you remove that constant again later:
module M
class C; end
end
module A
B = M::C
end
M::C = nil
M.send(:remove_const, :C)
M = nil
self.class.send(:remove_const, :M)
foo = A::B
A::B = nil
A.send(:remove_const, :B)
A = nil
self.class.send(:remove_const, :A)
# *None* of the constants exist anymore.
foo.name
#=> 'M::C'
# The `Class#name` property still stays the path of the very first constant

Nested classes in Ruby

I can't figure out how to initialize a class from a parent class variable. I'm trying to accomplish this:
x = A::B.new('my string')
myObject = x::C.new(**params)
and the program I'm calling is organized similar to:
module A
...<stuff>...
class B
...<stuff>....
class C < B
...<stuff>...
end
end
end
I want to initialize the class C after initializing the parent class B. That way, I can have access to class B's variables and methods from class C.
When I try to execute my program, I get:
"#<A::B:0x...............>" is not a class/module (TypeError)
Can anyone point me in the right direction for initializing nested classes like this?
You can't construct an instance from an instance - the whole module hierarchy is only applicable to modules and classes. Since x is neither, the parser has no idea what :: is supposed to do.
The idea behind nested classes is that they are namespaced within the parent class, no more, no less. In effect, class B acts like a module prefix to class C, but there's no inherent relationship between them (by being nested alone; you do inherit C from B in your example, which is what gives you the relationship), and certainly not between an instance of B and the class C
Instead, I would recommend constructing a C directly with 'my string', then calling #super in the initialize method, like so:
myObject = A::B::C.new('my string', **params)
and in the implementation:
module A
class B
def initialize(some_string)
#some_string = some_string
end
class C < B
def initialize(str, params)
super(str)
...
end
end
end
end
As the error message suggests, the namespace operator :: can only be applied to a class/module. If x were the class A::B, then x::C should work. It does not make sense to apply ::C on an instance of A::B.
You need to apply the :: to x's class, not x itself. So you just need a call to the class method:
x = A::B.new('my string')
myObject = x.class::C.new(**params)
For example, this sort of thing:
module A
class B
class C
end
end
end
pancakes = A::B.new
eggs = pancakes.class::C.new
puts pancakes.inspect
puts eggs.inspect
gives you something like this:
#<A::B:0x007faea90b6a58>
#<A::B::C:0x007faea90b6a30>

How to trace the singleton class and m_tbl in Ruby

I started to touch the meta-programming in Ruby
If I want to trace all the details in meta-programming
Like to lookup m_tbl methods_table in a specific object,
I mean if there is a test method and defined in class B
A < B
B < C
What's the convenient way to know the method is defined in class B
Any good methods or tools to share about discovery the meta-programing in Ruby.
To look up all the relation between object's hierachy relation in quick way.
Thanks !
Use method method:
class C
def c
end
end
class B < C
def b
end
end
class A < B
def a
end
end
a = A.new
a.method(:b).owner
# => B

How do I get the parent's class name in Ruby

Let assume I have a classes A and B where B inherits A. How do I print parent class name in B
class A
end
class B < A
end
Some things I have tried
>> B.new.class #=> B #which is correct
>> B.new.parent #=> Undefined method `parent`
>> B.parent #=> Object
>> B.parent.class #=> Class
Thanks :)
class A
end
class B < A
end
B.superclass # => A
B.superclass.name # => "A"
If you want the full ancestor stack try:
object.class.ancestors
For instance:
> a = Array.new
=> []
> a.class.ancestors
=> [Array, Enumerable, Object, Kernel, BasicObject]
In case google brings anyone here who's working in Rails, what you may want instead is base_class, as superclass will traverse the ActiveRecord inheritance structure as well.
class A < ActiveRecord::Base
end
class B < A
end
> A.superclass
=> ActiveRecord::Base
> B.superclass
=> A
> A.base_class
=> A
> B.base_class
=> A
Even further...
class C < B
end
> C.base_class
=> A
In other words, base_class gives you the top of the inheritance tree but limited to the context of your application. Fair warning though, as far as Rails is concerned "your application" includes any gems you're using, so if you have a model that subclasses something defined in a gem, base_class will return the gem's class, not yours.
Given an object (Instantiated Class) you can derive the parent Class
>> x = B.new
>> x.class.superclass.name
=>"A"
The term you're looking for is superclass. And indeed you can do B.superclass to get A. (You can also do B.ancestors to get a list of all the classes and modules it inherits from — something like [B, A, Object, Kernel, BasicObject].)
Inheritance is a relation between two classes. Inheritance create a
parent child relationship between classes. It is a mechanism for code
reuse and to allow independent extensions of the original software via
public classes and interfaces.The benefit of inheritance is that
classes lower down the hierarchy get the features of those higher up,
but can also add specific features of their own.
In Ruby, a class can only inherit from a single other class. (i.e. a class can inherit from a class that inherits from another class which inherits from another class, but a single class can not inherit from many classes at once). The BasicObject class is the parent class of all classes in Ruby. Its methods are therefore available to all objects unless explicitly overridden.
Ruby overcome the single class inheritance at once by using the mixin.
I will try to explain with an example.
module Mux
def sam
p "I am an module"
end
end
class A
include Mux
end
class B < A
end
class C < B
end
class D < A
end
You can trace by using class_name.superclass.name and do this process unless you found BasicOject in this hierarchy. BasicObject is super class o every classes. lets see suppose we want to see class C hierarchy tree.
C.superclass
=> B
B.superclass
=> A
A.superclass
=> Object
Object.superclass
=> BasicObject
You can see the whole hierarchy of class C. Point to note using this approach you will not find modules that are included or prepended in the parent classes.
There is another approach to find complete hierarchy including modules. According to Ruby doc ancestors. Returns a list of modules included/prepended in mod (including mod itself).
C.ancestors
=> [C, B, A, Mux, Object, Kernel, BasicObject]
Here, Mux and Kernel are Modules.
http://rubylearning.com/satishtalim/ruby_inheritance.html
https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)

Multiple Inheritance in Ruby?

I thought that Ruby only allowed single inheritance besides mixin. However, when I have class Square that inherits class Thing, Thing in turn inherits Object by default.
class Thing
end
class Square < Thing
end
Doesn't this represent multiple inheritance?
I think you are taking the meaning of multiple inheritance in a wrong way. Probably what you have in mind as multiple inheritance is like this:
class A inherits class B
class B inherits class C
If so, then that is wrong. That is not what multiple inheritance is, and Ruby has no problem with that. What multiple inheritance really means is this:
class A inherits class B
class A inherits class C
And you surely cannot do this in Ruby.
No, multi inheritance means one class have more than one parent class. For example in ruby you can have that behavior with modules like:
class Thing
include MathFunctions
include Taggable
include Persistence
end
So in this example Thing class would have some methods from MathFunctions module, Taggable and Persistence, that wouldn't be possible using simple class inheritance.
Multiple inheritance - This is absolutely not possible in ruby not even with modules.
multilevel inheritance - This is what is possible even with the modules.
Why ?
Modules acts as an absolute superclasses to the class that includes them.
Ex1 :
class A
end
class B < A
end
This is a normal inheritance chain, and you can check this by ancestors.
B.ancestors => B -> A -> Object -> ..
Inheritance with Modules -
Ex2 :
module B
end
class A
include B
end
inheritance chain for above example -
B.ancestors => B -> A -> Object -> ..
Which is exactly same as a Ex1. That means all the methods in module B can override the methods in A, And it acts as a real class inheritance.
Ex3 :
module B
def name
p "this is B"
end
end
module C
def name
p "this is C"
end
end
class A
include B
include C
end
A.ancestors => A -> C -> B -> Object -> ..
if you see the last example even though two different modules are included they are in a single inheritance chain where B is a superclass of C, C is a superclass of A.
so,
A.new.name => "this is C"
if you remove the name method from module C, above code will return "this is B". which is same as inheriting a class.
so,
At any point there is only one multilevel inheritance chain in ruby, which nullifies having multiple direct parent to the class.
If class B inherits from class A,
then instances of B have the behaviors of both class A and class B
class A
end
class B < A
attr_accessor :editor
end
Ruby has single inheritance, i.e. each class has one and only one parent class.
Ruby can simulate multiple inheritance using Modules(MIXINs)
module A
def a1
end
def a2
end
end
module B
def b1
end
def b2
end
end
class Sample
include A
include B
def s1
end
end
samp=Sample.new
samp.a1
samp.a2
samp.b1
samp.b2
samp.s1
Module A consists of the methods a1 and a2. Module B consists of the methods b1 and b2. The class Sample includes both modules A and B. The class Sample can access all four methods, namely, a1, a2, b1, and b2. Therefore, you can see that the class Sample inherits from both the modules. Thus you can say the class Sample shows multiple inheritance or a mixin.

Resources