开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜