Рекурсивный to_s для вложенных структур с пользовательским форматом - PullRequest
0 голосов
/ 27 декабря 2011

Я создал OpenStruct -подобный класс с именем Ribbon:

class Ribbon < BasicObject
  def __hash__
    @hash ||= {}
  end

  def initialize(hash = {}, &block)
    __hash__.merge! hash, &block
    Ribbon.convert_all! self
  end

  def self.convert(object)
    case object
      when ::Hash then self.new object
      when ::Array then object.map { |element| convert element }
      else object
    end
  end

  def self.convert_all!(ribbon)
    ribbon.__hash__.each do |key, value|
      ribbon[key] = case value
        when Ribbon then convert_all! value
        else convert value
      end
    end
    ribbon
  end
end

Не включены: [key], [key] = value и method_missing. Полный код .

Я бы хотел предоставить способ настройки строки, сгенерированной to_s и inspect. Я хочу сделать так, чтобы пользовательский формат также применялся к вложенным Ribbon s:

hash = { a: { b: { c: 'd' } }, e: 'f' }
ribbon = hash.to_ribbon # Ribbon.new(self)

ribbon.to_s { |k, v| "#{k} -> #{v}" }
=> { Ribbon a -> { Ribbon b -> { Ribbon c -> d } }, e -> f }

Моя первая попытка состояла в следующем:

def to_s(&b)
  # __h__ contains the key => value mappings.
  v = __h__.map { |k, v| b ? b.call(k, v) : "#{key}:#{value}" }
  "{ Ribbon #{v.join ', '} }"
end

# Format is applied only for the receiver.
=> { Ribbon a -> { Ribbon b:{ Ribbon c:d } }, e -> f }

Поскольку Ribbon объекты являются особым случаем, я подумал, что перехватил бы и обработал их специально:

def to_s(&b)
  v = __h__.map do |k, v|
    case v
      when Ribbon then v.to_s &b
      else b ? b.call(k, v) : "#{key}:#{value}"
    end
  end
  "{ Ribbon #{v.join ', '} }"
end

# Now, the keys for all nested hashes but the deepest are hidden.
=> { Ribbon { Ribbon { Ribbon c -> d } }, e -> f }

У меня проблемы с выяснением этого. Как лучше всего решить эту проблему?

1 Ответ

2 голосов
/ 27 декабря 2011

Попробуйте это:

def to_s(&b)
  v = __h__.map do |k, v|
    b ? b.call(k, v.to_s(&b)) : "#{k}: #{v}"
  end
  "{ Ribbon #{v.join ', '} }"
end

Тестирование:

r = Ribbon.new({a: Ribbon.new({b: Ribbon.new({c: 'd'})}), e: 'f'})

puts r.to_s
 => { Ribbon a: { Ribbon b: { Ribbon c: d } }, e: f }

puts r.to_s {|k, v| "#{k}: #{v}"}
 => { Ribbon a: { Ribbon b: { Ribbon c: d } }, e: f }

puts r.to_s {|k, v| "#{k} => #{v}"}
 => { Ribbon a => { Ribbon b => { Ribbon c => d } }, e => f }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...