helium-console 0.1.9 → 0.1.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/pull_request.yml +37 -0
- data/.rspec +0 -1
- data/.rubocop.yml +18 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +9 -1
- data/README.md +69 -13
- data/bin/console +1 -1
- data/lib/helium/console/colorized_string.rb +31 -0
- data/lib/helium/console/formatter.rb +127 -0
- data/lib/helium/console/formatters/overflow/wrap.rb +2 -0
- data/lib/helium/console/key_value.rb +130 -0
- data/lib/helium/console/printer.rb +16 -4
- data/lib/helium/console/prompt.rb +44 -0
- data/lib/helium/console/registry/array.rb +22 -11
- data/lib/helium/console/registry/booleans.rb +2 -2
- data/lib/helium/console/registry/date.rb +15 -0
- data/lib/helium/console/registry/hash.rb +29 -14
- data/lib/helium/console/registry/method.rb +64 -0
- data/lib/helium/console/registry/module.rb +18 -6
- data/lib/helium/console/registry/nil.rb +1 -1
- data/lib/helium/console/registry/numeric.rb +7 -1
- data/lib/helium/console/registry/object.rb +21 -40
- data/lib/helium/console/registry/pathname.rb +11 -0
- data/lib/helium/console/registry/set.rb +91 -0
- data/lib/helium/console/registry/string.rb +32 -12
- data/lib/helium/console/registry/symbol.rb +1 -1
- data/lib/helium/console/registry/time.rb +15 -0
- data/lib/helium/console/registry.rb +16 -60
- data/lib/helium/console/version.rb +1 -1
- data/lib/helium/console.rb +45 -29
- metadata +12 -4
- data/lib/helium/console/registry/table.rb +0 -82
- data/lib/helium/console/table.rb +0 -23
@@ -3,7 +3,13 @@
|
|
3
3
|
module Helium
|
4
4
|
class Console
|
5
5
|
define_formatter_for Hash do
|
6
|
-
def
|
6
|
+
def render_compact
|
7
|
+
return '{}' unless object.any?
|
8
|
+
|
9
|
+
"##{format object.class, :compact}#{light_black "[#{object.size}]"}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def render_partial
|
7
13
|
return '{}' if object.none?
|
8
14
|
return inline_with_truncation if force_inline?
|
9
15
|
|
@@ -13,23 +19,27 @@ module Helium
|
|
13
19
|
private
|
14
20
|
|
15
21
|
def format_as_table
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
22
|
+
key_value = build_key_value do |kv|
|
23
|
+
object.each do |key, value|
|
24
|
+
key = light_blue(key.to_s) if all_symbol?
|
25
|
+
kv.row(key, value)
|
26
|
+
end
|
20
27
|
end
|
21
28
|
|
22
|
-
|
23
|
-
'{'
|
24
|
-
|
25
|
-
|
26
|
-
|
29
|
+
yield_lines do |y|
|
30
|
+
y << '{'
|
31
|
+
format_key_value(key_value, left: ' ', between: after_key,
|
32
|
+
format_keys: all_symbol? ? false : {}).lines.each do |line|
|
33
|
+
y << line
|
34
|
+
end
|
35
|
+
y << '}'
|
36
|
+
end
|
27
37
|
end
|
28
38
|
|
29
39
|
def inline_with_truncation
|
30
40
|
truncated = formatted_inline_elements.with_index.inject([]) do |collected, (formatted, index)|
|
31
41
|
new_collected = [*collected[0..-2], formatted, trunc_text(index + 1)].compact
|
32
|
-
break collected if new_collected.join(', ')
|
42
|
+
break collected if length_of(new_collected.join(', ')) > max_width - 4
|
33
43
|
|
34
44
|
new_collected
|
35
45
|
end
|
@@ -55,15 +65,18 @@ module Helium
|
|
55
65
|
end
|
56
66
|
|
57
67
|
def formatted_inline_elements
|
68
|
+
max_width = 15 unless level == 1
|
58
69
|
object.each.lazy.map do |key, value|
|
59
|
-
formatted_key = format_key(key, max_lines: 1, nesting: 1, max_with:
|
60
|
-
formatted_value = format_nested(value, max_lines: 1, nesting: 1, max_width:
|
70
|
+
formatted_key = format_key(key, max_lines: 1, nesting: 1, max_with: max_width)
|
71
|
+
formatted_value = format_nested(value, max_lines: 1, nesting: 1, max_width: max_width)
|
61
72
|
[formatted_key, after_key, formatted_value].join
|
62
73
|
end
|
63
74
|
end
|
64
75
|
|
65
76
|
def all_symbol?
|
66
|
-
|
77
|
+
return @all_symbol if defined?(@all_symbol)
|
78
|
+
|
79
|
+
@all_symbol = object.keys.all? { |key| key.is_a? Symbol }
|
67
80
|
end
|
68
81
|
|
69
82
|
def format_key(key, **options)
|
@@ -78,6 +91,8 @@ module Helium
|
|
78
91
|
|
79
92
|
def trunc_text(count)
|
80
93
|
truncated_elements = total_elements - count
|
94
|
+
return if truncated_elements.zero?
|
95
|
+
|
81
96
|
light_black("(#{truncated_elements} #{count.zero? ? 'elements' : 'more'})")
|
82
97
|
end
|
83
98
|
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Helium
|
4
|
+
class Console
|
5
|
+
define_formatter_for Method do
|
6
|
+
def render_full
|
7
|
+
as_table(source: true)
|
8
|
+
end
|
9
|
+
|
10
|
+
def render_partial
|
11
|
+
as_table(source: false)
|
12
|
+
end
|
13
|
+
|
14
|
+
def render_compact
|
15
|
+
"#{yellow 'method'} #{title}"
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# TODO: he method below breaks ABCSize, most likely due to an amount of colouring method calls.
|
21
|
+
# This should be simplified by altering table handling: https://github.com/helium-rb/console/issues/10
|
22
|
+
def as_table(source:) # rubocop:disable Metrics/AbcSize
|
23
|
+
key_value = build_key_value do |kv|
|
24
|
+
kv.row(magenta('receiver'), object.receiver)
|
25
|
+
kv.row(magenta('location'), object.source_location&.join(':'))
|
26
|
+
kv.row(magenta('source'), trimmed_source, format_value: false) if source && object.source_location
|
27
|
+
end
|
28
|
+
|
29
|
+
yield_lines do |y|
|
30
|
+
y << "#{light_black '#'} #{render_compact}"
|
31
|
+
format_key_value(key_value, left: light_black('| '), format_keys: false, between: light_black(': '))
|
32
|
+
.lines.each { |line| y << line }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def title
|
37
|
+
formatted_owner = format(owner, :compact)
|
38
|
+
formatted_owner = "(#{formatted_owner})" unless owner.is_a? Module
|
39
|
+
|
40
|
+
"#{formatted_owner}#{yellow(singleton_owner? ? '.' : '#')}#{yellow object.name.to_s}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def owner
|
44
|
+
return @owner if defined?(@owner)
|
45
|
+
|
46
|
+
@owner = object.owner
|
47
|
+
if singleton_owner?
|
48
|
+
@owner = object.receiver
|
49
|
+
@owner = owner.ancestors.find { |ancestor| ancestor.singleton_class == object.owner } if owner.is_a? Class
|
50
|
+
end
|
51
|
+
@owner
|
52
|
+
end
|
53
|
+
|
54
|
+
def singleton_owner?
|
55
|
+
object.owner.singleton_class?
|
56
|
+
end
|
57
|
+
|
58
|
+
def trimmed_source
|
59
|
+
indent = object.source.lines.map { |line| line =~ /[^ ]/ }.min
|
60
|
+
object.source.lines.map { |line| line[indent..-1] }.join.chomp
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -2,22 +2,34 @@
|
|
2
2
|
|
3
3
|
module Helium
|
4
4
|
class Console
|
5
|
-
|
6
|
-
def
|
7
|
-
|
5
|
+
define_class_formatter_for BasicObject do
|
6
|
+
def render_compact
|
7
|
+
class_name || singleton_name || anonymous_text
|
8
8
|
end
|
9
9
|
|
10
10
|
private
|
11
11
|
|
12
|
+
def class_name
|
13
|
+
light_yellow(object.name) if object.name
|
14
|
+
end
|
15
|
+
|
16
|
+
def singleton_name
|
17
|
+
return unless object.is_a?(Class) && object.singleton_class?
|
18
|
+
|
19
|
+
owner = ObjectSpace.each_object(object).first
|
20
|
+
"#{light_yellow 'singleton class of'} #{format owner, :compact}"
|
21
|
+
end
|
22
|
+
|
12
23
|
def anonymous_text
|
13
24
|
closest = (object.ancestors.grep(Class) - [Object, BasicObject]).find(&:name)&.name
|
14
25
|
|
15
26
|
signature = if closest
|
16
|
-
"subclass of #{closest}"
|
27
|
+
"#{light_yellow 'subclass of'} #{format closest, :compact}"
|
17
28
|
else
|
18
|
-
object.class.name.downcase
|
29
|
+
light_yellow(object.class.name.downcase)
|
19
30
|
end
|
20
|
-
|
31
|
+
|
32
|
+
"#{light_yellow '('}#{signature})#{light_yellow ')'}"
|
21
33
|
end
|
22
34
|
end
|
23
35
|
end
|
@@ -3,9 +3,15 @@
|
|
3
3
|
module Helium
|
4
4
|
class Console
|
5
5
|
define_formatter_for Numeric do
|
6
|
-
def
|
6
|
+
def render_compact
|
7
7
|
light_cyan(object.to_s)
|
8
8
|
end
|
9
9
|
end
|
10
|
+
|
11
|
+
define_formatter_for 'BigDecimal' do
|
12
|
+
def render_compact
|
13
|
+
light_cyan(object.to_s('F'))
|
14
|
+
end
|
15
|
+
end
|
10
16
|
end
|
11
17
|
end
|
@@ -3,28 +3,17 @@
|
|
3
3
|
module Helium
|
4
4
|
class Console
|
5
5
|
define_formatter_for Object do
|
6
|
-
def
|
7
|
-
return
|
6
|
+
def optimal_format
|
7
|
+
return [:compact, {}] if object.instance_variables.none?
|
8
8
|
|
9
|
-
|
9
|
+
super
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
def format_as_table
|
15
|
-
table = Table.new(runner: light_black('| '), after_key: light_black(': '), format_keys: false)
|
16
|
-
|
17
|
-
object.instance_variables.each do |inst|
|
18
|
-
table.row(magenta(inst.to_s), object.instance_variable_get(inst))
|
19
|
-
end
|
20
|
-
|
21
|
-
[
|
22
|
-
"#{light_black '#'} #{class_name}",
|
23
|
-
format(table)
|
24
|
-
].reject(&:empty?).join("\n")
|
12
|
+
def render_compact
|
13
|
+
"#{format object.class, :compact}#{light_black "##{object.object_id}"}"
|
25
14
|
end
|
26
15
|
|
27
|
-
def
|
16
|
+
def render_inline
|
28
17
|
class_name = class_name(short: true)
|
29
18
|
|
30
19
|
vars = formatted_instance_variables(max_width: 15, max_lines: 1).inject([]) do |collected, element|
|
@@ -38,30 +27,22 @@ module Helium
|
|
38
27
|
[class_name, formatted_vars].compact.join
|
39
28
|
end
|
40
29
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
#
|
47
|
-
# formatted_key = format(key, level: 3, max_with: 15)
|
48
|
-
# formatted_value = format(value, level: 3, max_width: 15)
|
49
|
-
# formatted = "#{formatted_key} => #{formatted_value}"
|
50
|
-
#
|
51
|
-
# joined = [joined, formatted].compact.join(', ')
|
52
|
-
#
|
53
|
-
# return if joined.length > max_width - 4
|
54
|
-
# end
|
55
|
-
# joined = " #{joined} " if joined
|
56
|
-
# ['{', joined, '}'].compact.join
|
57
|
-
# end
|
58
|
-
|
59
|
-
def force_inline?
|
60
|
-
level > 2
|
30
|
+
def render_partial
|
31
|
+
yield_lines do |y|
|
32
|
+
y << "#{light_black '#'} #{class_name}"
|
33
|
+
as_table.lines.each { |line| y << line }
|
34
|
+
end
|
61
35
|
end
|
62
36
|
|
63
|
-
|
64
|
-
|
37
|
+
private
|
38
|
+
|
39
|
+
def as_table
|
40
|
+
key_value = build_key_value do |kv|
|
41
|
+
object.instance_variables.each do |inst|
|
42
|
+
kv.row(magenta(inst.to_s), object.instance_variable_get(inst))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
format_key_value(key_value, left: light_black('| '), between: light_black(': '), format_keys: false)
|
65
46
|
end
|
66
47
|
|
67
48
|
def formatted_instance_variables(**options)
|
@@ -72,7 +53,7 @@ module Helium
|
|
72
53
|
end
|
73
54
|
|
74
55
|
def class_name(short: false)
|
75
|
-
formatted = format(object.class,
|
56
|
+
formatted = format(object.class, :compact)
|
76
57
|
short ? "##{formatted}" : "#{formatted} instance"
|
77
58
|
end
|
78
59
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Helium
|
4
|
+
class Console
|
5
|
+
define_formatter_for 'Set' do
|
6
|
+
def render_compact
|
7
|
+
return render_empty if object.none?
|
8
|
+
|
9
|
+
"#{light_magenta('Set:')} #{trunc_message(object.count, all_truncated: true)}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def render_partial
|
13
|
+
return render_empty if object.none?
|
14
|
+
return inline_with_truncation if options[:max_lines] == 1
|
15
|
+
|
16
|
+
inline_without_truncation || format_as_table
|
17
|
+
end
|
18
|
+
|
19
|
+
def simple?
|
20
|
+
object.none?
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def render_empty
|
26
|
+
"#{light_magenta('Set:')} #{red 'empty'}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def format_as_table
|
30
|
+
table = Table.new(runner: '', format_keys: false)
|
31
|
+
object.each do |element|
|
32
|
+
table.row(light_black('-'), element)
|
33
|
+
end
|
34
|
+
|
35
|
+
yield_lines do |y|
|
36
|
+
y << light_magenta('Set: {')
|
37
|
+
format(table).lines.each { |line| y << line }
|
38
|
+
y << light_magenta('}')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def inline_with_truncation
|
43
|
+
formatted = formatted_elements.with_index.inject([]) do |joined, (element, index)|
|
44
|
+
new_joined = [*joined[0..-2], element, trunc_message(object_size - index - 1, all_truncated: index.zero?)]
|
45
|
+
break joined if too_long?(new_joined, max_width: max_width - 9)
|
46
|
+
|
47
|
+
new_joined
|
48
|
+
end
|
49
|
+
|
50
|
+
"#{light_magenta('Set: {')} #{formatted.join(light_magenta(' | '))} #{light_magenta('}')}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def inline_without_truncation
|
54
|
+
return unless object.all? { |element| Helium::Console.simple? element }
|
55
|
+
|
56
|
+
formatted = formatted_elements.inject([]) do |joined, element|
|
57
|
+
joined = [*joined, element]
|
58
|
+
break if too_long?(joined, max_width: max_width - 4)
|
59
|
+
|
60
|
+
joined
|
61
|
+
end
|
62
|
+
|
63
|
+
"#{light_magenta('Set: {')} #{formatted.join(light_magenta(' | '))} #{light_magenta('}')}" unless formatted.nil?
|
64
|
+
end
|
65
|
+
|
66
|
+
def too_long?(object, max_width:)
|
67
|
+
string = object.respond_to?(:join) ? object.join(' | ') : object
|
68
|
+
length_of(string) > max_width - 4
|
69
|
+
end
|
70
|
+
|
71
|
+
def formatted_elements(**options)
|
72
|
+
sorted = begin
|
73
|
+
object.sort
|
74
|
+
rescue StandardError
|
75
|
+
object
|
76
|
+
end
|
77
|
+
sorted.each.lazy.map { |element| format_nested(element, **options) }
|
78
|
+
end
|
79
|
+
|
80
|
+
def trunc_message(count, all_truncated: false)
|
81
|
+
return if count < 1
|
82
|
+
|
83
|
+
light_black "(#{count} #{all_truncated ? 'elements' : 'more'})"
|
84
|
+
end
|
85
|
+
|
86
|
+
def object_size
|
87
|
+
@object_size ||= object.size
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -3,26 +3,46 @@
|
|
3
3
|
module Helium
|
4
4
|
class Console
|
5
5
|
define_formatter_for String do
|
6
|
-
def
|
7
|
-
|
8
|
-
|
6
|
+
def render_compact
|
7
|
+
render_string(object, max_width: 15, max_lines: 1)
|
8
|
+
end
|
9
|
+
|
10
|
+
def render_inline
|
11
|
+
render_string(object.gsub("\n", '\n'), max_lines: 1)
|
12
|
+
end
|
13
|
+
|
14
|
+
def render_partial
|
15
|
+
render_string(object, max_lines: max_lines || 3)
|
16
|
+
end
|
17
|
+
|
18
|
+
def render_full
|
19
|
+
render_string(object)
|
20
|
+
end
|
21
|
+
|
22
|
+
def simple?
|
23
|
+
object.lines.count == 1 && length_of(object) < 15
|
24
|
+
end
|
25
|
+
|
26
|
+
def render_string(string, max_lines: self.max_lines, max_width: self.max_width)
|
27
|
+
formatted = format_string(
|
28
|
+
"\"#{string.gsub('"', '\"')}\"",
|
9
29
|
max_width: max_width,
|
10
30
|
max_lines: max_lines,
|
11
31
|
overflow: overflow,
|
12
|
-
ellipses: '..."'
|
32
|
+
ellipses: '..."',
|
33
|
+
indent: indent
|
13
34
|
)
|
14
35
|
|
15
|
-
formatted.lines
|
16
|
-
.map { |line| light_green(line) }
|
17
|
-
.join
|
36
|
+
result = formatted.lines
|
37
|
+
.map { |line| light_green(line.chomp) }
|
38
|
+
.join("\n")
|
39
|
+
|
40
|
+
result = "#{result}\n" if formatted.end_with?("\n")
|
41
|
+
result
|
18
42
|
end
|
19
43
|
|
20
44
|
def max_lines
|
21
|
-
|
22
|
-
when 1 then nil
|
23
|
-
when 2 then 3
|
24
|
-
else 1
|
25
|
-
end
|
45
|
+
@options[:max_lines]
|
26
46
|
end
|
27
47
|
end
|
28
48
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Helium
|
4
|
+
class Console
|
5
|
+
define_formatter_for Time do
|
6
|
+
def render_inline
|
7
|
+
blue object.strftime('%A, %d %b %Y, %H:%M:%S')
|
8
|
+
end
|
9
|
+
|
10
|
+
def render_compact
|
11
|
+
blue object.strftime('%d/%m/%Y, %H:%M')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,77 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'colorized_string'
|
3
|
+
require 'helium/console/colorized_string'
|
4
|
+
require 'helium/console/formatter'
|
4
5
|
|
5
6
|
module Helium
|
6
7
|
class Console
|
7
8
|
class Registry
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
@options = options
|
12
|
-
end
|
13
|
-
|
14
|
-
def call
|
15
|
-
end
|
16
|
-
|
17
|
-
attr_reader :object, :options
|
18
|
-
|
19
|
-
def format_nested(other_object, **options)
|
20
|
-
Helium::Console.format(other_object, **nested_opts(options))
|
21
|
-
end
|
22
|
-
|
23
|
-
def format(other_object, **options)
|
24
|
-
Helium::Console.format(other_object, **nested_opts(options, increase_level: false))
|
25
|
-
end
|
26
|
-
|
27
|
-
def format_string(string, **options)
|
28
|
-
Helium::Console.format_string(string, **options)
|
29
|
-
end
|
30
|
-
|
31
|
-
def simple?
|
32
|
-
false
|
33
|
-
end
|
34
|
-
|
35
|
-
def method_missing(name, *args)
|
36
|
-
return @options[name] if @options.key?(name)
|
37
|
-
return ColorizedString.new(*args).colorize(name) if ColorizedString.colors.include?(name)
|
38
|
-
|
39
|
-
super
|
40
|
-
end
|
41
|
-
|
42
|
-
def respond_to_missing?(name, private = false)
|
43
|
-
@options.key?(name) || ColorizedString.colors.include?(name) || super
|
44
|
-
end
|
45
|
-
|
46
|
-
def nested_opts(new_options, increase_level: true)
|
47
|
-
new_options = options.merge(new_options)
|
48
|
-
new_options[:level] += 1 if increase_level
|
49
|
-
new_options[:ignore_objects] << object.object_id
|
50
|
-
new_options
|
51
|
-
end
|
9
|
+
def self.instance_formatters
|
10
|
+
@instance_formatters ||= new
|
11
|
+
end
|
52
12
|
|
53
|
-
|
54
|
-
|
55
|
-
end
|
13
|
+
def self.class_formatters
|
14
|
+
@class_formatters ||= new
|
56
15
|
end
|
57
16
|
|
58
|
-
def add(
|
59
|
-
|
60
|
-
define_method(:call, &handler)
|
61
|
-
end
|
17
|
+
def add(mod, formatter)
|
18
|
+
handlers[mod] = formatter
|
62
19
|
end
|
63
20
|
|
64
|
-
def define(
|
65
|
-
|
21
|
+
def define(mod, &block)
|
22
|
+
add(mod, Class.new(Formatter, &block))
|
66
23
|
end
|
67
24
|
|
68
|
-
def handler_for(
|
69
|
-
|
70
|
-
|
25
|
+
def handler_for(klass)
|
26
|
+
klass.ancestors.each do |ancestor|
|
27
|
+
result = handlers[ancestor] || handlers[ancestor.name]
|
28
|
+
return result if result
|
71
29
|
end
|
72
|
-
|
73
|
-
|
74
|
-
element_class.new(object, **options)
|
30
|
+
handlers[BasicObject]
|
75
31
|
end
|
76
32
|
|
77
33
|
private
|