helium-console 0.1.9 → 0.1.13
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/.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
|