Reputation: 7627
I made a User
class containing a class method find_by_email
:
class User
attr_accessor :email
def initialize
@email="[email protected]"
end
def self.find_by_email(pattern)
ObjectSpace.each_object(self) do |object|
puts object.email+" "+(object.email.include? pattern).to_s
end
end
end
In irb
I try:
irb> user1=User.new
irb> user2=User.new
irb> user1.email="[email protected]"
irb> User.find_by_email "s"
which returns:
[email protected] false
[email protected] true
I would like find_by_email
to return an array with the matching emails. So for this example it should only return ["[email protected]"]
. How can I refactor the find_by_email
class to achieve this?
Upvotes: 1
Views: 606
Reputation: 110685
This is an example of the approach I believe @tadman is suggesting.
class User
attr_accessor :email
@users = []
def initialize
@email="[email protected]"
self.class.instance_variable_get(:@users) << self
end
def self.select_by_email(pattern)
instance_variable_get(:@users).select { |instance|
instance.email.include?(pattern) }
end
end
user1=User.new
#=> #<User:0x000055aaab80f6f0 @email="[email protected]">
user2=User.new
#=> #<User:0x000055aaab8536c0 @email="[email protected]">
user1.email="[email protected]"
a = User.select_by_email "s"
#=> [#<User:0x000055aaab80f6f0 @email="[email protected]">]
Note:
User.instance_variable_get(:@users)
#=> [#<User:0x000055aaab80f6f0 @email="[email protected]">,
# #<User:0x000055aaab8536c0 @email="[email protected]">]
We might then write:
a.map { |user| user.email }
#=> ["[email protected]"]
I used the method Object#instance_variable_get, rather than creating a "getter" method for @users
, because I do not want the content of that (class) instance variable to be accessible outside the class (though I guess I could have made that method private).
Upvotes: 2
Reputation: 7627
After reading the answer/comments I see how ObjectSpace
could affect performance if there are many classes and instances to look for. So I decided to use the following class (using code from another question):
class User
attr_accessor :email
@@instance_collector = []
def initialize
@email="[email protected]"
@@instance_collector << self
end
def self.find_by_email(pattern)
@@instance_collector.collect do |instance|
instance.email if instance.email.include? pattern
end.compact
end
end
Upvotes: 0
Reputation: 187044
Your method does not return but only prints out what it finds.
You need to create an array, add to it, then return it.
def self.find_by_email(pattern)
# Create an empty array to store the emails.
emails = []
# Search!
ObjectSpace.each_object(self) do |object|
# If it matches, put the email in the array.
if object.email.include? pattern
emails << object.email
end
end
# Return the array.
emails
end
And just a word of caution. You should probably stay away from ObjectSpace
. This very much gets you under the hood of a ruby application, and into some territory where you may not be ready to go. I would recommend studying a lot more ruby foundational concepts before using it. And even then, it's probably a bad idea.
Upvotes: 3