Ruby and public_method_defined? : strange behaviour

Posted by aXon on Stack Overflow See other posts from Stack Overflow or by aXon
Published on 2010-04-25T14:12:43Z Indexed on 2010/04/25 14:23 UTC
Read the original article Hit count: 260

Filed under:

Hi there

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.

© Stack Overflow or respective owner

Related posts about ruby