self in Methods
Part of the Object Oriented Programming section of Coddy's Ruby journey. Lesson 9 of 57.
Inside a method, name = value always creates a local variable, even when the class has a setter name=. To call the setter, write the receiver: 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.levelOutput:
level is a new local variable here, still nil
2Readers need no self.: level and self.level call the same method. The usual style writes self. only where Ruby needs it, in front of a 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!.areaOutput:
24Calling the setter from initialize with self. makes new objects pass the same check as later changes, so the rule lives in one place:
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
endOutput:
5
price must be positiveWhat self is depends on where the code runs. Inside an instance method it is the instance; in the class body, outside every method, it is the class itself:
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.whoamiOutput:
in the class body, self is Robot
in a method, self is a RobotChallenge
EasyThe class Account has a custom setter balance= that raises ArgumentError with balance cannot be negative for a value below 0. Complete initialize(owner, balance), deposit(amount) and withdraw(amount) so every change of the balance goes through that setter with self., including the starting balance.
The supplied code reads the owner and the starting balance, then commands +n (deposit) or -n (withdraw). It prints Ada: 120 after each command, or the error message and the unchanged balance. An invalid starting balance prints the error message only.
Your code goes in account.rb. main.rb holds the supplied input/output code and cannot be edited.
Try it yourself
require_relative 'account'
# Supplied input/output code: keep it as it is
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
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Classes and Objects
Working With FilesDefining ClassesInstance VariablesMethods and selfto_s and inspectRecap - Library Card7Polymorphism and Duck Typing
PolymorphismDuck TypingAbstract Methodscase and ClassesRecap - Payment Methods2Accessors and Self
Readers and WritersCustom Settersself in MethodsIdentity and EqualityRecap - Contact List8Special Methods
Equality and hashOperator MethodsIndexing and AppendingCustom CollectionsRecap - Fractions11Project: Library Management
Books and MembersBorrowing Books3Class Methods and Variables
Class MethodsClass Instance VariablesConstantsFactory MethodsRecap - Coupon CodesPractice on your own: Online Ruby compiler