diff --git a/lib/awesome_print/colorize.rb b/lib/awesome_print/colorize.rb
new file mode 100644
index 0000000..33f438e
--- /dev/null
+++ b/lib/awesome_print/colorize.rb
@@ -0,0 +1,24 @@
+autoload :CGI, "cgi"
+
+module AwesomePrint
+ module Colorize
+
+ # Pick the color and apply it to the given string as necessary.
+ #------------------------------------------------------------------------------
+ def colorize(str, type)
+ str = CGI.escapeHTML(str) if options[:html]
+ if options[:plain] || !options[:color][type] || !inspector.colorize?
+ str
+ #
+ # Check if the string color method is defined by awesome_print and accepts
+ # html parameter or it has been overriden by some gem such as colorize.
+ #
+ elsif str.method(options[:color][type]).arity == -1 # Accepts html parameter.
+ str.send(options[:color][type], options[:html])
+ else
+ str = %Q|#{str}| if options[:html]
+ str.send(options[:color][type])
+ end
+ end
+ end
+end
diff --git a/lib/awesome_print/formatter.rb b/lib/awesome_print/formatter.rb
index cff0c55..94dccbf 100644
--- a/lib/awesome_print/formatter.rb
+++ b/lib/awesome_print/formatter.rb
@@ -3,19 +3,27 @@
# Awesome Print is freely distributable under the terms of MIT license.
# See LICENSE file or http://www.opensource.org/licenses/mit-license.php
#------------------------------------------------------------------------------
-autoload :CGI, "cgi"
-require "shellwords"
+require_relative "formatters/object_formatter"
+require_relative "formatters/hash_formatter"
+require_relative "formatters/array_formatter"
+require_relative "formatters/simple_formatter"
+require_relative "formatters/method_formatter"
+require_relative "formatters/class_formatter"
+require_relative "formatters/dir_formatter"
+require_relative "formatters/file_formatter"
+require_relative "colorize"
module AwesomePrint
class Formatter
+ include Colorize
+
+ attr_reader :inspector, :options
CORE = [ :array, :bigdecimal, :class, :dir, :file, :hash, :method, :rational, :set, :struct, :unboundmethod ]
- DEFAULT_LIMIT_SIZE = 7
def initialize(inspector)
@inspector = inspector
@options = inspector.options
- @indentation = @options[:indent].abs
end
# Main entry point to format an object.
@@ -37,292 +45,71 @@ module AwesomePrint
CORE.grep(type)[0] || :self
end
- # Pick the color and apply it to the given string as necessary.
- #------------------------------------------------------------------------------
- def colorize(str, type)
- str = CGI.escapeHTML(str) if @options[:html]
- if @options[:plain] || !@options[:color][type] || !@inspector.colorize?
- str
- #
- # Check if the string color method is defined by awesome_print and accepts
- # html parameter or it has been overriden by some gem such as colorize.
- #
- elsif str.method(@options[:color][type]).arity == -1 # Accepts html parameter.
- str.send(@options[:color][type], @options[:html])
- else
- str = %Q|#{str}| if @options[:html]
- str.send(@options[:color][type])
- end
- end
-
-
private
- # Check whether a variable_name is a method or ivar
- #------------------------------------------------------------------------------
- def valid_instance_var?(variable_name)
- variable_name.to_s.start_with?('@')
- end
-
# Catch all method to format an arbitrary object.
#------------------------------------------------------------------------------
def awesome_self(object, type)
if @options[:raw] && object.instance_variables.any?
- return awesome_object(object)
+ awesome_object(object)
elsif hash = convert_to_hash(object)
awesome_hash(hash)
else
- colorize(object.inspect.to_s, type)
+ awesome_simple(object.inspect.to_s, type, @inspector)
end
end
- # Format an array.
- #------------------------------------------------------------------------------
- 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
-
- # Format a hash. If @options[:indent] if negative left align hash keys.
- #------------------------------------------------------------------------------
- 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
-
- # Format an object.
- #------------------------------------------------------------------------------
- def awesome_object(o)
- awesome_object_data(o, o.instance_variables)
- end
-
- def awesome_object_data(o, variables)
- vars = variables.map do |var|
- property = var.to_s[1..-1].to_sym # to_s because of some monkey patching done by Puppet.
- 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
- var_contents = if valid_instance_var?(var)
- o.instance_variable_get(var)
- else
- o.send(var) # Enables handling of Struct attributes
- end
-
- key << colorize(" = ", :hash) + @inspector.awesome(var_contents)
- end
- end
- if @options[:multiline]
- "#<#{awesome_instance(o)}\n#{data.join(%Q/,\n/)}\n#{outdent}>"
- else
- "#<#{awesome_instance(o)} #{data.join(', ')}>"
- end
- end
-
- # Format a set.
- #------------------------------------------------------------------------------
- def awesome_set(s)
- awesome_array(s.to_a)
- end
-
- # Format a Struct.
- #------------------------------------------------------------------------------
- def awesome_struct(s)
- awesome_object_data(s, s.members)
- end
-
- # Format Class object.
- #------------------------------------------------------------------------------
- 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
-
- # Format File object.
- #------------------------------------------------------------------------------
- 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
-
- # Format Dir object.
- #------------------------------------------------------------------------------
- def awesome_dir(d)
- ls = `ls -alF #{d.path.shellescape}`
- colorize(ls.empty? ? d.inspect : "#{d.inspect}\n#{ls.chop}", :dir)
- end
-
- # Format BigDecimal object.
- #------------------------------------------------------------------------------
def awesome_bigdecimal(n)
- colorize(n.to_s("F"), :bigdecimal)
+ o = n.to_s("F")
+ type = :bigdecimal
+ awesome_simple(o, type, @inspector)
end
- # Format Rational object.
- #------------------------------------------------------------------------------
def awesome_rational(n)
- colorize(n.to_s, :rational)
+ o = n.to_s
+ type = :rational
+ awesome_simple(o, type, @inspector)
+ end
+
+ def awesome_simple(o, type, inspector)
+ AwesomePrint::Formatters::SimpleFormatter.new(o, type, inspector).format
+ end
+
+ def awesome_array(a)
+ Formatters::ArrayFormatter.new(a, @inspector).format
+ end
+
+ def awesome_set(s)
+ Formatters::ArrayFormatter.new(s.to_a, @inspector).format
+ end
+
+ def awesome_hash(h)
+ Formatters::HashFormatter.new(h, @inspector).format
+ end
+
+ def awesome_object(o)
+ Formatters::ObjectFormatter.new(o, o.instance_variables, @inspector).format
+ end
+
+ def awesome_struct(s)
+ Formatters::ObjectFormatter.new(s, s.members, @inspector).format
end
- # Format a method.
- #------------------------------------------------------------------------------
def awesome_method(m)
- name, args, owner = method_tuple(m)
- "#{colorize(owner, :class)}##{colorize(name, :method)}#{colorize(args, :args)}"
+ Formatters::MethodFormatter.new(m, @inspector).format
end
alias :awesome_unboundmethod :awesome_method
- # Format object instance.
- #------------------------------------------------------------------------------
- def awesome_instance(o)
- "#{o.class}:0x%08x" % (o.__id__ * 2)
+ def awesome_class(c)
+ Formatters::ClassFormatter.new(c, @inspector).format
end
- # Format object.methods array.
- #------------------------------------------------------------------------------
- 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)) rescue nil # Rescue to avoid NameError when the method is not
- end # available (ex. File.lchmod on Ubuntu 12).
- 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}]"
+ def awesome_file(f)
+ Formatters::FileFormatter.new(f, @inspector).format
end
- # Return [ name, arguments, owner ] tuple for a given method.
- #------------------------------------------------------------------------------
- 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:
- #
- # #
- # #
- # #)#_username>
- # #
- # #
- # #
- #
- 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
-
- # Format hash keys as plain strings regardless of underlying data type.
- #------------------------------------------------------------------------------
- def plain_single_line
- plain, multiline = @options[:plain], @options[:multiline]
- @options[:plain], @options[:multiline] = true, false
- yield
- ensure
- @options[:plain], @options[:multiline] = plain, multiline
+ def awesome_dir(d)
+ Formatters::DirFormatter.new(d, @inspector).format
end
# Utility methods.
@@ -331,6 +118,7 @@ module AwesomePrint
if ! object.respond_to?(:to_hash)
return nil
end
+
if object.method(:to_hash).arity != 0
return nil
end
@@ -342,91 +130,5 @@ module AwesomePrint
return hash
end
-
- 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
-
- def indented
- @indentation += @options[:indent].abs
- yield
- ensure
- @indentation -= @options[:indent].abs
- end
-
- def left_aligned
- current, @options[:indent] = @options[:indent], 0
- yield
- ensure
- @options[:indent] = current
- end
-
- def indent
- ' ' * @indentation
- end
-
- def outdent
- ' ' * (@indentation - @options[:indent].abs)
- end
-
- # 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] == true or (@options[:limit].is_a?(Fixnum) and @options[:limit] > 0)
- end
-
- def get_limit_size
- @options[:limit] == true ? DEFAULT_LIMIT_SIZE : @options[:limit]
- 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]
-
- 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
end
end
diff --git a/lib/awesome_print/formatters/array_formatter.rb b/lib/awesome_print/formatters/array_formatter.rb
new file mode 100644
index 0000000..eda390d
--- /dev/null
+++ b/lib/awesome_print/formatters/array_formatter.rb
@@ -0,0 +1,73 @@
+require_relative 'base_formatter'
+
+module AwesomePrint
+ module Formatters
+ class ArrayFormatter < BaseFormatter
+
+ attr_reader :array, :inspector, :options
+
+ def initialize(array, inspector)
+ @array = array
+ @inspector = inspector
+ @options = inspector.options
+ end
+
+ def format
+ return "[]" if array == []
+
+ if array.instance_variable_defined?('@__awesome_methods__')
+ methods_array(array)
+ elsif options[:multiline]
+ width = (array.size - 1).to_s.size
+
+ data = array.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
+ "[ " << array.map{ |item| inspector.awesome(item) }.join(", ") << " ]"
+ end
+ end
+
+ private
+
+ 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)) rescue nil # Rescue to avoid NameError when the method is not
+ end # available (ex. File.lchmod on Ubuntu 12).
+ 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
+ end
+ end
+end
diff --git a/lib/awesome_print/formatters/base_formatter.rb b/lib/awesome_print/formatters/base_formatter.rb
new file mode 100644
index 0000000..802a90b
--- /dev/null
+++ b/lib/awesome_print/formatters/base_formatter.rb
@@ -0,0 +1,138 @@
+require_relative "../colorize"
+
+module AwesomePrint
+ 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] or (options[:limit].is_a?(Fixnum) and options[:limit] > 0)
+ 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]
+
+ 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
+
+
+ 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:
+ #
+ # #
+ # #
+ # #)#_username>
+ # #
+ # #
+ # #
+ #
+ 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
+
+ #
+ # Indentation related methods
+ #-----------------------------------------
+ def indentation
+ inspector.current_indentation
+ end
+
+ def indented
+ inspector.increase_indentation(&Proc.new)
+ end
+
+ def indent
+ ' ' * indentation
+ end
+
+ def outdent
+ ' ' * (indentation - options[:indent].abs)
+ end
+
+ 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
+
+ end
+ end
+end
diff --git a/lib/awesome_print/formatters/class_formatter.rb b/lib/awesome_print/formatters/class_formatter.rb
new file mode 100644
index 0000000..8cc1089
--- /dev/null
+++ b/lib/awesome_print/formatters/class_formatter.rb
@@ -0,0 +1,24 @@
+require_relative 'base_formatter'
+
+module AwesomePrint
+ module Formatters
+ class ClassFormatter < BaseFormatter
+
+ attr_reader :klass, :inspector, :options
+
+ def initialize(klass, inspector)
+ @klass = klass
+ @inspector = inspector
+ @options = inspector.options
+ end
+
+ def format
+ if superclass = klass.superclass # <-- Assign and test if nil.
+ colorize("#{klass.inspect} < #{superclass}", :class)
+ else
+ colorize(klass.inspect, :class)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/awesome_print/formatters/dir_formatter.rb b/lib/awesome_print/formatters/dir_formatter.rb
new file mode 100644
index 0000000..d773520
--- /dev/null
+++ b/lib/awesome_print/formatters/dir_formatter.rb
@@ -0,0 +1,22 @@
+require_relative 'base_formatter'
+require "shellwords"
+
+module AwesomePrint
+ module Formatters
+ class DirFormatter < BaseFormatter
+
+ attr_reader :dir, :inspector, :options
+
+ def initialize(dir, inspector)
+ @dir = dir
+ @inspector = inspector
+ @options = inspector.options
+ end
+
+ def format
+ ls = `ls -alF #{dir.path.shellescape}`
+ colorize(ls.empty? ? dir.inspect : "#{dir.inspect}\n#{ls.chop}", :dir)
+ end
+ end
+ end
+end
diff --git a/lib/awesome_print/formatters/file_formatter.rb b/lib/awesome_print/formatters/file_formatter.rb
new file mode 100644
index 0000000..3bf62b6
--- /dev/null
+++ b/lib/awesome_print/formatters/file_formatter.rb
@@ -0,0 +1,22 @@
+require_relative 'base_formatter'
+require "shellwords"
+
+module AwesomePrint
+ module Formatters
+ class FileFormatter < BaseFormatter
+
+ attr_reader :file, :inspector, :options
+
+ def initialize(file, inspector)
+ @file = file
+ @inspector = inspector
+ @options = inspector.options
+ end
+
+ def format
+ ls = File.directory?(file) ? `ls -adlF #{file.path.shellescape}` : `ls -alF #{file.path.shellescape}`
+ colorize(ls.empty? ? file.inspect : "#{file.inspect}\n#{ls.chop}", :file)
+ end
+ end
+ end
+end
diff --git a/lib/awesome_print/formatters/hash_formatter.rb b/lib/awesome_print/formatters/hash_formatter.rb
new file mode 100644
index 0000000..1435e43
--- /dev/null
+++ b/lib/awesome_print/formatters/hash_formatter.rb
@@ -0,0 +1,54 @@
+require_relative 'base_formatter'
+
+module AwesomePrint
+ module Formatters
+ class HashFormatter < BaseFormatter
+
+ attr_reader :hash, :inspector, :options
+
+ def initialize(hash, inspector)
+ @hash = hash
+ @inspector = inspector
+ @options = inspector.options
+ end
+
+ def format
+ return "{}" if hash == {}
+
+ keys = hash.keys
+ keys = keys.sort { |a, b| a.to_s <=> b.to_s } if options[:sort_keys]
+ data = keys.map do |key|
+ plain_single_line do
+ [ inspector.awesome(key), hash[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
+
+ private
+
+ 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
+ end
+ end
+end
diff --git a/lib/awesome_print/formatters/method_formatter.rb b/lib/awesome_print/formatters/method_formatter.rb
new file mode 100644
index 0000000..26c398d
--- /dev/null
+++ b/lib/awesome_print/formatters/method_formatter.rb
@@ -0,0 +1,22 @@
+require_relative 'base_formatter'
+
+module AwesomePrint
+ module Formatters
+ class MethodFormatter < BaseFormatter
+
+ attr_reader :method, :inspector, :options
+
+ def initialize(method, inspector)
+ @method = method
+ @inspector = inspector
+ @options = inspector.options
+ end
+
+ def format
+ name, args, owner = method_tuple(method)
+
+ "#{colorize(owner, :class)}##{colorize(name, :method)}#{colorize(args, :args)}"
+ end
+ end
+ end
+end
diff --git a/lib/awesome_print/formatters/object_formatter.rb b/lib/awesome_print/formatters/object_formatter.rb
new file mode 100644
index 0000000..c5a8d91
--- /dev/null
+++ b/lib/awesome_print/formatters/object_formatter.rb
@@ -0,0 +1,80 @@
+require_relative 'base_formatter'
+
+module AwesomePrint
+ module Formatters
+ class ObjectFormatter < BaseFormatter
+
+ attr_reader :object, :variables, :inspector, :options
+
+ def initialize(object, variables, inspector)
+ @object = object
+ @variables = variables
+ @inspector = inspector
+ @options = inspector.options
+ end
+
+ def format
+ vars = variables.map do |var|
+ property = var.to_s[1..-1].to_sym # to_s because of some monkey patching done by Puppet.
+ accessor = if object.respond_to?(:"#{property}=")
+ object.respond_to?(property) ? :accessor : :writer
+ else
+ object.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
+ var_contents = if valid_instance_var?(var)
+ object.instance_variable_get(var)
+ else
+ object.send(var) # Enables handling of Struct attributes
+ end
+
+ key << colorize(" = ", :hash) + inspector.awesome(var_contents)
+ end
+ end
+
+ if options[:multiline]
+ "#<#{awesome_instance}\n#{data.join(%Q/,\n/)}\n#{outdent}>"
+ else
+ "#<#{awesome_instance} #{data.join(', ')}>"
+ end
+ end
+
+ private
+
+ def valid_instance_var?(variable_name)
+ variable_name.to_s.start_with?('@')
+ end
+
+ def awesome_instance
+ "#{object.class}:0x%08x" % (object.__id__ * 2)
+ end
+
+ def left_aligned
+ current, options[:indent] = options[:indent], 0
+ yield
+ ensure
+ options[:indent] = current
+ end
+ end
+ end
+end
diff --git a/lib/awesome_print/formatters/simple_formatter.rb b/lib/awesome_print/formatters/simple_formatter.rb
new file mode 100644
index 0000000..bdd274f
--- /dev/null
+++ b/lib/awesome_print/formatters/simple_formatter.rb
@@ -0,0 +1,21 @@
+require_relative 'base_formatter'
+
+module AwesomePrint
+ module Formatters
+ class SimpleFormatter < BaseFormatter
+
+ attr_reader :string, :type, :inspector, :options
+
+ def initialize(string, type, inspector)
+ @string = string
+ @type = type
+ @inspector = inspector
+ @options = inspector.options
+ end
+
+ def format
+ colorize(string, type)
+ end
+ end
+ end
+end
diff --git a/lib/awesome_print/indentator.rb b/lib/awesome_print/indentator.rb
new file mode 100644
index 0000000..73e876b
--- /dev/null
+++ b/lib/awesome_print/indentator.rb
@@ -0,0 +1,18 @@
+module AwesomePrint
+ class Indentator
+
+ attr_reader :shift_width, :indentation
+
+ def initialize(indentation)
+ @indentation = indentation
+ @shift_width = indentation.freeze
+ end
+
+ def indent
+ @indentation += shift_width
+ yield
+ ensure
+ @indentation -= shift_width
+ end
+ end
+end
diff --git a/lib/awesome_print/inspector.rb b/lib/awesome_print/inspector.rb
index 0893a90..c519322 100644
--- a/lib/awesome_print/inspector.rb
+++ b/lib/awesome_print/inspector.rb
@@ -3,6 +3,8 @@
# Awesome Print is freely distributable under the terms of MIT license.
# See LICENSE file or http://www.opensource.org/licenses/mit-license.php
#------------------------------------------------------------------------------
+require_relative "indentator"
+
module AwesomePrint
class << self # Class accessors for custom defaults.
@@ -48,7 +50,7 @@ module AwesomePrint
end
class Inspector
- attr_accessor :options
+ attr_accessor :options, :indentator
AP = :__awesome_print__
@@ -90,8 +92,17 @@ module AwesomePrint
merge_options!(options)
@formatter = AwesomePrint::Formatter.new(self)
+ @indentator = AwesomePrint::Indentator.new(@options[:indent].abs)
Thread.current[AP] ||= []
end
+
+ def current_indentation
+ indentator.indentation
+ end
+
+ def increase_indentation
+ indentator.indent(&Proc.new)
+ end
# Dispatcher that detects data nesting and invokes object-aware formatter.
#------------------------------------------------------------------------------