class RSpec::Support::ObjectFormatter

Provide additional output details beyond what `inspect` provides when printing Time, DateTime, or BigDecimal @api private

Constants

BaseInspector
ELLIPSIS
INSPECTOR_CLASSES
InspectableItem

Attributes

max_formatted_output_length[RW]

Public Class Methods

default_instance() click to toggle source

Methods are deferred to a default instance of the class to maintain the interface For example, calling ObjectFormatter.format is still possible

# File lib/rspec/support/object_formatter.rb, line 15
def self.default_instance
  @default_instance ||= new
end
format(object) click to toggle source
# File lib/rspec/support/object_formatter.rb, line 19
def self.format(object)
  default_instance.format(object)
end
new(max_formatted_output_length=200) click to toggle source
# File lib/rspec/support/object_formatter.rb, line 27
def initialize(max_formatted_output_length=200)
  @max_formatted_output_length = max_formatted_output_length
  @current_structure_stack = []
end
prepare_for_inspection(object) click to toggle source
# File lib/rspec/support/object_formatter.rb, line 23
def self.prepare_for_inspection(object)
  default_instance.prepare_for_inspection(object)
end

Public Instance Methods

format(object) click to toggle source
# File lib/rspec/support/object_formatter.rb, line 32
def format(object)
  if max_formatted_output_length.nil?
    prepare_for_inspection(object).inspect
  else
    formatted_object = prepare_for_inspection(object).inspect
    if formatted_object.length < max_formatted_output_length
      formatted_object
    else
      beginning = truncate_string formatted_object, 0, max_formatted_output_length / 2
      ending = truncate_string formatted_object, -max_formatted_output_length / 2, -1
      beginning + ELLIPSIS + ending
    end
  end
end
prepare_array(array) click to toggle source
# File lib/rspec/support/object_formatter.rb, line 68
def prepare_array(array)
  with_entering_structure(array) do
    array.map { |element| prepare_element(element) }
  end
end
prepare_element(element) click to toggle source
# File lib/rspec/support/object_formatter.rb, line 92
def prepare_element(element)
  if recursive_structure?(element)
    case element
    when Array then InspectableItem.new('[...]')
    when Hash then InspectableItem.new('{...}')
    else raise # This won't happen
    end
  else
    prepare_for_inspection(element)
  end
end
prepare_for_inspection(object) click to toggle source

Prepares the provided object to be formatted by wrapping it as needed in something that, when `inspect` is called on it, will produce the desired output.

This allows us to apply the desired formatting to hash/array data structures at any level of nesting, simply by walking that structure and replacing items with custom items that have `inspect` defined to return the desired output for that item. Then we can just use `Array#inspect` or `Hash#inspect` to format the entire thing.

# File lib/rspec/support/object_formatter.rb, line 56
def prepare_for_inspection(object)
  case object
  when Array
    prepare_array(object)
  when Hash
    prepare_hash(object)
  else
    inspector_class = INSPECTOR_CLASSES.find { |inspector| inspector.can_inspect?(object) }
    inspector_class.new(object, self)
  end
end
prepare_hash(input_hash) click to toggle source
# File lib/rspec/support/object_formatter.rb, line 74
def prepare_hash(input_hash)
  with_entering_structure(input_hash) do
    sort_hash_keys(input_hash).inject({}) do |output_hash, key_and_value|
      key, value = key_and_value.map { |element| prepare_element(element) }
      output_hash[key] = value
      output_hash
    end
  end
end
recursive_structure?(object) click to toggle source
# File lib/rspec/support/object_formatter.rb, line 111
def recursive_structure?(object)
  @current_structure_stack.any? { |seen_structure| seen_structure.equal?(object) }
end
sort_hash_keys(input_hash) click to toggle source
# File lib/rspec/support/object_formatter.rb, line 84
def sort_hash_keys(input_hash)
  if input_hash.keys.all? { |k| k.is_a?(String) || k.is_a?(Symbol) }
    Hash[input_hash.sort_by { |k, _v| k.to_s }]
  else
    input_hash
  end
end
with_entering_structure(structure) { || ... } click to toggle source
# File lib/rspec/support/object_formatter.rb, line 104
def with_entering_structure(structure)
  @current_structure_stack.push(structure)
  return_value = yield
  @current_structure_stack.pop
  return_value
end

Private Instance Methods

truncate_string(str, start_index, end_index) click to toggle source

Returns the substring defined by the start_index and end_index If the string ends with a partial ANSI code code then that will be removed as printing partial ANSI codes to the terminal can lead to corruption

# File lib/rspec/support/object_formatter.rb, line 266
def truncate_string(str, start_index, end_index)
  cut_str = str[start_index..end_index]

  # ANSI color codes are like: \e[33m so anything with \e[ and a
  # number without a 'm' is an incomplete color code
  cut_str.sub(/\e\[\d+$/, '')
end