1

I have a Team class in my program and I am trying to use method_missing but instead of running the function when the method doesn't exist, it gives me an error:"undefined method `hawks' for Team:Class (NoMethodError)"

My code is as follows:

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 Answers2

5

There are a number of problems with your code. Let's go through one by one.

From the documentation,

method_missing(*args) private Invoked by Ruby when obj is sent a message it cannot handle.

Here message refers to the method. In ruby, whenever you're calling a method on an object, you're actually sending a message to the object

To better understand this, try this in the irb shell.

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

Here 1 and 2 are objects of Fixnum class. You can confirm that by using 1.class. Ok, back to your question. So, a method_missing method should be called on an instance.

team = Team.new
team.hawks

If you try the above piece of code, you'll get an error saying 'fetch': key not found: :roster (KeyError)

You can get around this by passing a default value as the second parameter to fetch method. Replace your initialize method with

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

end

If you execute the script, you'll get a stack level too deep (SystemStackError) because of a small typo in this line.

str = methID.id2name

In the method definition, you're receiving an argument with the name of methId but inside you're trying to call methID. Fix it with

str = methId.id2name

If you execute your script, you'll again get an error saying undefined method uppercase for "hawks":String (NoMethodError)

This is because there is no uppercase method on strings. You should instead use the upcase method.

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

and you should be good to go.

For more, see http://apidock.com/ruby/BasicObject/method_missing

Hope this helps!

Arun Kumar Mohan
  • 11,517
  • 3
  • 23
  • 44
0
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. 

Hope this is what you are looking for.

davidhu
  • 9,523
  • 6
  • 32
  • 53