Рубиновый эквивалент `repr()` Python?

Существует ли Ruby-эквивалент метода Python repr? Я хочу получить строковое представление любого заданного рубинового объекта, в котором перечислены все атрибуты, их значения и все методы.

Я определил следующий метод, но мне интересно, есть ли более канонический способ сделать это...

def repr
  attrhash = {}
  instance_variables.sort.each {
    |v|
    attrhash[v] = instance_variable_get(v)
  }
  [ self, self.class.instance_methods.sort, attrhash ].to_s
end

В идеале я бы не хотел включать этот метод в каждый класс, для которого мне нужны его repr-подобные данные, и мне интересно, существует ли стандартный рубиновый механизм для получения этой информации для любого данного объекта.


person HippoMan    schedule 20.10.2019    source источник


Ответы (3)


В Ruby нет эквивалента Python __repr__. На первый взгляд самым близким может быть казаться #inspect из-за следующих сходств:

Обычно используется для отладки, […]

и

Возвращает строку, содержащую удобочитаемое представление obj.

Но есть важное отличие:

Если это вообще возможно, это должно выглядеть как допустимое выражение Python, которое можно использовать для воссоздания объекта с тем же значением (при соответствующей среде).

и

Для многих типов эта функция пытается вернуть строку, которая дала бы объект с тем же значением при передаче в eval()

#inspect в Ruby фокусируется на том, чтобы быть удобочитаемым, тогда как __repr__ в Python пытается быть "eval()-удобным для чтения" (т.е. eval(repr(e)) == e), другими словами, он должен быть удобным для машинного чтения.

person Jörg W Mittag    schedule 20.10.2019
comment
Спасибо, но inspect не показывает имена методов. - person HippoMan; 20.10.2019
comment
Да, как я уже сказал, в Ruby нет эквивалента. - person Jörg W Mittag; 20.10.2019
comment
Я знаю, и никакой критики не было предназначено для того, что Вы поделились. Я просто уточняю, в свете того, что вы объяснили, почему inspect мне недостаточно. - person HippoMan; 20.10.2019

Основываясь на полезных комментариях от jeremy04 и Jörg W Mittag, я понимаю, что в Ruby нет ничего, что соответствовало бы repr, и что я не могу использовать простой repr-подобный метод во всех экземплярах класса без обезьяньего исправления самого class Object. Однако я понимаю, что если я просто сделаю repr отдельной функцией, я смогу получить ту же функциональность без обезьяньих исправлений и выполняя repr(obj) вместо obj.repr всякий раз, когда мне нужна эта информация для данного объекта. Работает следующая автономная функция...

def repr(obj)
  attrhash = {}
  obj.instance_variables.sort.each {
    |v|
    attrhash[v] = instance_variable_get(v)
  }
  {
    :string     => obj.inspect,
    :methods    => obj.class.instance_methods.sort,
    :attributes => attrhash
  }
end

У меня есть эта функция, возвращающая хеш вместо строки, чтобы я мог делать такие вещи:

repr(obj)[:attributes].

Я всегда могу сделать repr(obj).to_s, если мне нужна строка.

Кроме того, я мог бы превратить это в класс. Я оставлю это в качестве упражнения для читателя. :)

person HippoMan    schedule 20.10.2019

inspect является ближайшим эквивалентом repr в Ruby, но он не показывает общедоступные методы.

Если вам нужен инструмент: pry https://github.com/pry/pry

Команда ls делает именно то, что вы хотите. Вы также можете интегрировать pry в свою консоль irb/rails.

В качестве альтернативы вы можете использовать свой метод для обезьяньего патча class Object, но я чувствую, что это слишком экстремальный выбор, довольно много недостатков.

person jeremy04    schedule 20.10.2019
comment
pry выглядит весьма полезным. Он предлагает намного больше, чем то, что я прошу здесь, но это нормально. :) - person HippoMan; 20.10.2019