1

I'm having some trouble understanding scope in ruby.

Here is a link to a repo if you'd like to download/run what I'm talking about to see for yourself:

https://github.com/minervadreaming/killshit

I have several .rb files present - specifically, I'm having an issue calling a class method from an instance. Seems like I'm not properly following scope, but I'm not sure how or why.

Here is a snippet from room.rb:

module KillShit
    class Room
        attr_reader :player, :monster, :game

        def initialize(player, monster, game)
            @player = player
            @monster = monster
            @game = game
        end

        def action
            outline
            Player.describe(player)
            vs
            Monster.describe(monster)
            outline

            #rolling a d20 to see who takes a turn
            turn = rand(1..100)

            if turn <= 20
                monster_attack
            else
                puts "What would you like to do?"
                puts "1. Attack!"
                puts "2. Defend!"
                puts "3. Run away!"
                #Give the player magic if they're at least level 2
                if player.maglevel >= 1
                    puts "4. Cast spell"
                else
                end

                prompt; action = gets.chomp

                if action == "1"
                    attack(player, monster)
                elsif action == "2"
                    defend
                elsif action == "3"
                    flee
                elsif action == "4" && player.maglevel >= 1
                    magic
                else
                    action
                end
            end
        end

        def magic
            puts "What magic would you like to cast?"
            if player.maglevel == 1
                puts "1. Heal"
                puts "2. Fireball"
                puts "3. Tremor"
                prompt; magic = gets.chomp

                if magic == "1"
                    Spells.heal(player)
                elsif magic == "2"
                    Spells.fireball(player, monster)
                elsif magic == "3"
                    Spells.tremor(player, monster)
                else
                    magic
                end
            elsif player.maglevel == 2
                puts "1. Greater Heal"
                puts "2. Firestorm"
                puts "3. Earthquake"
                prompt; magic = gets.chomp

                if magic == "1"
                    Spells.greaterheal(player)
                elsif magic == "2"
                    Spells.firestorm(player, monster)
                elsif magic == "3"
                    Spells.earthquake(player, monster)
                else
                    magic
                end
            else
            end
        end
    end
end

As you can see, when the player chooses to cast a spell it calls out to a Spells class, which I have in spells.rb. Here is a snippet from that code:

require_relative 'room'
require_relative 'player'
require_relative 'monster'

module KillShit
    class Spells
        attr_accessor :player, :monster

    #Checking if user has enough MP to cast spell
        def self.mp_check(req, player)
            req_mp = req
            if player.mp < req_mp
                puts "#{player.name} doesn't have enough MP!"
                action
            else
            end
        end

        def self.heal(player)
            req_mp = 3
            Spells.mp_check(req_mp, player)

            player.mp -= req_mp
            amt = rand(3..10)
            player.hp += amt
            puts "#{player.name} has been healed by #{amt} HP!"
            Room.action
        end
    end
end

The problem is in the "Room.action" call at the end of the self.heal method (or just "action" as was my first attempt, as can be seen in the self.mp_check method). When it is hit, the following error is received:

spells.rb:27:in `heal': undefined method `action' for KillShit::Room:Class (NoMethodError)

I thought that it might've been because I needed to define "action" as a class method with "self." but that isn't doing it. I also thought that it's because I'm trying to call "action" from the Class itself as opposed to the instance of the class with which I am working, and so I should call .action but I can't figure out how to do so.

Any ideas? What should I be reading up on to better understand the concept behind what's happening here? Thanks!

1
  • Use the pry gem to help debug this. Make the program stop at before and after the lines of error. Commented Sep 16, 2014 at 23:32

2 Answers 2

2

You Should call the method Room#action like:

KillShit::Room.action
Sign up to request clarification or add additional context in comments.

2 Comments

I checked the file room.rb, in which you have declared a class method action and also in the instance methods of class Room, you are calling a method/variable with name "action". I guess this is creating some confusion.
If you are calling action from a instance method of a class then that should either be instance_method of that class.
0

Just after a brief look - you did not defined class but instance method action.

Class methods need to by referenced with keyword self or class name directly, so you would need fix the definition this way:

module KillShit
  class Room
    …
    def self.action
        …
    end
    …
  end
end

Updated answer:

module KillShit
  class Room
    def self.action
      puts 'action in Room !'
    end
  end

  class Spells
    def self.heal(player)
      Room.action
    end
  end
end

KillShit::Spells.heal('Wallace')
# action in Room !

3 Comments

Yes - that is what I thought, too, but I get the same result upon renaming to self.action. Do I need to call it in a different manner than "Room.action"?
You should not get the error then, no different way of call required. It looks you've messed up something different. Are you sure the module you are loading with require_relative 'room' is the fixed one ?
I've used your example and you can see it does work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.