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
Public Class Methods
Methods are deferred to a default instance of the class to maintain the interface For example, calling ::format is still possible
# File lib/rspec/support/object_formatter.rb, line 15 def self.default_instance @default_instance ||= new end
# File lib/rspec/support/object_formatter.rb, line 19 def self.format(object) default_instance.format(object) end
# 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
# 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
# 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
# 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
# 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
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
# 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
# File lib/rspec/support/object_formatter.rb, line 111 def recursive_structure?(object) @current_structure_stack.any? { |seen_structure| seen_structure.equal?(object) } end
# 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
# 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
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