Custom Setters
Part of the Object Oriented Programming section of Coddy's Ruby journey. Lesson 8 of 57.
A setter is a method whose name ends in =. Writing it yourself instead of using attr_writer lets it clean up the value before storing it:
class Person
attr_reader :name
def name=(value)
@name = value.strip.capitalize
end
end
ada = Person.new
ada.name = " aDA "
puts "[#{ada.name}]"Output:
[Ada]A setter can also refuse a value by raising an error. The instance variable is only assigned when the value passes the check, so the object keeps its old state:
class Product
attr_reader :price
def initialize(price)
@price = price
end
def price=(value)
raise ArgumentError, "price must be positive, got #{value}" if value <= 0
@price = value
end
end
item = Product.new(10)
begin
item.price = -5
rescue ArgumentError => e
puts e.message
end
puts item.priceOutput:
price must be positive, got -5
10An assignment expression always returns the value on its right-hand side, not what the setter returns or stores. Read the attribute again to see the stored value:
class Thermometer
attr_reader :celsius
def celsius=(value)
@celsius = value.round
end
end
t = Thermometer.new
result = (t.celsius = 21.7)
puts result
puts t.celsiusOutput:
21.7
22A reader and a custom setter together give an attribute that outside code can read and change, but only to valid values. Keep the check in the setter only, so every change goes through the same rule:
class Volume
attr_reader :level
def level=(value)
raise ArgumentError, "level must be 0-10" unless (0..10).cover?(value)
@level = value
end
endChallenge
EasyComplete the class Person. Its setter name= removes spaces around the value and capitalizes each word ( ada lovelace becomes Ada Lovelace). Its setter age= raises ArgumentError with the message invalid age: 200 when the age is outside 0 to 150, and otherwise stores it. Both values can be read.
A new Person starts with the name Unknown and age 0. The supplied code reads commands name text or age n, applies them through the setters and prints the person as Ada Lovelace (36) after each command, or the error message when a setter refuses the value.
Your code goes in person.rb. main.rb holds the supplied input/output code and cannot be edited.
Try it yourself
require_relative 'person'
# Supplied input/output code: keep it as it is
input = []
while (line = gets)
input << line.chomp
end
person = Person.new
input.each do |line|
command, value = line.split(" ", 2)
begin
command == "name" ? person.name = value : person.age = value.to_i
puts "#{person.name} (#{person.age})"
rescue ArgumentError => e
puts e.message
end
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