Indexing and Appending
Part of the Object Oriented Programming section of Coddy's Ruby journey. Lesson 39 of 57.
obj[key] calls the method [], and obj[key] = value calls []=. Defining them gives a class the square-bracket syntax of arrays and hashes, with whatever meaning suits it:
class Inventory
def initialize
@stock = Hash.new(0)
end
def [](name)
@stock[name]
end
def []=(name, qty)
@stock[name] = qty
end
end
inv = Inventory.new
inv["apple"] = 5
inv["apple"] += 2
puts inv["apple"]
puts inv["pear"]Output:
7
0[] can take several arguments, for example a row and a column, and it can check them. IndexError is the usual error for a position that does not exist:
class Board
def initialize(size)
@size = size
@cells = Array.new(size) { Array.new(size, ".") }
end
def [](row, col)
check(row, col)
@cells[row][col]
end
def []=(row, col, mark)
check(row, col)
@cells[row][col] = mark
end
def check(row, col)
raise IndexError, "no cell #{row},#{col}" unless row.between?(0, @size - 1) && col.between?(0, @size - 1)
end
end
b = Board.new(3)
b[1, 1] = "X"
puts b[1, 1] + b[0, 0]
begin
b[3, 0]
rescue IndexError => e
puts e.message
endOutput:
X.
no cell 3,0<< is the append operator. Returning self from it allows chaining, like list << a << b on arrays:
class Shelf
def initialize
@books = []
end
def <<(title)
@books << title
self
end
def to_s
@books.join(" | ")
end
end
shelf = Shelf.new
shelf << "Dune" << "Emma" << "Ulysses"
puts shelfOutput:
Dune | Emma | UlyssesAn assignment through []= returns the assigned value, not what the method returns, as with any setter. Brackets and << give a class a small, familiar interface:
inv["apple"] = 5 # calls []=("apple", 5), the expression is 5
inv["apple"] # calls []("apple")
shelf << "Dune" << "Emma" # << returns self, so it chains
board[1, 2] = "X" # []=(1, 2, "X")Challenge
EasyComplete the class Inventory. inv[name] returns the quantity of an item (0 when unknown), inv[name] = qty sets it, and inv << name adds one of that item and returns the inventory so calls can be chained. to_s returns apple: 3, pear: 1 in alphabetical order of the names, leaving out items with quantity 0, or empty.
The supplied code reads commands: set apple 5, add apple pear pear (which chains << for every name), get apple and print, and prints the result of get and print.
Your code goes in inventory.rb. main.rb holds the supplied input/output code and cannot be edited.
Try it yourself
require_relative 'inventory'
# Supplied input/output code: keep it as it is
input = []
while (line = gets)
input << line.chomp
end
inv = Inventory.new
input.each do |line|
cmd, *args = line.split
case cmd
when "set" then inv[args[0]] = args[1].to_i
when "add" then args.reduce(inv) { |target, name| target << name }
when "get" then puts inv[args[0]]
else puts inv
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