class NestedText::Dumper

Dumping with recursive DFS traversal of the object references.

Public Class Methods

add_prefix(prefix, target) click to toggle source
# File lib/nestedtext/dumper.rb, line 23
def self.add_prefix(prefix, target)
  if target.empty? || target[0] == "\n"
    "#{prefix}#{target}"
  else
    "#{prefix} #{target}"
  end
end
multiline_key?(key) click to toggle source
# File lib/nestedtext/dumper.rb, line 31
def self.multiline_key?(key)
  syntax1 = '{[#'
  syntax2 = ':->'

  key.empty? ||
    key != key.strip ||
    key.include?("\n") ||
    key.include?(': ') ||
    syntax1.include?(key.lstrip[0]) ||
    (syntax2.include?(key.lstrip[0]) && key.lstrip[1] == ' ')
end
new(indentation, strict) click to toggle source
# File lib/nestedtext/dumper.rb, line 10
def initialize(indentation, strict)
  @indentation = indentation
  @strict = strict
  @traced_cycles = nil
  @traced_keys = nil
end

Public Instance Methods

dump(obj) click to toggle source
# File lib/nestedtext/dumper.rb, line 17
def dump(obj)
  @traced_cycles = []
  @traced_keys = []
  dump_any obj
end

Private Instance Methods

convert_key(key) click to toggle source
# File lib/nestedtext/dumper.rb, line 45
def convert_key(key)
  if key.nil?
    ''
  elsif key.is_a? String
    key.normalize_line_endings
  elsif !@strict
    key.to_s
  else
    raise Errors::DumpHashKeyStrictStringError, key
  end
end
dump_any(obj, depth: 0, **kwargs) click to toggle source
# File lib/nestedtext/dumper.rb, line 84
def dump_any(obj, depth: 0, **kwargs)
  trace_cycles(obj) do
    case obj
    when Hash then dump_hash(obj, depth: depth, **kwargs)
    when Array then dump_array(obj, depth: depth, **kwargs)
    when String then dump_string(obj, depth: depth, **kwargs)
    when nil
      @strict ? '' : dump_custom_class(nil, depth: depth, **kwargs)
    else
      dump_custom_class(obj, depth: depth, **kwargs)
    end
  end
end
dump_array(array, depth: 0, **kwargs) click to toggle source
# File lib/nestedtext/dumper.rb, line 131
def dump_array(array, depth: 0, **kwargs)
  rep = if array.empty?
          '[]'
        else
          array.each_with_index.map do |e, i|
            trace_keys(i) do
              Dumper.add_prefix('-', dump_any(e, depth: depth + 1, **kwargs))
            end
          end.join("\n")
        end

  indent(rep, depth)
end
dump_custom_class(obj, **kwargs) click to toggle source
# File lib/nestedtext/dumper.rb, line 162
def dump_custom_class(obj, **kwargs)
  raise Errors::DumpUnsupportedTypeError.new(obj, traced_key) if @strict

  if obj.is_a? Symbol
    dump_string(obj.id2name, **kwargs)
  elsif obj.respond_to? :encode_nt_with
    class_name = obj.nil? ? 'nil' : obj.class.name
    enc = { CUSTOM_CLASS_KEY => class_name, 'data' => obj.encode_nt_with }
    dump_any(enc, **kwargs)
  else
    dump_string(obj.to_s, **kwargs)
  end
end
dump_hash(hash, depth: 0, **kwargs) click to toggle source
# File lib/nestedtext/dumper.rb, line 126
def dump_hash(hash, depth: 0, **kwargs)
  rep = hash.empty? ? '{}' : dump_hash_items(hash, depth, **kwargs)
  indent(rep, depth)
end
dump_hash_items(hash, depth, **kwargs) click to toggle source
# File lib/nestedtext/dumper.rb, line 113
def dump_hash_items(hash, depth, **kwargs)
  hash.map do |key, value|
    trace_keys(key) do
      key = convert_key(key)
      if Dumper.multiline_key?(key)
        dump_hash_key_multiline(key, value, depth, **kwargs)
      else
        dump_hash_key(key, value, depth, **kwargs)
      end
    end
  end.join("\n")
end
dump_hash_key(key, value, depth, **kwargs) click to toggle source
# File lib/nestedtext/dumper.rb, line 106
def dump_hash_key(key, value, depth, **kwargs)
  rep_key = "#{key}:"
  rep_value = dump_any(value, depth: depth + 1, **kwargs)
  rep_key += ' ' unless rep_value.empty? || rep_value.include?("\n")
  [rep_key, rep_value].join
end
dump_hash_key_multiline(key, value, depth, **kwargs) click to toggle source
# File lib/nestedtext/dumper.rb, line 98
def dump_hash_key_multiline(key, value, depth, **kwargs)
  key_lines = key.empty? ? [''] : key.lines
  key_lines << '' if key_lines[-1][-1] =~ /\n|\r/
  rep_key = key_lines.map { |line| Dumper.add_prefix(':', line) }.join
  rep_value = dump_any(value, depth: depth + 1, force_multiline: value.is_a?(String), **kwargs)
  [rep_key, rep_value].join
end
dump_string(string, depth: 0, force_multiline: false) click to toggle source
# File lib/nestedtext/dumper.rb, line 151
def dump_string(string, depth: 0, force_multiline: false)
  lines = string.normalize_line_endings.lines
  lines << '' if !lines.empty? && lines.last[-1] == "\n"
  multiline = lines.length > 1 || force_multiline

  lines = prefix_lines(lines, depth, multiline)

  rep = lines.join.chomp
  multiline ? indent(rep, depth) : rep
end
indent(target, depth) click to toggle source
# File lib/nestedtext/dumper.rb, line 57
def indent(target, depth)
  return target unless depth.positive?

  indentstr = ' ' * @indentation
  "\n#{target.lines.map { |line| indentstr + line }.join}"
end
prefix_lines(lines, depth, multiline) click to toggle source
# File lib/nestedtext/dumper.rb, line 145
def prefix_lines(lines, depth, multiline)
  lines = lines.map { |line| Dumper.add_prefix('>', line) } if multiline || depth.zero?
  lines << '>' if lines.empty? && (depth.zero? || multiline)
  lines
end
trace_cycles(obj) { || ... } click to toggle source
# File lib/nestedtext/dumper.rb, line 64
def trace_cycles(obj)
  raise Errors::DumpCyclicReferencesDetectedError, traced_key if @traced_cycles.include?(obj)

  @traced_cycles << obj
  yield
ensure
  @traced_cycles.pop
end
trace_keys(key) { || ... } click to toggle source
# File lib/nestedtext/dumper.rb, line 73
def trace_keys(key)
  @traced_keys << key
  yield
ensure
  @traced_keys.pop
end
traced_key() click to toggle source
# File lib/nestedtext/dumper.rb, line 80
def traced_key
  @traced_keys.last
end