-1

I'm a new coder trying to create a simple "Sword crafting" terminal app in ruby. So I've got a class with a few instanced variables I want to iterate upon depending on the users input (@strength and @speed). So here, if the user inputs that the grip is "straight" i want it to increase the instance variable "strength" by 5 - but for some reason it's not editing it no matter what I do. I've already set "strength" as attr_accessor, and i've tried making the method manually as well - but I still can't iterate upon it. What am i doing wrong?

class Weapon
    attr_reader :id, :weapon_name, :guard, :blade
    attr_accessor :grip, :strength, :speed

    SWORDS = []

    def initialize(weapon_name, grip, guard, blade)
        @id = SWORDS.length + 1
        @weapon_name = weapon_name
        @grip = grip.to_str
        @guard = guard
        @blade = blade
        @strength = 0
        @speed = 0
        SWORDS << self
    end

    def strength=(strength)
        if @grip == "straight"
            @strength = strength + 5
        end
    end
    
    def to_s
        
        "Your weapon is called: #{@weapon_name}
            The grip is: #{@grip}
            The guard is: #{@guard}
            The blade is: #{@blade}
            Total stats are: Strength = #{@strength} and Speed = #{@speed}"
    
    end
end

zedd0
  • 31
  • 4
  • 2
    There is no user input anywhere in this code. Consider reducing your problem to a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). As of right now, it's not reproducible; I can't copy this into a new file and experience the problem you're describing. – Silvio Mayolo Apr 05 '21 at 04:00
  • Oh sorry, I forgot to mention I'm testing it in IRB. I do a test case like load "file.rb". and then w = Weapon.new("swordname", "straight", "forward", "curved") – zedd0 Apr 05 '21 at 04:06
  • Your code works as expected. When I initialize a Weapon with the line from your comment and the call `w.strength = 10` and `w.to_s` then `Total stats are: Strength = 15 and Speed = 0"` is returned. Seems like you your conditional assignment works as expected. – spickermann Apr 05 '21 at 07:31
  • This thread may answer some questions for you: https://stackoverflow.com/questions/12924080/difference-between-instance-variable-and-attr-accessor – fatfrog Apr 05 '21 at 14:20

2 Answers2

1

Accessors are only called if you refer to a name on the class.

@strength = 0

This doesn't call an accessor. Ever. Even if one is defined.

self.strength = 0

This will call an accessor. Now, attr_accessor defines strength and strength=. If you're planning to write strength= yourself, then you want attr_reader, which does not define strength= for you.

class Weapon
  attr_reader :strength

  def initialize()
    ...
    self.strength = 0
  end

  ...

  def strength=(value)
    ...
  end

end
Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116
0

It might be easier to modify the getter:

class Weapon
  attr_accessor :grip, :strength

  # ...

  def strength
    if grip == 'straight'
      @strength + 5
    else
      @strength
    end
  end
end
w = Weapon.new
w.strength = 10

w.strength
#=> 10

Since the getter always re-calculates the value, you can modify both, strength and grip and it will instantly reflect the change:

w.grip = 'straight'
w.strength
#=> 15

w.strength = 12
w.strength
#=> 17

w.grip = 'curved'
w.strength
#=> 12

To avoid confusion, you could call the initial strength base_strength.

Stefan
  • 109,145
  • 14
  • 143
  • 218