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.
@@ -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
  #------------------------------------------------------------------------------