class AwesomePrint::Formatter

Constants

CORE
DEFAULT_LIMIT_SIZE

Public Class Methods

new(inspector) click to toggle source
# File lib/awesome_print/formatter.rb, line 15
def initialize(inspector)
  @inspector   = inspector
  @options     = inspector.options
  @indentation = @options[:indent].abs
end

Public Instance Methods

cast(object, type) click to toggle source

Hook this when adding custom formatters. Check out lib/awesome_print/ext directory for custom formatters that ship with awesome_print.

# File lib/awesome_print/formatter.rb, line 36
def cast(object, type)
  CORE.grep(type)[0] || :self
end
colorize(s, type) click to toggle source

Pick the color and apply it to the given string as necessary.

# File lib/awesome_print/formatter.rb, line 42
def colorize(s, type)
  s = CGI.escapeHTML(s) if @options[:html]
  if @options[:plain] || !@options[:color][type] || !@inspector.colorize?
    s
  else
    s.send(@options[:color][type], @options[:html])
  end
end
format(object, type = nil) click to toggle source

Main entry point to format an object.

# File lib/awesome_print/formatter.rb, line 23
def format(object, type = nil)
  core_class = cast(object, type)
  awesome = if core_class != :self
    send(:"awesome_#{core_class}", object) # Core formatters.
  else
    awesome_self(object, type) # Catch all that falls back to object.inspect.
  end
  @options[:html] ? "<pre>#{awesome}</pre>" : awesome
end

Private Instance Methods

align(value, width) click to toggle source

Utility methods.

# File lib/awesome_print/formatter.rb, line 298
def align(value, width)
  if @options[:multiline]
    if @options[:indent] > 0
      value.rjust(width)
    elsif @options[:indent] == 0
      indent + value.ljust(width)
    else
      indent[0, @indentation + @options[:indent]] + value.ljust(width)
    end
  else
    value
  end
end
awesome_array(a) click to toggle source

Format an array.

# File lib/awesome_print/formatter.rb, line 63
def awesome_array(a)
  return "[]" if a == []

  if a.instance_variable_defined?('@__awesome_methods__')
    methods_array(a)
  elsif @options[:multiline]
    width = (a.size - 1).to_s.size 

    data = a.inject([]) do |arr, item|
      index = indent
      index << colorize("[#{arr.size.to_s.rjust(width)}] ", :array) if @options[:index]
      indented do
        arr << (index << @inspector.awesome(item))
      end
    end

    data = limited(data, width) if should_be_limited?
    "[\n" << data.join(",\n") << "\n#{outdent}]"
  else
    "[ " << a.map{ |item| @inspector.awesome(item) }.join(", ") << " ]"
  end
end
awesome_bigdecimal(n) click to toggle source

Format BigDecimal and Rational objects by convering them to Float.

# File lib/awesome_print/formatter.rb, line 194
def awesome_bigdecimal(n)
  colorize(n.to_f.inspect, :bigdecimal)
end
Also aliased as: awesome_rational
awesome_class(c) click to toggle source

Format Class object.

# File lib/awesome_print/formatter.rb, line 170
def awesome_class(c)
  if superclass = c.superclass # <-- Assign and test if nil.
    colorize("#{c.inspect} < #{superclass}", :class)
  else
    colorize(c.inspect, :class)
  end
end
awesome_dir(d) click to toggle source

Format Dir object.

# File lib/awesome_print/formatter.rb, line 187
def awesome_dir(d)
  ls = `ls -alF #{d.path.shellescape}`
  colorize(ls.empty? ? d.inspect : "#{d.inspect}\n#{ls.chop}", :dir)
end
awesome_file(f) click to toggle source

Format File object.

# File lib/awesome_print/formatter.rb, line 180
def awesome_file(f)
  ls = File.directory?(f) ? `ls -adlF #{f.path.shellescape}` : `ls -alF #{f.path.shellescape}`
  colorize(ls.empty? ? f.inspect : "#{f.inspect}\n#{ls.chop}", :file)
end
awesome_hash(h) click to toggle source

Format a hash. If @options if negative left align hash keys.

# File lib/awesome_print/formatter.rb, line 88
def awesome_hash(h)
  return "{}" if h == {}

  keys = @options[:sort_keys] ? h.keys.sort { |a, b| a.to_s <=> b.to_s } : h.keys
  data = keys.map do |key|
    plain_single_line do
      [ @inspector.awesome(key), h[key] ]
    end
  end
  
  width = data.map { |key, | key.size }.max || 0
  width += @indentation if @options[:indent] > 0
  
  data = data.map do |key, value|
    indented do
      align(key, width) << colorize(" => ", :hash) << @inspector.awesome(value)
    end
  end

  data = limited(data, width, :hash => true) if should_be_limited?
  if @options[:multiline]
    "{\n" << data.join(",\n") << "\n#{outdent}}"
  else
    "{ #{data.join(', ')} }"
  end
end
awesome_instance(o) click to toggle source

Format object instance.

# File lib/awesome_print/formatter.rb, line 209
def awesome_instance(o)
  "#{o.class}:0x%08x" % (o.__id__ * 2)
end
awesome_method(m) click to toggle source

Format a method.

# File lib/awesome_print/formatter.rb, line 201
def awesome_method(m)
  name, args, owner = method_tuple(m)
  "#{colorize(owner, :class)}##{colorize(name, :method)}#{colorize(args, :args)}"
end
Also aliased as: awesome_unboundmethod
awesome_object(o) click to toggle source

Format an object.

# File lib/awesome_print/formatter.rb, line 117
def awesome_object(o)
  vars = o.instance_variables.map do |var|
    property = var[1..-1].to_sym
    accessor = if o.respond_to?(:"#{property}=")
      o.respond_to?(property) ? :accessor : :writer
    else
      o.respond_to?(property) ? :reader : nil
    end
    if accessor
      [ "attr_#{accessor} :#{property}", var ]
    else
      [ var.to_s, var ]
    end
  end

  data = vars.sort.map do |declaration, var|
    key = left_aligned do
      align(declaration, declaration.size)
    end

    unless @options[:plain]
      if key =~ /(@\w+)/
        key.sub!($1, colorize($1, :variable))
      else
        key.sub!(/(attr_\w+)\s(\:\w+)/, "#{colorize('\\1', :keyword)} #{colorize('\\2', :method)}")
      end
    end
    indented do
      key << colorize(" = ", :hash) + @inspector.awesome(o.instance_variable_get(var))
    end
  end
  if @options[:multiline]
    "#<#{awesome_instance(o)}\n#{data.join(%Q/,\n/)}\n#{outdent}>"
  else
    "#<#{awesome_instance(o)} #{data.join(', ')}>"
  end
end
awesome_rational(n)
Alias for: awesome_bigdecimal
awesome_self(object, type) click to toggle source

Catch all method to format an arbitrary object.

# File lib/awesome_print/formatter.rb, line 56
def awesome_self(object, type)
  return awesome_object(object) if object.instance_variables.any?
  colorize(object.inspect.to_s, type)
end
awesome_struct(s) click to toggle source

Format a Struct.

# File lib/awesome_print/formatter.rb, line 157
def awesome_struct(s)
  #
  # The code is slightly uglier because of Ruby 1.8.6 quirks:
  # awesome_hash(Hash[s.members.zip(s.values)]) <-- ArgumentError: odd number of arguments for Hash)
  # awesome_hash(Hash[*s.members.zip(s.values).flatten]) <-- s.members returns strings, not symbols.
  #
  hash = {}
  s.each_pair { |key, value| hash[key] = value }
  awesome_hash(hash)
end
awesome_unboundmethod(m)
Alias for: awesome_method
get_limit_size() click to toggle source
# File lib/awesome_print/formatter.rb, line 358
def get_limit_size
  @options[:limit] == true ? DEFAULT_LIMIT_SIZE : @options[:limit]
end
indent() click to toggle source
# File lib/awesome_print/formatter.rb, line 326
def indent
  ' ' * @indentation
end
indented() { || ... } click to toggle source
# File lib/awesome_print/formatter.rb, line 312
def indented
  @indentation += @options[:indent].abs
  yield
ensure
  @indentation -= @options[:indent].abs
end
left_aligned() { || ... } click to toggle source
# File lib/awesome_print/formatter.rb, line 319
def left_aligned
  current, @options[:indent] = @options[:indent], 0
  yield
ensure
  @options[:indent] = current
end
limited(data, width, is_hash = false) click to toggle source
# File lib/awesome_print/formatter.rb, line 362
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]

    if is_hash
      temp[head] = "#{indent}#{data[head].strip} .. #{data[data.length - tail - 1].strip}"
    else
      temp[head] = "#{indent}[#{head.to_s.rjust(width)}] .. [#{data.length - tail - 1}]"
    end

    temp
  end
end
method_tuple(method) click to toggle source

Return [ name, arguments, owner ] tuple for a given method.

# File lib/awesome_print/formatter.rb, line 249
def method_tuple(method)
  if method.respond_to?(:parameters) # Ruby 1.9.2+
    # See http://ruby.runpaint.org/methods#method-objects-parameters
    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 :opt, :rest then "*#{name}"
        when :block      then "&#{name}"
        else '?'
      end
    end
  else # See http://ruby-doc.org/core/classes/Method.html#M001902
    args = (1..method.arity.abs).map { |i| "arg#{i}" }
    args[-1] = "*#{args[-1]}" if method.arity < 0
  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>
  # #<UnboundMethod: Hello#world>
  #
  if method.to_s =~ /(Unbound)*Method: (.*)[#\.]/
    unbound, klass = $1 && '(unbound)', $2
    if klass && klass =~ /(\(\w+:\s.*?\))/  # Is this ActiveRecord-style class?
      klass.sub!($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
methods_array(a) click to toggle source

Format object.methods array.

# File lib/awesome_print/formatter.rb, line 215
def methods_array(a)
  a.sort! { |x, y| x.to_s <=> y.to_s }                  # Can't simply a.sort! because of o.methods << [ :blah ]
  object = a.instance_variable_get('@__awesome_methods__')
  tuples = a.map do |name|
    if name.is_a?(Symbol) || name.is_a?(String)         # Ignore garbage, ex. 42.methods << [ :blah ]
      tuple = if object.respond_to?(name, true)         # Is this a regular method?
        the_method = object.method(name) rescue nil     # Avoid potential ArgumentError if object#method is overridden.
        if the_method && the_method.respond_to?(:arity) # Is this original object#method?
          method_tuple(the_method)                      # Yes, we are good.
        end
      elsif object.respond_to?(:instance_method)        # Is this an unbound method?
        method_tuple(object.instance_method(name))
      end
    end
    tuple || [ name.to_s, '(?)', '?' ]                  # Return WTF default if all the above fails.
  end

  width = (tuples.size - 1).to_s.size
  name_width = tuples.map { |item| item[0].size }.max || 0
  args_width = tuples.map { |item| item[1].size }.max || 0

  data = tuples.inject([]) do |arr, item|
    index = indent
    index << "[#{arr.size.to_s.rjust(width)}]" if @options[:index]
    indented do
      arr << "#{index} #{colorize(item[0].rjust(name_width), :method)}#{colorize(item[1].ljust(args_width), :args)} #{colorize(item[2], :class)}"
    end
  end

  "[\n" << data.join("\n") << "\n#{outdent}]"
end
outdent() click to toggle source
# File lib/awesome_print/formatter.rb, line 330
def outdent
  ' ' * (@indentation - @options[:indent].abs)
end
plain_single_line() { || ... } click to toggle source

Format hash keys as plain strings regardless of underlying data type.

# File lib/awesome_print/formatter.rb, line 288
def plain_single_line
  plain, multiline = @options[:plain], @options[:multiline]
  @options[:plain], @options[:multiline] = true, false
  yield
ensure
  @options[:plain], @options[:multiline] = plain, multiline
end
should_be_limited?() click to toggle source

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

]

# File lib/awesome_print/formatter.rb, line 354
def should_be_limited?
  @options[:limit] == true or (@options[:limit].is_a?(Fixnum) and @options[:limit] > 0)
end