Menu
Coddy logo textTech

self nos Métodos

Parte da seção Programação orientada a objetos do Journey de Ruby da Coddy. Lição 9 de 57.

Dentro de um método, name = value sempre cria uma variável local, mesmo quando a classe tem um setter name=. Para chamar o setter, escreva o receptor: self.name = value:

class Player
  attr_accessor :level

  def initialize
    @level = 1
  end

  def broken_level_up
    level = level + 1
  rescue NoMethodError
    puts "level is a new local variable here, still nil"
  end

  def level_up
    self.level = level + 1
  end
end

p1 = Player.new
p1.broken_level_up
p1.level_up
puts p1.level

Saída:

level is a new local variable here, still nil
2

Os leitores não precisam de self.: level e self.level chamam o mesmo método. O estilo usual escreve self. apenas onde o Ruby precisa dele, antes de um setter:

class Rect
  attr_accessor :w, :h

  def initialize(w, h)
    @w = w
    @h = h
  end

  def area
    w * h
  end

  def double!
    self.w = w * 2
    self.h = self.h * 2
    self
  end
end

puts Rect.new(2, 3).double!.area

Saída:

24

Chamar o setter a partir de initialize com self. faz com que os novos objetos passem pela mesma verificação que as alterações posteriores, portanto a regra fica em um só lugar:

class Product
  attr_reader :price

  def initialize(price)
    self.price = price
  end

  def price=(value)
    raise ArgumentError, "price must be positive" if value <= 0

    @price = value
  end
end

puts Product.new(5).price
begin
  Product.new(0)
rescue ArgumentError => e
  puts e.message
end

Saída:

5
price must be positive

O que self representa depende de onde o código é executado. Dentro de um método de instância, ele é a instância; no corpo da classe, fora de qualquer método, ele é a própria classe:

class Robot
  puts "in the class body, self is #{self}"

  def whoami
    "in a method, self is a #{self.class}"
  end
end

puts Robot.new.whoami

Saída:

in the class body, self is Robot
in a method, self is a Robot
challenge icon

Desafio

Fácil

A classe Account tem um setter personalizado balance= que gera ArgumentError com balance cannot be negative para um valor abaixo de 0. Complete initialize(owner, balance), deposit(amount) e withdraw(amount) para que toda alteração do saldo passe por esse setter com self., incluindo o saldo inicial.

O código fornecido lê o proprietário e o saldo inicial, depois recebe os comandos +n (depósito) ou -n (saque). Ele imprime Ada: 120 após cada comando, ou a mensagem de erro e o saldo inalterado. Um saldo inicial inválido imprime apenas a mensagem de erro.

Seu código deve ser colocado em account.rb. main.rb contém o código fornecido de entrada/saída e não pode ser editado.

Experimente você mesmo

require_relative 'account'

# Código de entrada/saída fornecido: mantenha-o como está
input = []
while (line = gets)
  input << line.chomp
end
begin
  account = Account.new(input[0], input[1].to_i)
  input.drop(2).each do |cmd|
    begin
      amount = cmd[1..].to_i
      cmd.start_with?("+") ? account.deposit(amount) : account.withdraw(amount)
    rescue ArgumentError => e
      puts e.message
    end
    puts "#{account.owner}: #{account.balance}"
  end
rescue ArgumentError => e
  puts e.message
end
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação orientada a objetos

Pratique por conta própria: Compilador de Ruby online