lib/amazing_print/formatters/base_formatter.rb
# frozen_string_literal: true require_relative '../colorize' module AmazingPrint module Formatters class BaseFormatter include Colorize DEFAULT_LIMIT_SIZE = 7 # To support limited output, for example: # # ap ('a'..'z').to_a, :limit => 3 # [ # [ 0] "a", # [ 1] .. [24], # [25] "z" # ] # # ap (1..100).to_a, :limit => true # Default limit is 7. # [ # [ 0] 1, # [ 1] 2, # [ 2] 3, # [ 3] .. [96], # [97] 98, # [98] 99, # [99] 100 # ] #------------------------------------------------------------------------------ def should_be_limited? options[:limit] || (options[:limit].is_a?(Integer) && options[:limit].positive?) end def get_limit_size case options[:limit] when true DEFAULT_LIMIT_SIZE else options[:limit] end end def limited(data, width, is_hash: false) limit = get_limit_size if data.length <= limit data else # Calculate how many elements to be displayed above and below the separator. head = limit / 2 tail = head - ((limit - 1) % 2) # Add the proper elements to the temp array and format the separator. temp = data[0, head] + [nil] + data[-tail, tail] temp[head] = if is_hash "#{indent}#{data[head].strip} .. #{data[data.length - tail - 1].strip}" else "#{indent}[#{head.to_s.rjust(width)}] .. [#{data.length - tail - 1}]" end temp end end def method_tuple(method) # See http://readruby.chengguangnan.com/methods#method-objects-parameters # (mirror: http://archive.is/XguCA#selection-3381.1-3381.11) args = method.parameters.inject([]) do |arr, (type, name)| name ||= (type == :block ? 'block' : "arg#{arr.size + 1}") arr << case type when :req then name.to_s when :keyreq then "#{name}:" when :key then "*#{name}:" when :opt, :rest then "*#{name}" when :block then "&#{name}" else '?' end end # method.to_s formats to handle: # # #<Method: Fixnum#zero?> # #<Method: Fixnum(Integer)#years> # #<Method: User(#<Module:0x00000103207c00>)#_username> # #<Method: User(id: integer, username: string).table_name> # #<Method: User(id: integer, username: string)(ActiveRecord::Base).current> # #<Method: #<Class:0x100c567f>(ActiveRecord::Querying)#first> # #<UnboundMethod: Hello#world> # #<UnboundMethod: Hello#world() /home/hs/code/amazing_print/spec/methods_spec.rb:68> # if method.to_s =~ %r{(Unbound)*Method: ((#<)?[^/#]*)[#.]} unbound = Regexp.last_match(1) && '(unbound)' klass = Regexp.last_match(2) if klass && klass =~ /(\(\w+:\s.*?\))/ # Is this ActiveRecord-style class? klass.sub!(Regexp.last_match(1), '') # Yes, strip the fields leaving class name only. end owner = "#{klass}#{unbound}".gsub('(', ' (') end [method.name.to_s, "(#{args.join(', ')})", owner.to_s] end # # Indentation related methods #----------------------------------------- def indentation inspector.current_indentation end def indented(&blk) inspector.increase_indentation(&blk) end # precompute common indentations INDENT_CACHE = (0..100).map { |i| ' ' * i }.map(&:freeze).freeze def indent(n = indentation) INDENT_CACHE[n] || (' ' * n) end def outdent i = indentation - options[:indent].abs INDENT_CACHE[i] || (' ' * i) end def align(value, width) if options[:multiline] indent_option = options[:indent] effective_width = width + value.size - colorless_size(value) if indent_option.positive? value.rjust(effective_width) elsif indent_option.zero? "#{indent}#{value.ljust(effective_width)}" else "#{indent(indentation + indent_option)}#{value.ljust(effective_width)}" end else value end end def colorless(string) string.gsub(/\e\[[\d;]+m/, '') end def colorless_size(string) colorless(string).size end end end end