简体   繁体   中英

Ruby class accessing protected method of child class?

I have a background in Node Js and I am new to Ruby, Pardon me If this question is a noob. I have 3 classes like this.

class Babylon::Metric::Counter < Babylon::Metric
  protected

  def record
    # some code here
  end
end
class Babylon::Metric::Gauge < Babylon::Metric
  protected

  def record
    # some code here
  end
end

and the parent class of these is

class Babylon::Metric
  class ArgumentError < ArgumentError; end

  def initialize name, category, amount
    @name = name
    @category = category
    @amount = amount
  end

  def self.call name:, category:, amount:
    new(name, category, amount).()
  end

  # What is it doing here exactly is it calling Counter or Gauge record method from here, 
  # based on valid method returns true or false?

  def call
    valid? ? record : notify
  rescue => e
    begin
      raise Babylon::Error, e.inspect
    rescue Babylon::Error => e
      Babylon::Event.(event: "babylon.error", error: e)
    end
  end

  def valid?
    # do validation
  end

  def notify
    # do some stuff 
  end

end

I think that the call method is able to in turn call Counter class and Gauge class record methods If the valid method returns true, But I don't know how it can call as these are protected members?.

If you initialize the parent class and call the call or record method on it, you will get a NoMethodError as you would expect. The trick is, that all of the methods of the parent are available in the children as well.

That means that if you initiate a child class and call record on it, the record method on the child class is called exactly as expected.

But also, if you call the call method on the child class, it will use the implementation from the parent, but in the context of the child class, meaning that the record method called in it, will be available and no error is raised.

In Ruby, protected methods can only be called with either:

  • An implicit receiver (ie say_hello instead of eg self.say_hello )
  • An explicit receiver in the same object family (self and descendants)

In the parent class, you can see that record is called with an implicit receiver, which means that the method can be either public, protected, or private.

For example:

class Foo
  def say_hello
    whisper_hello # implicit receiver
  end
end

class Bar < Foo
  private # protected would work as well in this example

  def whisper_hello
    puts "(hello)"
  end
end

In this example, Foo.new.say_hello will fail because whisper_hello isn't defined in the parent class (in other words you could say that Foo is an abstract class); but Bar.new.say_hello will work just fine.

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