Ruby and public_method_defined? : strange behaviour
Whilst reading through the book "The well grounded Rubyist", I came across some strange behaviour. The idea behind the code is using one's own method_missing method. The only thing I am not able to grasp is, why this code gets executed, as I do not have any Person.all_with_* class methods defined, which in turn means that the self.public_method_defined?(attr) returns true (attr is friends and then hobbies).
#!/usr/bin/env ruby1.9
class Person
PEOPLE = []
attr_reader :name, :hobbies, :friends
def initialize(mame)
@name = name
@hobbies = []
@friends = []
PEOPLE << self
end
def has_hobby(hobby)
@hobbies << hobby
end
def has_friend(friend)
@friends << friend
end
def self.method_missing(m,*args)
method = m.to_s
if method.start_with?("all_with_")
attr = method[9..-1]
if self.public_method_defined?(attr)
PEOPLE.find_all do |person|
person.send(attr).include?(args[0])
end
else
raise ArgumentError, "Can't find #{attr}"
end
else
super
开发者_开发问答 end
end
end
j = Person.new("John")
p = Person.new("Paul")
g = Person.new("George")
r = Person.new("Ringo")
j.has_friend(p)
j.has_friend(g)
g.has_friend(p)
r.has_hobby("rings")
Person.all_with_friends(p).each do |person|
puts "#{person.name} is friends with #{p.name}"
end
Person.all_with_hobbies("rings").each do |person|
puts "#{person.name} is into rings"
end
The output is
is friends with
is friends with
is into rings
which is really understandable, as there is nothing to be executed.
hmm, is is because I have accessors for friends and hobbies? But I thought they would only be accessed in instances, and not on the class-object level.
Assuming that the code pasted into your question is the exact code that you're running then the problem is a typing mistake in initialize
:
def initialize(
mame)
should be def initialize(
name)
If the name of the parameter name
is mistyped then this causes the line @name = name
, rather than meaning
"set @name
to the value of the parameter"
to mean
"set @name
to the value returned by the method name
(your attr reader)" (which of course is nil
because it hasn't been set)
Hence all your Beatles get left without their names being set and the output is the 2 friends for Paul and Ringo's hobby but with all the names blank.
精彩评论