awesome_print 1.6.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Appraisals +16 -3
- data/{CHANGELOG → CHANGELOG.md} +55 -18
- data/CONTRIBUTING.md +43 -3
- data/README.md +13 -52
- data/lib/awesome_print.rb +2 -2
- data/lib/awesome_print/colorize.rb +24 -0
- data/lib/awesome_print/ext/nobrainer.rb +49 -0
- data/lib/awesome_print/formatter.rb +53 -326
- data/lib/awesome_print/formatters/array_formatter.rb +73 -0
- data/lib/awesome_print/formatters/base_formatter.rb +138 -0
- data/lib/awesome_print/formatters/class_formatter.rb +24 -0
- data/lib/awesome_print/formatters/dir_formatter.rb +22 -0
- data/lib/awesome_print/formatters/file_formatter.rb +22 -0
- data/lib/awesome_print/formatters/hash_formatter.rb +54 -0
- data/lib/awesome_print/formatters/method_formatter.rb +22 -0
- data/lib/awesome_print/formatters/object_formatter.rb +80 -0
- data/lib/awesome_print/formatters/simple_formatter.rb +21 -0
- data/lib/awesome_print/indentator.rb +18 -0
- data/lib/awesome_print/inspector.rb +12 -1
- data/lib/awesome_print/version.rb +1 -1
- data/spec/active_record_helper.rb +19 -29
- data/spec/colors_spec.rb +2 -2
- data/spec/formats_spec.rb +73 -34
- data/spec/methods_spec.rb +6 -6
- data/spec/misc_spec.rb +4 -2
- data/spec/objects_spec.rb +52 -8
- data/spec/spec_helper.rb +49 -34
- metadata +31 -6
- data/lib/awesome_print/ext/no_brainer.rb +0 -58
@@ -0,0 +1,138 @@
|
|
1
|
+
require_relative "../colorize"
|
2
|
+
|
3
|
+
module AwesomePrint
|
4
|
+
module Formatters
|
5
|
+
class BaseFormatter
|
6
|
+
include Colorize
|
7
|
+
|
8
|
+
DEFAULT_LIMIT_SIZE = 7
|
9
|
+
|
10
|
+
# To support limited output, for example:
|
11
|
+
#
|
12
|
+
# ap ('a'..'z').to_a, :limit => 3
|
13
|
+
# [
|
14
|
+
# [ 0] "a",
|
15
|
+
# [ 1] .. [24],
|
16
|
+
# [25] "z"
|
17
|
+
# ]
|
18
|
+
#
|
19
|
+
# ap (1..100).to_a, :limit => true # Default limit is 7.
|
20
|
+
# [
|
21
|
+
# [ 0] 1,
|
22
|
+
# [ 1] 2,
|
23
|
+
# [ 2] 3,
|
24
|
+
# [ 3] .. [96],
|
25
|
+
# [97] 98,
|
26
|
+
# [98] 99,
|
27
|
+
# [99] 100
|
28
|
+
# ]
|
29
|
+
#------------------------------------------------------------------------------
|
30
|
+
def should_be_limited?
|
31
|
+
options[:limit] or (options[:limit].is_a?(Fixnum) and options[:limit] > 0)
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_limit_size
|
35
|
+
case options[:limit]
|
36
|
+
when true
|
37
|
+
DEFAULT_LIMIT_SIZE
|
38
|
+
else
|
39
|
+
options[:limit]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def limited(data, width, is_hash = false)
|
44
|
+
limit = get_limit_size
|
45
|
+
if data.length <= limit
|
46
|
+
data
|
47
|
+
else
|
48
|
+
# Calculate how many elements to be displayed above and below the separator.
|
49
|
+
head = limit / 2
|
50
|
+
tail = head - (limit - 1) % 2
|
51
|
+
|
52
|
+
# Add the proper elements to the temp array and format the separator.
|
53
|
+
temp = data[0, head] + [ nil ] + data[-tail, tail]
|
54
|
+
|
55
|
+
if is_hash
|
56
|
+
temp[head] = "#{indent}#{data[head].strip} .. #{data[data.length - tail - 1].strip}"
|
57
|
+
else
|
58
|
+
temp[head] = "#{indent}[#{head.to_s.rjust(width)}] .. [#{data.length - tail - 1}]"
|
59
|
+
end
|
60
|
+
|
61
|
+
temp
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def method_tuple(method)
|
67
|
+
if method.respond_to?(:parameters) # Ruby 1.9.2+
|
68
|
+
# See http://ruby.runpaint.org/methods#method-objects-parameters
|
69
|
+
args = method.parameters.inject([]) do |arr, (type, name)|
|
70
|
+
name ||= (type == :block ? 'block' : "arg#{arr.size + 1}")
|
71
|
+
arr << case type
|
72
|
+
when :req then name.to_s
|
73
|
+
when :opt, :rest then "*#{name}"
|
74
|
+
when :block then "&#{name}"
|
75
|
+
else '?'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
else # See http://ruby-doc.org/core/classes/Method.html#M001902
|
79
|
+
args = (1..method.arity.abs).map { |i| "arg#{i}" }
|
80
|
+
args[-1] = "*#{args[-1]}" if method.arity < 0
|
81
|
+
end
|
82
|
+
|
83
|
+
# method.to_s formats to handle:
|
84
|
+
#
|
85
|
+
# #<Method: Fixnum#zero?>
|
86
|
+
# #<Method: Fixnum(Integer)#years>
|
87
|
+
# #<Method: User(#<Module:0x00000103207c00>)#_username>
|
88
|
+
# #<Method: User(id: integer, username: string).table_name>
|
89
|
+
# #<Method: User(id: integer, username: string)(ActiveRecord::Base).current>
|
90
|
+
# #<UnboundMethod: Hello#world>
|
91
|
+
#
|
92
|
+
if method.to_s =~ /(Unbound)*Method: (.*)[#\.]/
|
93
|
+
unbound, klass = $1 && '(unbound)', $2
|
94
|
+
if klass && klass =~ /(\(\w+:\s.*?\))/ # Is this ActiveRecord-style class?
|
95
|
+
klass.sub!($1, '') # Yes, strip the fields leaving class name only.
|
96
|
+
end
|
97
|
+
owner = "#{klass}#{unbound}".gsub('(', ' (')
|
98
|
+
end
|
99
|
+
|
100
|
+
[ method.name.to_s, "(#{args.join(', ')})", owner.to_s ]
|
101
|
+
end
|
102
|
+
|
103
|
+
#
|
104
|
+
# Indentation related methods
|
105
|
+
#-----------------------------------------
|
106
|
+
def indentation
|
107
|
+
inspector.current_indentation
|
108
|
+
end
|
109
|
+
|
110
|
+
def indented
|
111
|
+
inspector.increase_indentation(&Proc.new)
|
112
|
+
end
|
113
|
+
|
114
|
+
def indent
|
115
|
+
' ' * indentation
|
116
|
+
end
|
117
|
+
|
118
|
+
def outdent
|
119
|
+
' ' * (indentation - options[:indent].abs)
|
120
|
+
end
|
121
|
+
|
122
|
+
def align(value, width)
|
123
|
+
if options[:multiline]
|
124
|
+
if options[:indent] > 0
|
125
|
+
value.rjust(width)
|
126
|
+
elsif options[:indent] == 0
|
127
|
+
indent + value.ljust(width)
|
128
|
+
else
|
129
|
+
indent[0, indentation + options[:indent]] + value.ljust(width)
|
130
|
+
end
|
131
|
+
else
|
132
|
+
value
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative 'base_formatter'
|
2
|
+
|
3
|
+
module AwesomePrint
|
4
|
+
module Formatters
|
5
|
+
class ClassFormatter < BaseFormatter
|
6
|
+
|
7
|
+
attr_reader :klass, :inspector, :options
|
8
|
+
|
9
|
+
def initialize(klass, inspector)
|
10
|
+
@klass = klass
|
11
|
+
@inspector = inspector
|
12
|
+
@options = inspector.options
|
13
|
+
end
|
14
|
+
|
15
|
+
def format
|
16
|
+
if superclass = klass.superclass # <-- Assign and test if nil.
|
17
|
+
colorize("#{klass.inspect} < #{superclass}", :class)
|
18
|
+
else
|
19
|
+
colorize(klass.inspect, :class)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'base_formatter'
|
2
|
+
require "shellwords"
|
3
|
+
|
4
|
+
module AwesomePrint
|
5
|
+
module Formatters
|
6
|
+
class DirFormatter < BaseFormatter
|
7
|
+
|
8
|
+
attr_reader :dir, :inspector, :options
|
9
|
+
|
10
|
+
def initialize(dir, inspector)
|
11
|
+
@dir = dir
|
12
|
+
@inspector = inspector
|
13
|
+
@options = inspector.options
|
14
|
+
end
|
15
|
+
|
16
|
+
def format
|
17
|
+
ls = `ls -alF #{dir.path.shellescape}`
|
18
|
+
colorize(ls.empty? ? dir.inspect : "#{dir.inspect}\n#{ls.chop}", :dir)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'base_formatter'
|
2
|
+
require "shellwords"
|
3
|
+
|
4
|
+
module AwesomePrint
|
5
|
+
module Formatters
|
6
|
+
class FileFormatter < BaseFormatter
|
7
|
+
|
8
|
+
attr_reader :file, :inspector, :options
|
9
|
+
|
10
|
+
def initialize(file, inspector)
|
11
|
+
@file = file
|
12
|
+
@inspector = inspector
|
13
|
+
@options = inspector.options
|
14
|
+
end
|
15
|
+
|
16
|
+
def format
|
17
|
+
ls = File.directory?(file) ? `ls -adlF #{file.path.shellescape}` : `ls -alF #{file.path.shellescape}`
|
18
|
+
colorize(ls.empty? ? file.inspect : "#{file.inspect}\n#{ls.chop}", :file)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require_relative 'base_formatter'
|
2
|
+
|
3
|
+
module AwesomePrint
|
4
|
+
module Formatters
|
5
|
+
class HashFormatter < BaseFormatter
|
6
|
+
|
7
|
+
attr_reader :hash, :inspector, :options
|
8
|
+
|
9
|
+
def initialize(hash, inspector)
|
10
|
+
@hash = hash
|
11
|
+
@inspector = inspector
|
12
|
+
@options = inspector.options
|
13
|
+
end
|
14
|
+
|
15
|
+
def format
|
16
|
+
return "{}" if hash == {}
|
17
|
+
|
18
|
+
keys = hash.keys
|
19
|
+
keys = keys.sort { |a, b| a.to_s <=> b.to_s } if options[:sort_keys]
|
20
|
+
data = keys.map do |key|
|
21
|
+
plain_single_line do
|
22
|
+
[ inspector.awesome(key), hash[key] ]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
width = data.map { |key, | key.size }.max || 0
|
27
|
+
width += indentation if options[:indent] > 0
|
28
|
+
|
29
|
+
data = data.map do |key, value|
|
30
|
+
indented do
|
31
|
+
align(key, width) << colorize(" => ", :hash) << inspector.awesome(value)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
data = limited(data, width, :hash => true) if should_be_limited?
|
36
|
+
if options[:multiline]
|
37
|
+
"{\n" << data.join(",\n") << "\n#{outdent}}"
|
38
|
+
else
|
39
|
+
"{ #{data.join(', ')} }"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def plain_single_line
|
46
|
+
plain, multiline = options[:plain], options[:multiline]
|
47
|
+
options[:plain], options[:multiline] = true, false
|
48
|
+
yield
|
49
|
+
ensure
|
50
|
+
options[:plain], options[:multiline] = plain, multiline
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'base_formatter'
|
2
|
+
|
3
|
+
module AwesomePrint
|
4
|
+
module Formatters
|
5
|
+
class MethodFormatter < BaseFormatter
|
6
|
+
|
7
|
+
attr_reader :method, :inspector, :options
|
8
|
+
|
9
|
+
def initialize(method, inspector)
|
10
|
+
@method = method
|
11
|
+
@inspector = inspector
|
12
|
+
@options = inspector.options
|
13
|
+
end
|
14
|
+
|
15
|
+
def format
|
16
|
+
name, args, owner = method_tuple(method)
|
17
|
+
|
18
|
+
"#{colorize(owner, :class)}##{colorize(name, :method)}#{colorize(args, :args)}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require_relative 'base_formatter'
|
2
|
+
|
3
|
+
module AwesomePrint
|
4
|
+
module Formatters
|
5
|
+
class ObjectFormatter < BaseFormatter
|
6
|
+
|
7
|
+
attr_reader :object, :variables, :inspector, :options
|
8
|
+
|
9
|
+
def initialize(object, variables, inspector)
|
10
|
+
@object = object
|
11
|
+
@variables = variables
|
12
|
+
@inspector = inspector
|
13
|
+
@options = inspector.options
|
14
|
+
end
|
15
|
+
|
16
|
+
def format
|
17
|
+
vars = variables.map do |var|
|
18
|
+
property = var.to_s[1..-1].to_sym # to_s because of some monkey patching done by Puppet.
|
19
|
+
accessor = if object.respond_to?(:"#{property}=")
|
20
|
+
object.respond_to?(property) ? :accessor : :writer
|
21
|
+
else
|
22
|
+
object.respond_to?(property) ? :reader : nil
|
23
|
+
end
|
24
|
+
if accessor
|
25
|
+
[ "attr_#{accessor} :#{property}", var ]
|
26
|
+
else
|
27
|
+
[ var.to_s, var ]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
data = vars.sort.map do |declaration, var|
|
32
|
+
key = left_aligned do
|
33
|
+
align(declaration, declaration.size)
|
34
|
+
end
|
35
|
+
|
36
|
+
unless options[:plain]
|
37
|
+
if key =~ /(@\w+)/
|
38
|
+
key.sub!($1, colorize($1, :variable))
|
39
|
+
else
|
40
|
+
key.sub!(/(attr_\w+)\s(\:\w+)/, "#{colorize('\\1', :keyword)} #{colorize('\\2', :method)}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
indented do
|
45
|
+
var_contents = if valid_instance_var?(var)
|
46
|
+
object.instance_variable_get(var)
|
47
|
+
else
|
48
|
+
object.send(var) # Enables handling of Struct attributes
|
49
|
+
end
|
50
|
+
|
51
|
+
key << colorize(" = ", :hash) + inspector.awesome(var_contents)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
if options[:multiline]
|
56
|
+
"#<#{awesome_instance}\n#{data.join(%Q/,\n/)}\n#{outdent}>"
|
57
|
+
else
|
58
|
+
"#<#{awesome_instance} #{data.join(', ')}>"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def valid_instance_var?(variable_name)
|
65
|
+
variable_name.to_s.start_with?('@')
|
66
|
+
end
|
67
|
+
|
68
|
+
def awesome_instance
|
69
|
+
"#{object.class}:0x%08x" % (object.__id__ * 2)
|
70
|
+
end
|
71
|
+
|
72
|
+
def left_aligned
|
73
|
+
current, options[:indent] = options[:indent], 0
|
74
|
+
yield
|
75
|
+
ensure
|
76
|
+
options[:indent] = current
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative 'base_formatter'
|
2
|
+
|
3
|
+
module AwesomePrint
|
4
|
+
module Formatters
|
5
|
+
class SimpleFormatter < BaseFormatter
|
6
|
+
|
7
|
+
attr_reader :string, :type, :inspector, :options
|
8
|
+
|
9
|
+
def initialize(string, type, inspector)
|
10
|
+
@string = string
|
11
|
+
@type = type
|
12
|
+
@inspector = inspector
|
13
|
+
@options = inspector.options
|
14
|
+
end
|
15
|
+
|
16
|
+
def format
|
17
|
+
colorize(string, type)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module AwesomePrint
|
2
|
+
class Indentator
|
3
|
+
|
4
|
+
attr_reader :shift_width, :indentation
|
5
|
+
|
6
|
+
def initialize(indentation)
|
7
|
+
@indentation = indentation
|
8
|
+
@shift_width = indentation.freeze
|
9
|
+
end
|
10
|
+
|
11
|
+
def indent
|
12
|
+
@indentation += shift_width
|
13
|
+
yield
|
14
|
+
ensure
|
15
|
+
@indentation -= shift_width
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -3,6 +3,8 @@
|
|
3
3
|
# Awesome Print is freely distributable under the terms of MIT license.
|
4
4
|
# See LICENSE file or http://www.opensource.org/licenses/mit-license.php
|
5
5
|
#------------------------------------------------------------------------------
|
6
|
+
require_relative "indentator"
|
7
|
+
|
6
8
|
module AwesomePrint
|
7
9
|
|
8
10
|
class << self # Class accessors for custom defaults.
|
@@ -48,7 +50,7 @@ module AwesomePrint
|
|
48
50
|
end
|
49
51
|
|
50
52
|
class Inspector
|
51
|
-
attr_accessor :options
|
53
|
+
attr_accessor :options, :indentator
|
52
54
|
|
53
55
|
AP = :__awesome_print__
|
54
56
|
|
@@ -90,8 +92,17 @@ module AwesomePrint
|
|
90
92
|
merge_options!(options)
|
91
93
|
|
92
94
|
@formatter = AwesomePrint::Formatter.new(self)
|
95
|
+
@indentator = AwesomePrint::Indentator.new(@options[:indent].abs)
|
93
96
|
Thread.current[AP] ||= []
|
94
97
|
end
|
98
|
+
|
99
|
+
def current_indentation
|
100
|
+
indentator.indentation
|
101
|
+
end
|
102
|
+
|
103
|
+
def increase_indentation
|
104
|
+
indentator.indent(&Proc.new)
|
105
|
+
end
|
95
106
|
|
96
107
|
# Dispatcher that detects data nesting and invokes object-aware formatter.
|
97
108
|
#------------------------------------------------------------------------------
|