Calling method in parent class from subclass methods in Ruby
If the method is the same name, i.e. you're overriding a method you can simply use super
. Otherwise you can use an alias_method
or a binding.
class Parent
def method
end
end
class Child < Parent
alias_method :parent_method, :method
def method
super
end
def other_method
parent_method
#OR
Parent.instance_method(:method).bind(self).call
end
end
Calling a subclass method from a superclass
Good question, but you are making it too complicated. Keep in mind a few principles and it should all be clear...
The types will be resolved dynamically, so if a
show
exists anywhere in the object's class hierarchy at the moment it is actually called then Ruby will find it and call it. You are welcome to type in method calls to anything that may or may not exist in the future and it's legal ruby syntax and it will parse. You can type in an expression that includes a reference tothis_will_never_be_implemented
and no one will care unless it actually gets called.Even in Java, there is only one actual object. Yes, you may have a method in the superclass that's calling a method, but it is an instance of the derived class (as well as an instance of the base class) and so you can count on the new
show
being called.In a sense, every Ruby class is an abstract class containing stubs for every possible method that might be defined in the future. You can call anything without access qualifiers in the base class or derived class.
If you want a null superclass implementation, you may want to define one that does nothing or raises an exception.
Update: Possibly, I should have just said "call show
like any other method" and left it at that, but having come this far I want to add: You can also implement show
with Ruby's version of multiple inheritance: include SomeModule. Since you are obviously interested in Ruby's object model, you might implement your attribute with a mixin just for fun.
Can I call a subclass' private method from its parent class?
You're getting it wrong - in your example, there is no such a thing as the parent class calling children methods.
Methods/constants name lookup in Ruby always works "bottom up": first we check if the method is defined in object's class, then in object's class's superclass and so on (this is a huge simplification because Ruby's object model is more complicated, more on this later). So, in your example things happen in roughly the following order:
When you call
RoadBike.new
runtime checks if there is aninitialize
methods defined for the class RoadBike. There is no, so we use the implementation defined for its parent class -Bycicle
(but the execution context stays the same - it is stillRoadBike
instance)When executing
Bycicle#initialize
runtime encounters another method call -default_chain
. At this moment we start method name resolving in the very same manner - starting from the RoadBike context. DoesRoadBike
have its own implementation ofdefault_chain
? Yes, it does, so we simply call it.
The following baby example makes it crystal clear, hopefully:
class Parent
def initialize
puts "Parent Initializer is called"
a
b
end
def a
puts "Parent a is called"
end
def b
puts "Parent b is called"
end
end
class Child < Parent
def b
puts "Child b is called"
end
end
pry(main)> Child.new
Parent Initializer is called
Parent a is called
Child b is called
In reality the methods/constants resolution machinery is more complicated(includes so-called singleton classes). This is a bigger topic that will not fit nicely in SO answer, so I strongly recommend reading "Metaprogramming Ruby 2" by Paolo Perotta where this model is wery well explained in great details from the very practical point of view.
How do I call a super class method
In Ruby 2.2, you can use Method#super_method
now
For example:
class B < A
def foo
super + " world"
end
def bar
method(:foo).super_method.call
end
end
Ref: https://bugs.ruby-lang.org/issues/9781#change-48164 and https://www.ruby-forum.com/topic/5356938
Ruby subclass not inheriting parent method or not able to call parent methods in class body
You're calling element as if it was defined as a class method. Any code that is in a class definition but not in a method definition will only be able to call class methods. One way to make the method visible from where your calling it would be to change the signature so it becomes a method of the class object.
class Page
def self.element
end
end
Call subclass method from superclass - Design Pattern
Try this:
class Animals
def self.update
puts "self = #{self} in Animals::update"
if whatever == "Happy Days"
puts "The Fonz rules"
end
end
end
class Tiger < Animals
def self.whatever
"Happy Days"
end
end
Tiger.update
# self = Tiger in Animals::update
# The Fonz rules
Before discussing this, a few notes:
- I've removed the module
Zoo
and the instance methodTiger#update
as they are not relevant to the question. - I've removed
self.
fromself.whatever
, as it is not needed (self
is assumed if there is no explicit receiver). - I've defined the class methods in the more conventional way (but there is nothing wrong with the way the OP defines them).
update
is only to be invoked from subclasses, asAnimal.update
would raise a "there's no method or local variable 'whatever'" exception.
The important point here is that Tiger.update
invokes the method Animal::update
, just as though update
had been defined in Tiger
, rather than having been inherited from Animal
. That's why:
Tiger.methods.include?(:update) #=> true
Therefore, "call a class method of a child class from a parent class" is not correct; Tiger::whatever
is being called from the child class. Nothing is being called from the parent class because self
never equals Animals
when Tiger::update
is invoked. This is not just semantics.
Calling a parent instance variable from a sub class in ruby
You are overriding ParentClass#initialize
.
Ruby does not magically invoke overridden methods. That would kind of defeat the point of overriding in the first place: for example, often, the reason why you override a method in a subclass, is that the subclass implementation can make use of its knowledge of the subclass to improve performance. It wouldn't make sense for Ruby to invoke the un-optimized version in addition to the optimized one.
However, another big purpose of overriding is differential code reuse: reusing code by only implementing the difference in behavior. In order to do that, Ruby has the super
keyword, which allows you to retry the method lookup starting one level up in the ancestors chain.
Here's what that would look like in your case:
class SubClass < ParentClass
def initialize(*)
super
@retries = 0
end
end
This solves the problem with the un-initialized instance variable.
However, there are several other problems with your code. For example, here:
SubClass.new().run()
You are sending the message new
to SubClass
without any arguments. By default, Class#new
is implemented roughly like this:
class Class
def new(...)
obj = allocate
obj.initialize(...)
obj
end
end
[Technically, initialize
is private
, so we need to break encapsulation here by using something more like obj.__send__(:initialize, ...)
.]
In other words, new
passes its arguments on to initialize
. But you have defined ParentClass#initialize
with one mandatory keyword parameter profile:
, so theoretically, we need to pass an argument to super
… but what should we pass? So, instead, we have defined SubClass#initialize
to take arguments and pass them on to ParentClass#initialize
.
However, you are passing no arguments to SubClass::new
here, that we could pass on, and in fact, it isn't clear what arguments we could pass here.
I would like to help you here, but to be honest, the code simply does not make sense, so I don't see how to fix it. Superclasses must never know about their subclasses, in fact, they typically cannot know about their subclasses: many languages allow you to add subclasses after the fact, and Ruby is no exception. Therefore, a superclass knowing about its subclass is a sign that something in your design is very, very, very wrong.
Also note that the very idea of a "parent instance variable" does not make sense: "parent" refers to the class hierarchy, but instance variables belong to instances … that's why they are called "instance" variables, after all.
Ruby on Rails - Call a method for each subclass from the parent class
This happens because rails autoloads classes: Parent
doesn't know about its subclasses until they used somewhere or required.
Just require them all manually from the Parent
class:
# parent.rb
require 'child1'
require 'child2'
class Parent
def self.parse
self.subclasses.each(&:parse) # how to fix this?
end
end
calling child class method in parent class method
Just use STI here:
class Product < ActiveRecord::Base
self.inheritance_column = :product_type
end
class Orange < Product
end
# then...
> Orange.all
Orange Load (0.1ms) SELECT "products".* FROM "products" WHERE "products"."product_type" IN ('Orange')
Ie. don't do the default_scope
or the after_initialize
, because Rails already has you covered as soon as you inherit from another model Rails will assume you're using STI and it will add the right thing in the query.
Call derived class instance method from parent class in ruby
Your code already works, so I don't know what the question is.
However, one thing I will say is that there's a standard way to handle control flow like this, without resorting to method
meta-programming: yield
. You can do something like this:
class Parent
def common_logic(params)
# Some common code which it's Child classes share
yield
end
end
class Child < Parent
def child_method(params)
# ...
end
def some_other_method(params)
common_logic(params) { child_method(params) }
end
end
Related Topics
Make Rake Task from Gem Available Everywhere
Seeding File Uploads with Carrierwave, Rails 3
Error While Installing Ruby-1.8.7 on Fedora 15
How to Run Selenium (Used Through Capybara) at a Lower Speed
Include Params/Request Information in Rails Logger
Using Ruby Libraries and Gems with a Shoes App
How to Install (Build) Ruby 1.9.3 on Osx Lion
How to Install Ruby on Rails 3.0 on Ubuntu 10.10
Cannot Connect to Remote Db Using Ssh Tunnel and Activerecord
Rspec 3 How to Test Flash Messages
How to Use Array#Delete While Iterating Over the Array
Only Show Decimal Point If Floating Point Component Is Not .00 Sprintf/Printf
Check If User Is Active Before Allowing User to Sign in with Devise (Rails)