Method_missing не работает, когда это должно

У меня есть класс Team в моей программе, и я пытаюсь использовать method_missing, но вместо запуска функции, когда метод не существует, он выдает мне ошибку:"неопределенный метод`hawks'для Team:Class (NoMethodError)"

Мой код выглядит следующим образом:

class Team
  attr_accessor :cust_roster, :cust_total_per, :cust_name, :cust_best_player
  @@teams = []
  def initialize(stats = {})
    @cust_roster = stats.fetch(:roster) || []
    @cust_total_per = stats.fetch(:per)
    @cust_name = stats.fetch(:name)
    @cust_best_player = stats.fetch(:best)
    @@teams << self

  end
  def method_missing(methId)
    str = methID.id2name
    Team.new(roster:[], per: 0, name: str.uppercase, best: 0)

  end



  class <<self
    def all_teams
      @@teams
    end
  end

end
hawks = Team.hawks

2 ответа

Решение

Есть ряд проблем с вашим кодом. Давайте пройдемся по одному.

Из документации,

method_missing (* args) private Вызывается Ruby, когда obj отправляется сообщение, которое он не может обработать.

Вот message относится к method, В ruby, когда вы вызываете метод объекта, вы на самом деле sendв message к object

Чтобы лучше это понять, попробуйте это в оболочке irb.

1+2
=> 3
1.send(:+,2)
=> 3

Здесь 1 и 2 являются объектами Fixnum учебный класс. Вы можете подтвердить это, используя 1.class, Хорошо, вернемся к вашему вопросу. Итак, method_missing метод должен быть вызван на экземпляр.

team = Team.new
team.hawks

Если вы попробуете приведенный выше фрагмент кода, вы получите сообщение об ошибке 'fetch': key not found: :roster (KeyError)

Вы можете обойти это, передав default value в качестве второго параметра fetch метод. Замените свой initialize метод с

def initialize(stats = {})
  @cust_roster = stats.fetch(:roster, [])
  @cust_total_per = stats.fetch(:per, 0)
  @cust_name = stats.fetch(:name, "anon")
  @cust_best_player = stats.fetch(:best, "anon")
  @@teams << self

конец

Если вы выполните сценарий, вы получите stack level too deep (SystemStackError) из-за небольшой опечатки в этой строке.

str = methID.id2name

В определении метода вы получаете аргумент с именем methId но внутри ты пытаешься позвонить methID, Исправить это с

str = methId.id2name

Если вы выполните свой скрипт, вы снова получите сообщение об ошибке undefined method uppercase for "hawks":String (NoMethodError)

Это потому что нет uppercase метод на строки. Вы должны вместо этого использовать upcase метод.

Team.new(roster:[], per: 0, name: str.upcase, best: 0)

и тебе должно быть хорошо идти.

Для получения дополнительной информации см. http://apidock.com/ruby/BasicObject/method_missing

Надеюсь это поможет!

class Team
  attr_accessor :cust_roster, :cust_total_per, :cust_name, :cust_best_player
  @@teams = []
  def initialize(stats = {roster: [], per: 0, name: "", best: 0}) # I added the default values here. 
    @cust_roster = stats.fetch(:roster)
    @cust_total_per = stats.fetch(:per)
    @cust_name = stats.fetch(:name)
    @cust_best_player = stats.fetch(:best)
    @@teams << self

  end
  def method_missing(name, *args)
    self.cust_name = name.to_s.upcase
  end

  class << self
    def all_teams
      @@teams
    end
  end

end

team_hawks = Team.new #=> create an instance of Team class, I renamed the object to avoid confusions. 
team_hawks.hawks      #=> called method_missing which assigned the cust_name variable to "HAWKS"

team_hawks.cust_name  #=> HAWKS, so cust_name is assigned to be hawks. This is to check if the assignment worked. 

Надеюсь, это то, что вы ищете.

Другие вопросы по тегам