Project

General

Profile

Bug #16111 ยป ruby-bug.rb

mtelford (Michael Telford), 08/19/2019 05:46 AM

 
#!/usr/bin/env ruby
#
# Tested in ruby 2.5.3 and 2.6.3 installed via rbenv.
#

class Name < String
# Name#to_hash gets called. But why?
def to_hash
puts 'Name#to_hash was called.'
end
end

class Person
attr_accessor :name

def initialize(name = 'world')
@name = name
end

# The key thing here is the method signature which must contain a default
# positional parameter followed by a default keyword parameter for the
# Name#to_hash method to be called. When calling Person#greet only the name
# parameter should be provided. See my example usage below.
def greet(name = @name, age: nil)
if age
puts "Hello #{name}, you are #{age}"
else
puts "Hello #{name}"
end
end
end

# [12] pry(main)> n = Name.new 'Michael'
# => "Michael"
# [13] pry(main)> p = Person.new
# => #<Person:0x00007ff0eab4d768 @name="world">
# [14] pry(main)> p.greet
# Hello world
# => nil
# [15] pry(main)> p.greet n
# Name#to_hash was called.
# Hello Michael
# => nil
# [16] pry(main)> p.greet n, age: 30
# Hello Michael, you are 30
# => nil

# Notice how `p.greet n` results in `Name#to_hash` being called. Why?
# This feels like a bug. I have a defined to_hash method in my code which is
# being called when I don't want it to be. It should also be noted that if Name
# didn't respond to :to_hash the code wouldn't complain about the missing
# method so something like the following must be happening:
# `obj.to_hash if obj.respond_to? :to_hash`.
    (1-1/1)