Ruby: Can I use instance methods inside a class method?
-
17-06-2021 - |
سؤال
I have a class that contains this class method:
def self.get_event_record(row, participant)
event = Event.where(
:participant_id => participant.id,
:event_type_code => row[:event_type],
:event_start_date => self.format_date(row[:event_start_date])
).first
event = Event.new(
:participant_id => participant.id,
:event_type_code => row[:event_type],
:event_start_date => self.format_date(row[:event_start_date])
) if event.blank?
event
end
And I also have, in the same class, an instance method:
def format_date(date)
parsed_date = date.split('/')
# if month or day are single digit, make them double digit with a leading zero
if parsed_date[0].split("").size == 1
parsed_date[0].insert(0, '0')
end
if parsed_date[1].split("").size == 1
parsed_date[1].insert(0, '0')
end
parsed_date[2].insert(0, '20')
formatted_date = parsed_date.rotate(-1).join("-")
formatted_date
end
I'm getting an 'undefined method' error for #format_date
. (I tried it without the self
in front, at first). Can you not use instance methods in class methods of the same class?
المحلول
Short answer is no, you cannot use instance methods of a class inside a class method unless you have something like:
class A
def instance_method
# do stuff
end
def self.class_method
a = A.new
a.instance_method
end
end
But as far as I can see, format_date
does not have to be an instance method. So
write format_date like
def self.format_date(date)
# do stuff
end
نصائح أخرى
Just create class method
def self.format_date (..)
...
end
And if u need instance method, delegate it to class method
def format_date *args
self.class.format_date *args
end
And i don't think that it is good idea to call instance methods from class scope
You could do YourClassName.new.format_date(your_date)
, although I think it's pretty clear you should be restructuring your code - this method probably doesn't belong on an instance. Why don't you extend the Date Class, or make format_date
a class method on the class you are using?
EDIT: Here are a few other things to think about with your code:
- Your whole
format_date
method goes to a lot of lengths to manipulate dates as strings. Why not use Ruby's Date Class? UsingDate.parse
orDate.strptime
or even"01/01/2001".to_date
might be useful depending on your locale Consider extending the String class for your method, if you really need to make your own method:
class String def to_friendly_formatted_date Date.strptime(self, "%d/%m/%y") end end "01/08/09".to_friendly_formated_date
Your class method is crying our for the
find_or_initialize_by
helper methods:self.get_event_record(row, participant) find_or_initialize_by_participant_id_and_event_type_code_and_event_start_date(:participant_id => participant.id, :event_type_code => row[:event_type_code], :event_start_date => row[:event_start_date].to_friendly_formatted_date) end
By god it's long, but it achieves what you're trying to do more elegantly (although I'm open to argument!)