简体   繁体   中英

Ruby Inheritance and overwriting class method

I have set up two classes as shown below

class Parent

  def self.inherited(child)
    child.custom_class_method
  end

  def self.custom_class_method
    raise "You haven't implemented me yet!"
  end
end

class Child < Parent

  def self.custom_class_method
    "hello world"
  end
end

It seems that when the inheritence Child < Parent is evaluated, it calls self.inherited , which in turn raises the Parent 's version of self.custom_class_method instead of the Child 's. This is a problem because instead of getting an expected "hello world" I get an error raised saying "You haven't implemented me yet!"

Does Child 's self.custom_class_method not get evaluated until after Parent 's self.inherited is finished evaluating? And if so is there perhaps a work around this? Should I just not put a raise check on the Parent class?

I think this should clarify:

class Parent
  def self.inherited(child)
    puts "Inherited"
  end
end

class Child < Parent
  puts "Starting to define methods"
  def self.stuff; end
end

Output makes it clear that .inherited gets called the moment you open the new class, not when you close it. Thus, as you guessed, Child.custom_class_method does not exist at the point when you are trying to call it - all .inherited sees is a blank slate.

(As to how to get around it... I can't say without more insight into what you are trying to do, unfortunately.)

The template pattern/lazy initialization may help solve your problem. The code assumes what is different between the children classes is the database connection information, perhaps just a table name or perhaps completely different databases. The parent class has all the code for creating and maintaining the connection, leaving the children only the responsibility of providing what is different.

class Parent
  def connection
    @connection ||= make_connection
  end

  def make_connection
    puts "code for making connection to database #{database_connection_info}"
    return :the_connection
  end

  def database_connection_info
    raise "subclass responsibility"
  end
end

class Child1 < Parent
  def database_connection_info
    {host: '1'}
  end
end

class Child2 < Parent
  def database_connection_info
    {host: '2'}
  end
end

child1 = Child1.new
child1.connection  # => makes the connection with host: 1
child1.connection  # => uses existing connection

Child2.new.connection  # => makes connection with host: 2

You have to wrap self.inherited in Thread.new

Example:

class Foo
  def self.inherited klass
    begin
      puts klass::BAZ
    rescue => error
      # Can't find and autoload module/class "BAZ".
      puts error.message
    end

    Thread.new do
      # 123
      puts klass::BAZ
    end
  end
end

class Bar < Foo
  BAZ = 123
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM