18

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?

6
  • 2
    Why is format_date an instance method? It is not using anything from the instance. Commented Jun 28, 2012 at 13:04
  • Of course, you can't. In order to call an instance method you need an instance of your class. Commented Jun 28, 2012 at 13:06
  • @tdgs Good point. I made it an instance method because I thought that making it a class method would imply it was for public use, when the case is it's only for internal use Commented Jun 28, 2012 at 13:11
  • @KL-7 Of course, you're right. Like in my other comments, my intent was to just have a method that "helps" a class method in its class. Maybe making it a class method doesn't necessarily imply its for use outside the class, or maybe I need to take a different tact altogether Commented Jun 28, 2012 at 13:14
  • @steve_gallagher, you can make your class method private like that. Commented Jun 28, 2012 at 13:17

3 Answers 3

31

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
Sign up to request clarification or add additional context in comments.

2 Comments

I have a instance method because is called from a validation, and a class method than was fine to be able to call the instance method, to be DRY
Then do something like this class A; def instance_method; self.class.class_method; end; def self.class_method; -- do stuff -- ; end; end
6

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

3 Comments

class.format_args? Why are you calling a class method on the jeyword class?
That doesn't mean that calling it on the keyword class will do anything but have a syntax error. You need self.
Now I can happily give you +1, cause I like your answer.
3

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? Using Date.parse or Date.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!)

6 Comments

I originally had it as a class method, but, I was thinking (possibly erroneously) that class methods are meant to be used outside of the class, while this method is strictly an internal method.
I think that thought was erroneous! Instance methods should relate to the specific attributes of an instance of that class. Your method really has nothing to do with an instance at all. I'd turn it back into a class method. You have a few opportunities to re-factor your code, too - I'll edit my answer.
@steve_gallagher: You can make class methods private. Take a look at this gist.
@steve_gallagher Have edited my answer with a few other tips.
first_or_initialize is recommended atm
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.