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)
Related
I have a module that provides logging functionality. Some classes extend it, others include it. As part of the logging, I pass in a class name.
If I do this:
global_logger.call(level, self, msg)
It could log either:
WARN -- Some::Class: some msg
OR
WARN -- #<Some::OtherClass:0x00007fdc04907710>: some msg
based on if the module was extended or included. I can call self.class instead, but then the the other one turns into Class.
Is there a way to get a class name(without the #<...:0x00007fdc04907710>), given that you don't know if self is a class or an instance?
There are a number of things you could do, but one of the easiest is probably to see if the passed object is a class before trying to extract other information about it. For example:
Object.kind_of? Class #=> true
Object.new.kind_of? Class #=> false
You can then decide what methods are appropriate to call based on whether or not it's a class. For example:
p Object.new.class.name #=> "Object"
P Object.name #=> "Object"
We know that, for a given module M, you can determine if a class C has included M by writing
C.included_modules.include?(M)
To determine if a class C has extended M you may execute
C.singleton_class.included_modules.include?(M)
because extending a module to a class is equivalent to including the same module to the class' singleton class.
See Module#included_modules and Object#singleton_class.
Here is an example.
module M
def m; end
end
class C
extend M
end
a = C.singleton_class.included_modules
#=> [M, Kernel]
a.include?(M)
#=> true
I am experimenting with the Ruby include keyword as shown below:
module A
def show
puts "working"
end
end
include A
class E
end
class D
end
e = E.new
d = D.new
e.show
d.show
o = Object.new
puts o.respond_to?("show")
******************************output****************
working
working
true
I was expecting output to be undefined method but it's giving me the proper output. I have also observed that the show method defined in module A is becoming an instance method of Object.
Why are these methods becoming instance methods of the class Object?
Please help in understanding this concept.
Because instances of class Class inherit from Object.
Thus, modules, included into Object are available to instances of Class's instances (instances of your E and D classes).
class A
end
module B
def test; :hi end
end
#=> test
include B
#=> Object
A.new.test
#=> :hi
Object.new.test
#=> :hi
Having include B written in the top-level means include'ing B into Object.
include B is the outermost context is equivalent to:
class Object
include B
end
The only class, whose instances do not share module B's methods is BasicObject.
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.
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>
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.