Ruby: можно ли использовать методы экземпляра внутри метода класса?


У меня есть класс, который содержит этот метод класса:

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

И у меня также есть, в том же классе, метод экземпляра:

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

Я получаю ошибку "неопределенный метод" для #format_date. (Сначала я попробовал без self спереди). Нельзя ли использовать методы экземпляра в методах класса того же класса?

3 9

3 ответа:

Короткий ответ-Нет, вы не можете использовать методы экземпляра класса внутри метода класса, если у вас нет чего-то вроде:

class A
  def instance_method
    # do stuff
  end

  def self.class_method
     a = A.new
     a.instance_method
  end
end
Но, насколько я могу видеть, format_date не обязательно должен быть методом экземпляра. Так напишите format_date как
def self.format_date(date)
   # do stuff
end

Просто создайте метод класса

def self.format_date (..)
  ...
end

И если вам нужен метод экземпляра, делегируйте его методу класса

def format_date *args
  self.class.format_date *args
end

И я не думаю, что это хорошая идея, чтобы вызвать методы экземпляра из области видимости класса

Вы могли бы сделать YourClassName.new.format_date(your_date), хотя я думаю, что довольно ясно, что вы должны реструктурировать свой код - этот метод, вероятно, не принадлежит экземпляру. Почему бы вам не расширить класс Date или не сделать format_date методом класса для класса, который вы используете?

EDIT: вот еще несколько вещей, о которых стоит подумать с вашим кодом:

  • весь ваш метод format_date идет на много длин, чтобы манипулировать датами как строками. Почему бы не использовать класс свиданий Руби? Использование Date.parse или Date.strptime или даже "01/01/2001".to_date может будьте полезны в зависимости от вашего региона
  • Рассмотрите возможность расширения класса String для вашего метода, Если вам действительно нужно создать свой собственный метод:

    class String
      def to_friendly_formatted_date
        Date.strptime(self, "%d/%m/%y")
      end
    end
    "01/08/09".to_friendly_formated_date
    
  • Ваш метод класса плачет наш для find_or_initialize_by вспомогательных методов:

    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
    
Клянусь Богом, это долго, но это достигает того, что вы пытаетесь сделать более элегантно (хотя я открыт для аргументации!)