I thought that defining a to_s
method for a custom class meant that calling the puts
method on that class would return an output as specified by to_s
. In this program, however, I only get the result I crave if I write puts bingo_board.to_s
. What is going on?
class BingoBoard < Array
@@letters = %w[B I N G O]
def initialize
# populates an 5x5 array with numbers 1-100
# to make this accessible across your methods within this class, I made
# this an instance variable. @ = instance variable
@bingo_board = Array.new(5) {Array.new(5)}
@bingo_board.each_with_index do |column, i|
rangemin = 15 * i + 1
@bingo_board[i] = (rangemin..(rangemin+14)).to_a.sample(5)
end
@bingo_board[2][2] = "X" # the 'free space' in the middle
@game_over = false
end
def game_over?
@game_over
end
def generate_call
....
end
def compare_call(call)
@bingo_board[@@letters.index(call[0])].include? call[1]
end
def react_to_call(call)
...
end
def check_board
...
end
def show_column(num)
...
end
def to_s
result = ""
0.upto(4) do |val|
result += " " + @@letters[val] + " "
end
result += "\n\n"
0.upto(4) do |row|
0.upto(4) do |col|
val = @bingo_board[col][row]
result += " " if val.to_i < 10
result += val.to_s + " "
end
result += "\n"
end
result
end
end
my_board = BingoBoard.new
counter = 0
until my_board.game_over?
puts my_board.to_s # renders the board in accordance with my to_s method
call = my_board.generate_call
counter += 1
puts "\nThe call \# #{counter} is #{call[0]} #{call[1]}"
my_board.react_to_call(call)
gets.chomp
end
puts my_board # renders bubkes (i.e., nothing)
puts "\n\n"
puts "Game over"
Its because you'r extending from Array. That's why you're getting the wierd behavior. I don't see where you need the extending from so just remove that and things will work as you expect.
Here's a more detaled answer if you'd like to know why this is happening. Basically puts makes an exception for arrays so when an array is passed puts is called on each member. Ruby Array#puts not using overridden implementation?
As @jörgwmittag said, this is a special case. The IO#puts
method treats arrays - which means anything that responds to to_ary
- differently. It calls to_ary
first and then iterates over each element of the resulting array, and only calls to_s
on them. It never calls to_s
on the array itself.
If you delegate to a member array instead of subclassing from Array
, you have finer-grained control over what gets "inherited" (delegated). Then you can exclude to_ary
from the delegation, which will prevent puts
from seeing your object as an Array and triggering this behavior.
Other general solutions:
Use string interpolation or explicit to_s
calls so that what puts
receives is already a string:
puts "#{bingo_board}" puts bingo_board.to_s
Use print
or printf
instead of puts
:
print bingo_board,"\\n" printf "%s\\n",bingo_board
If the object is an Array
or can be converted to one (ie it implements to_ary
), then puts
will not call to_s
on the object, but rather iterate over the object and print each object within by calling to_s
on it.
See:
puts [1, 2]
# 1
# 2
[1, 2].to_s
# => '[1, 2]'
This is actually documented , although somewhat implicitly:
If called with an array argument, writes each element on a new line.
Looks like it runs Array#inspect
method instead of your custom to_s
. Adding alias_method :inspect, :to_s
just after ending of the to_s
definition will help you.
But it'll work only with p
, because puts
runs each(&:inspect)
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.