helium-console 0.1.11 → 0.1.12

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d935efaa6d5d2a98d58c2d0cea17911486522ce45bfd00432b089735994ce20
4
- data.tar.gz: c86a17fc7b04379249cf491da55086537f7f8983c47758d9b20438495f12039e
3
+ metadata.gz: eaa7f60f45f5dfc8e2debd5115c10760755ea71ae485328300af7d4a36cff972
4
+ data.tar.gz: ce41d603bfcee8df481f4132cf2b82a03842de53452474d4b71fd65d6a676d5e
5
5
  SHA512:
6
- metadata.gz: 2ab8ca592e31437b6e70cd269cd961b8fc38c3e544b24aa2eecfbddce474ed22ebda4c704849271b847656e22d15b25feb169aedad5593f6267378e211b068bf
7
- data.tar.gz: 2915fa426caea028e549e9d55e5a4cb7799ef593cdd706529c9eac5bc582a841bdaaa67fb1480917df0543286a0d7743f5eb13b813b92ad4193eab207d49a378
6
+ metadata.gz: fbd742302810644a5c0e18d9ea1bb2bb1fef2d1995a2670dea2996478cc8eaf3232b07ba42785a84e9f9bb8fbc1d57a462cf3583747d0b3366f3a8072aab1fc2
7
+ data.tar.gz: 52cfe0ed72fddd80f8c61f4063d01ff8305a0a00ca88944fc73a0d3e1e466abdc262ab55b0fd050b27891af35dad0e349fd7e5d4b08904b0da30bec90d2e43e7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- helium-console (0.1.11)
4
+ helium-console (0.1.12)
5
5
  colorize
6
6
  pry
7
7
 
data/README.md CHANGED
@@ -1,7 +1,13 @@
1
1
  # Helium::Console
2
2
 
3
+ Readable console output for your ruby project!
4
+
3
5
  It is really tricky to display data in the console in the readable and consistent way. Many objects needs to display other objects, which might break their own formatting.
4
- Helium:Console is to make it easier by formatting strings in accordance to current console size.
6
+ Helium:Console is an attempt to make your development console more readable by:
7
+ * limiting displayed nesting levels to 3
8
+ * limiting data displayed for nested objects
9
+ * using nested table layout
10
+ * automatically dividing and wrapping long strings
5
11
 
6
12
  ## Installation
7
13
 
@@ -21,24 +27,74 @@ Or install it yourself as:
21
27
 
22
28
  ## Usage
23
29
 
24
- Helium::Console helps you to format any string in such a way that it displays nicely in the console:
30
+ You can start helium console same way as you would start Pry:
31
+
32
+ ``` ruby
33
+ require 'helium/console'
34
+ Helium::Console.start
35
+ ```
36
+
37
+ ### Custom formatters
38
+
39
+ Helium::Console hooks into pry and brings a number of default formatters. Unlike IRB and Pry, it does not use object's methods for display
40
+ (so no `inspect` nor `pretty_print`) and replaces them by the collection of inheritable formatters objects stored in its registry.
41
+
42
+ Formatter can be any object that conforms to the following interface:
43
+ * `initialize(object_to_format, format, console_instance, **options)`
44
+ * `call` method returning any object responding to `lines` (e.g. `String` )
45
+
46
+ Formatter bellow will simply return a result of `inspect` call on the object:
47
+
48
+ ```ruby
49
+ class InspectFormatter
50
+ def initialize(object, _console, **)
51
+ @object = object
52
+ end
53
+
54
+ def call
55
+ @object.inspect
56
+ end
57
+ end
58
+ ```
59
+
60
+ You can register your formatter in console registry with:
25
61
 
62
+ ```ruby
63
+ Helium::Console.register(Kernel, InspectFormatter)
26
64
  ```
27
- string = "- Hello there!\nGeneral Kenobi"
28
- Helium::Console.format(string, indent: 2)
29
- => " - Hello there!\n General Kenobi"
65
+
66
+ The call above makes `InspectFormatter` available for all the objects that derives from Kernel module.
67
+
68
+ To make formatting easier, you can subclass your formatter from `Helium::Console::Registry::Element`. By doing so, the following methods will be available to you inside your formatter class:
69
+ * `object`, `console` and `options` readers
70
+ * default `call` implementation, delegating formatting to one
71
+ * `format(other_object, **options)` - formats some other object **using the exact same options, including nesting level**.
72
+ * `format_nested(other_object, **options)` - as above, but increases nesting level.
73
+ * `format_string(string, **options)` - formats string by splitting it into lines of appropriate length and truncating (depending on nesting level).
74
+ This is different to `format` and `format_nested` as it will not trigger `String` formatter (which by default adds quotes, escapes inner quotes and colors the result light green)
75
+ * `red(string)`, `light_red(string)`, `yellow(string)`, etc - returns colorized string when `Pry.color` is set to true.
76
+ * `length_of(string)` - utility option returning the length of displayed string, handling both colorized and non-colorized strings.
77
+
78
+ ### Displaying as a table
79
+
80
+ To display object in a form of a table, format instance of `Helium::Console::Table`:
81
+
82
+ ```ruby
83
+ class MyFormatter < Helium::Console::Registry::Element
84
+ def call
85
+ table = Helium::Console::Table.new(runner: '--@', after_key: '--@--', format_keys: false)
86
+ table.row magenta("property 1"), object.prop1
87
+ table.row magenta("property 2"), object.instance_variable_get(:@prop2)
88
+
89
+ format table
90
+ end
91
+ end
30
92
  ```
31
93
 
32
- When executed in a non-console environment `format` simply returns the string.
94
+ Table will automatically format all the right-hand values with an increased nesting level. By default, it will also format the left-hand keys, however this is controlled with `format_keys` option.
33
95
 
34
- Supported formattign options:
96
+ Other options: `runner` is a string to be displayed at the beginning of each line, and `after_key` is a string to be injected between left and right values.
35
97
 
36
- * `indent` - specifies the amount of spaces added to each new line. Also accepts hash `{first:, other:}`. Defaults to 0.
37
- * `overflow` - specifies how to handle lines longer than console line width.
38
- * `:wrap` - splits the long line into few lines and applies the required indent.
39
- * `:wrap_words` - similar to wrap, but will try to avoid breaking the words.
40
- * `:none` - does not modify long strings.
41
- * `max-lines` - specifies how many lines to display. Last line will be truncated with `...`. Defaults to `nil`
42
98
 
43
99
  ## Development
44
100
 
data/bin/console CHANGED
@@ -7,4 +7,4 @@ require 'helium/console'
7
7
  require 'byebug'
8
8
  require 'ffaker'
9
9
 
10
- Pry.start
10
+ Helium::Console.start
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'colorized_string'
4
+
5
+ module Helium
6
+ class Console
7
+ class ColorizedString < ColorizedString
8
+ def length
9
+ uncolorize.to_s.length
10
+ end
11
+
12
+ def colorize(*)
13
+ return self unless Pry.color
14
+
15
+ super
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Helium
4
+ class Console
5
+ class Formatter
6
+ DEFAULT_STYLES = {
7
+ 1 => [:full, {}],
8
+ 2 => [:partial, {}],
9
+ 3 => [:partial, { max_lines: 1 }]
10
+ }.freeze
11
+
12
+ class LazyStringEvaluator
13
+ def initialize(&block)
14
+ @lines = Enumerator.new { |y| block.(y) }
15
+ end
16
+
17
+ attr_reader :lines
18
+
19
+ def to_s
20
+ lines.to_a.join
21
+ end
22
+ end
23
+
24
+ def initialize(object, style, console, **options)
25
+ @object = object
26
+ @options = options
27
+ @style = style
28
+ @console = console
29
+ end
30
+
31
+ def call
32
+ method_name = [:render, @style].compact.join('_')
33
+ public_send(method_name)
34
+ end
35
+
36
+ def optimal_format
37
+ DEFAULT_STYLES.fetch(level) { [:compact, {}] }
38
+ end
39
+
40
+ def render
41
+ format(object, *optimal_format)
42
+ end
43
+
44
+ def render_full
45
+ render_partial
46
+ end
47
+
48
+ def render_partial
49
+ format_string(render_inline, max_width: max_width, indent: indent)
50
+ end
51
+
52
+ def render_inline
53
+ render_compact
54
+ end
55
+
56
+ def render_compact
57
+ raise NotImplementedError
58
+ end
59
+
60
+ attr_reader :object, :options
61
+
62
+ def format_nested(other_object, style = nil, **options)
63
+ @console.format(other_object, style, **nested_opts(options))
64
+ end
65
+
66
+ def format(other_object, style = nil, **options)
67
+ @console.format(other_object, style, **nested_opts(options, increase_level: false))
68
+ end
69
+
70
+ def format_string(string, **options)
71
+ @console.format_string(string, **options)
72
+ end
73
+
74
+ def simple?
75
+ false
76
+ end
77
+
78
+ ColorizedString.colors.each do |color|
79
+ define_method color do |string|
80
+ ColorizedString.new(string).colorize(color)
81
+ end
82
+ end
83
+
84
+ def method_missing(name, *args)
85
+ return @options[name] if @options.key?(name)
86
+
87
+ super
88
+ end
89
+
90
+ def respond_to_missing?(name, private = false)
91
+ @options.key?(name) || super
92
+ end
93
+
94
+ private
95
+
96
+ def nested_objects
97
+ []
98
+ end
99
+
100
+ def nested_opts(new_options, increase_level: true)
101
+ new_options = options.merge(new_options)
102
+ new_options[:level] += 1 if increase_level
103
+ new_options[:ignore_objects] = nested_objects
104
+ new_options
105
+ end
106
+
107
+ def length_of(string)
108
+ ColorizedString.new(string).length
109
+ end
110
+
111
+ def yield_lines(&block)
112
+ LazyStringEvaluator.new(&block)
113
+ end
114
+ end
115
+ end
116
+ end
@@ -11,15 +11,22 @@ module Helium
11
11
  end
12
12
 
13
13
  def pp(object)
14
- formatted = Helium::Console.format(object)
15
- output << "\n" if object.is_a? Registry::Element::LazyStringEvaluator
16
- formatted.lines.each do |line|
17
- output << "#{line.chomp}\n"
14
+ formatted = Helium::Console.format(object, max_width: maxwidth)
15
+ start_new_line = formatted.is_a?(Formatter::LazyStringEvaluator)
16
+ byebug if !formatted
17
+ start_new_line ||= formatted.lines.count > 1
18
+ start_new_line ||= length_of(formatted.chomp) >= maxwidth - 2
19
+ output << "\n" if start_new_line
20
+
21
+ formatted.lines.each.with_index do |line, index|
22
+ output << "\n" unless index.zero?
23
+ output << line.chomp
18
24
  end
19
- output << "\n"
20
25
  end
21
26
 
22
- ::Pry.config.print = method(:default)
27
+ def length_of(str)
28
+ ColorizedString.new(str).uncolorize.length
29
+ end
23
30
  end
24
31
  end
25
- end
32
+ end
@@ -0,0 +1,42 @@
1
+ module Helium
2
+ class Console
3
+ class Prompt
4
+ def initialize
5
+ @line = 0
6
+ end
7
+
8
+ def pry_prompt
9
+ Pry::Prompt.new(
10
+ 'helium',
11
+ 'Default prompt for helium',
12
+ [
13
+ method(:active_prompt),
14
+ method(:wait_prompt)
15
+ ]
16
+ )
17
+ end
18
+
19
+ private
20
+
21
+ def active_prompt(context, _nesting, _pry)
22
+ @line += 1
23
+ str = [
24
+ ColorizedString.new("[#{@line}]").light_black,
25
+ ColorizedString.new("He\u269B").light_blue,
26
+ ColorizedString.new("(#{context.inspect})").magenta
27
+ ].join(' ')
28
+ "#{str}> "
29
+ end
30
+
31
+ def wait_prompt(context, nesting, pry)
32
+ @line += 1
33
+ str = [
34
+ ColorizedString.new("[#{@line}]").light_black,
35
+ ' ',
36
+ ColorizedString.new("(#{context.inspect})").magenta
37
+ ].join(' ')
38
+ "#{str}> "
39
+ end
40
+ end
41
+ end
42
+ end
@@ -3,13 +3,23 @@
3
3
  module Helium
4
4
  class Console
5
5
  define_formatter_for Array do
6
- def call
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
 
10
16
  inline_without_truncation || format_as_table
11
17
  end
12
18
 
19
+ def render_inline
20
+ inline_with_truncation
21
+ end
22
+
13
23
  def simple?
14
24
  object.none?
15
25
  end
@@ -32,7 +42,7 @@ module Helium
32
42
  def inline_with_truncation
33
43
  formatted = formatted_elements.with_index.inject([]) do |joined, (element, index)|
34
44
  new_joined = [*joined[0..-2], element, trunc_message(object_size - index - 1, all_truncated: index.zero?)]
35
- break joined if too_long?(new_joined, max_width: max_width - 4)
45
+ break joined if max_width && too_long?(new_joined, max_width: max_width - 4)
36
46
 
37
47
  new_joined
38
48
  end
@@ -65,7 +75,7 @@ module Helium
65
75
  def trunc_message(count, all_truncated: false)
66
76
  return if count < 1
67
77
 
68
- "(#{count} #{all_truncated ? 'elements' : 'more'})"
78
+ light_black "(#{count} #{all_truncated ? 'elements' : 'more'})"
69
79
  end
70
80
 
71
81
  def object_size
@@ -3,13 +3,13 @@
3
3
  module Helium
4
4
  class Console
5
5
  define_formatter_for TrueClass do
6
- def call
6
+ def render_compact
7
7
  green('true')
8
8
  end
9
9
  end
10
10
 
11
11
  define_formatter_for FalseClass do
12
- def call
12
+ def render_compact
13
13
  red('false')
14
14
  end
15
15
  end
@@ -3,9 +3,13 @@
3
3
  module Helium
4
4
  class Console
5
5
  define_formatter_for 'Date' do
6
- def call
6
+ def render_inline
7
7
  blue object.strftime('%A, %d %b %Y')
8
8
  end
9
+
10
+ def render_comapact
11
+ blue object.strftime('%d/%m/%Y')
12
+ end
9
13
  end
10
14
  end
11
15
  end
@@ -3,7 +3,13 @@
3
3
  module Helium
4
4
  class Console
5
5
  define_formatter_for Hash do
6
- def call
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
 
@@ -29,7 +35,7 @@ module Helium
29
35
  def inline_with_truncation
30
36
  truncated = formatted_inline_elements.with_index.inject([]) do |collected, (formatted, index)|
31
37
  new_collected = [*collected[0..-2], formatted, trunc_text(index + 1)].compact
32
- break collected if new_collected.join(', ').length > max_width - 4
38
+ break collected if length_of(new_collected.join(', ')) > max_width - 4
33
39
 
34
40
  new_collected
35
41
  end
@@ -55,9 +61,10 @@ module Helium
55
61
  end
56
62
 
57
63
  def formatted_inline_elements
64
+ max_width = 15 unless level == 1
58
65
  object.each.lazy.map do |key, value|
59
- formatted_key = format_key(key, max_lines: 1, nesting: 1, max_with: 15)
60
- formatted_value = format_nested(value, max_lines: 1, nesting: 1, max_width: 15)
66
+ formatted_key = format_key(key, max_lines: 1, nesting: 1, max_with: max_width)
67
+ formatted_value = format_nested(value, max_lines: 1, nesting: 1, max_width: max_width)
61
68
  [formatted_key, after_key, formatted_value].join
62
69
  end
63
70
  end
@@ -81,6 +88,8 @@ module Helium
81
88
 
82
89
  def trunc_text(count)
83
90
  truncated_elements = total_elements - count
91
+ return if truncated_elements.zero?
92
+
84
93
  light_black("(#{truncated_elements} #{count.zero? ? 'elements' : 'more'})")
85
94
  end
86
95
 
@@ -0,0 +1,53 @@
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
+ def as_table(source:)
21
+ table = Table.new(runner: light_black('| '), format_keys: false, after_key: light_black(': '))
22
+ table.row(magenta('receiver'), object.receiver)
23
+ table.row(magenta('location'), object.source_location&.join(':'))
24
+ table.row(magenta('source'), trimmed_source, :full) if source && object.source_location
25
+
26
+ yield_lines do |y|
27
+ y << "#{light_black '#'} #{render_compact}"
28
+ format(table).lines.each { |line| y << line }
29
+ end
30
+ end
31
+
32
+ def title
33
+ owner = object.owner
34
+ singleton = owner.singleton_class?
35
+
36
+ if singleton
37
+ owner = object.receiver
38
+ owner = owner.ancestors.find { |ancestor| ancestor.singleton_class == object.owner } if owner.is_a? Class
39
+ end
40
+
41
+ formatted_owner = format(owner, short: true, max_length: 20)
42
+ formatted_owner = "(#{formatted_owner})" unless owner.is_a? Module
43
+
44
+ "#{formatted_owner}#{yellow(singleton ? '.' : '#')}#{yellow object.name.to_s}"
45
+ end
46
+
47
+ def trimmed_source
48
+ indent = object.source.lines.map { |line| line =~ /[^ ]/ }.min
49
+ object.source.lines.map { |line| line[indent..-1] }.join.chomp
50
+ end
51
+ end
52
+ end
53
+ end
@@ -2,22 +2,34 @@
2
2
 
3
3
  module Helium
4
4
  class Console
5
- define_formatter_for Module do
6
- def call
7
- light_yellow(object.name || anonymous_text)
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
- "(anonymous #{signature})"
31
+
32
+ "#{light_yellow '('}#{signature})#{light_yellow ')'}"
21
33
  end
22
34
  end
23
35
  end
@@ -3,7 +3,7 @@
3
3
  module Helium
4
4
  class Console
5
5
  define_formatter_for NilClass do
6
- def call
6
+ def render_compact
7
7
  light_black('nil')
8
8
  end
9
9
  end
@@ -3,7 +3,7 @@
3
3
  module Helium
4
4
  class Console
5
5
  define_formatter_for Numeric do
6
- def call
6
+ def render_compact
7
7
  light_cyan(object.to_s)
8
8
  end
9
9
  end
@@ -3,28 +3,17 @@
3
3
  module Helium
4
4
  class Console
5
5
  define_formatter_for Object do
6
- def call
7
- return inline_with_truncation if force_inline?
6
+ def optimal_format
7
+ return [:compact, {}] if object.instance_variables.none?
8
8
 
9
- format_as_table
9
+ super
10
10
  end
11
11
 
12
- private
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
- yield_lines do |y|
22
- y << "#{light_black '#'} #{class_name}"
23
- format(table).lines.each {|line| y << line }
24
- end
12
+ def render_compact
13
+ "#{format object.class, :compact}#{light_black "##{object.object_id}"}"
25
14
  end
26
15
 
27
- def inline_with_truncation
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,14 +27,22 @@ module Helium
38
27
  [class_name, formatted_vars].compact.join
39
28
  end
40
29
 
41
- def force_inline?
42
- level > 2
43
- end
44
30
 
45
- def all_symbol?
46
- object.keys.all? { |key| key.is_a? Symbol }
31
+ def render_partial
32
+ table = Table.new(runner: light_black('| '), after_key: light_black(': '), format_keys: false)
33
+
34
+ object.instance_variables.each do |inst|
35
+ table.row(magenta(inst.to_s), object.instance_variable_get(inst))
36
+ end
37
+
38
+ yield_lines do |y|
39
+ y << "#{light_black '#'} #{class_name}"
40
+ format(table).lines.each { |line| y << line }
41
+ end
47
42
  end
48
43
 
44
+ private
45
+
49
46
  def formatted_instance_variables(**options)
50
47
  object.instance_variables.sort.each.lazy.map do |var_name|
51
48
  value = object.instance_variable_get(var_name)
@@ -54,7 +51,7 @@ module Helium
54
51
  end
55
52
 
56
53
  def class_name(short: false)
57
- formatted = format(object.class, short: short)
54
+ formatted = format(object.class, :compact)
58
55
  short ? "##{formatted}" : "#{formatted} instance"
59
56
  end
60
57
  end
@@ -3,8 +3,8 @@
3
3
  module Helium
4
4
  class Console
5
5
  define_formatter_for 'Pathname' do
6
- def call
7
- "#{format(Pathname, short: true)}: #{yellow(object.to_s)}"
6
+ def render_compact
7
+ "#{format(Pathname, :compact)}: #{yellow(object.to_s)}"
8
8
  end
9
9
  end
10
10
  end
@@ -3,9 +3,15 @@
3
3
  module Helium
4
4
  class Console
5
5
  define_formatter_for Set do
6
- def call
6
+ def render_compact
7
+ return rendr_empty if object.none?
8
+
9
+ "#{light_magenta('Set:')} #{trunc_message(object.count, all_truncated: true)}"
10
+ end
11
+
12
+ def render_partial
7
13
  return "#{light_magenta('Set:')} #{red 'empty'}" if object.none?
8
- return inline_with_truncation if force_inline?
14
+ return inline_with_truncation if options[:max_lines] == 1
9
15
 
10
16
  inline_without_truncation || format_as_table
11
17
  end
@@ -16,17 +22,21 @@ module Helium
16
22
 
17
23
  private
18
24
 
25
+ def render_empty
26
+ "#{light_magenta('Set:')} #{red 'empty'}" if object.none?
27
+ end
28
+
19
29
  def format_as_table
20
30
  table = Table.new(runner: '', format_keys: false)
21
31
  object.each do |element|
22
- table.row(light_magenta('-'), element)
32
+ table.row(light_black('-'), element)
23
33
  end
24
34
 
25
- [
26
- light_magenta('Set: {'),
27
- format(table),
28
- light_magenta('}')
29
- ].join("\n")
35
+ yield_lines do |y|
36
+ y << light_magenta('Set: {')
37
+ format(table).lines.each { |line| y << line }
38
+ y << light_magenta('}')
39
+ end
30
40
  end
31
41
 
32
42
  def inline_with_truncation
@@ -59,7 +69,8 @@ module Helium
59
69
  end
60
70
 
61
71
  def formatted_elements(**options)
62
- object.sort.each.lazy.map { |element| format_nested(element, **options) }
72
+ sorted = object.sort rescue object
73
+ sorted.each.lazy.map { |element| format_nested(element, **options) }
63
74
  end
64
75
 
65
76
  def trunc_message(count, all_truncated: false)
@@ -71,10 +82,6 @@ module Helium
71
82
  def object_size
72
83
  @object_size ||= object.size
73
84
  end
74
-
75
- def force_inline?
76
- level > 2
77
- end
78
85
  end
79
86
  end
80
87
  end
@@ -3,26 +3,46 @@
3
3
  module Helium
4
4
  class Console
5
5
  define_formatter_for String do
6
- def call
7
- formatted = Helium::Console.format_string(
8
- object.dump.gsub('\n', "\n"),
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
- case level
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
@@ -3,7 +3,7 @@
3
3
  module Helium
4
4
  class Console
5
5
  define_formatter_for Symbol do
6
- def call
6
+ def render_compact
7
7
  light_blue(":#{object}")
8
8
  end
9
9
  end
@@ -5,8 +5,8 @@ module Helium
5
5
  define_formatter_for Table do
6
6
  def call
7
7
  yield_lines do |y|
8
- rows.each do |key, value, options = {}|
9
- format_pair(key, value, **options) do |line|
8
+ rows.each do |key, value, style, options = {}|
9
+ format_pair(key, value, style, **options) do |line|
10
10
  y << line
11
11
  end
12
12
  end
@@ -16,8 +16,8 @@ module Helium
16
16
 
17
17
  private
18
18
 
19
- def format_pair(key, value, **options)
20
- formatted_value = format_nested(value, max_width: max_value_width, **options)
19
+ def format_pair(key, value, style, **options)
20
+ formatted_value = format_nested(value, style, max_width: max_value_width, **options)
21
21
 
22
22
  formatted_value.lines.each.with_index.map do |line, index|
23
23
  yield [
@@ -3,9 +3,13 @@
3
3
  module Helium
4
4
  class Console
5
5
  define_formatter_for Time do
6
- def call
6
+ def render_inline
7
7
  blue object.strftime('%A, %d %b %Y, %H:%M:%S')
8
8
  end
9
+
10
+ def render_compact
11
+ blue object.strftime('%d/%m/%Y, %H:%M')
12
+ end
9
13
  end
10
14
  end
11
15
  end
@@ -1,100 +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
- class Element
9
- class LazyStringEvaluator
10
- def initialize(&block)
11
- @lines = Enumerator.new { |y| block.(y) }
12
- end
13
-
14
- attr_reader :lines
15
-
16
- def to_s
17
- lines.to_a.join
18
- end
19
- end
20
-
21
- def initialize(object, **options)
22
- @object = object
23
- @options = options
24
- end
25
-
26
- def call
27
- end
28
-
29
- attr_reader :object, :options
30
-
31
- def format_nested(other_object, **options)
32
- Helium::Console.format(other_object, **nested_opts(options))
33
- end
34
-
35
- def format(other_object, **options)
36
- Helium::Console.format(other_object, **nested_opts(options, increase_level: false))
37
- end
38
-
39
- def format_string(string, **options)
40
- Helium::Console.format_string(string, **options)
41
- end
42
-
43
- def simple?
44
- false
45
- end
46
-
47
- def method_missing(name, *args)
48
- return @options[name] if @options.key?(name)
49
- return ColorizedString.new(*args).colorize(name) if ColorizedString.colors.include?(name)
50
-
51
- super
52
- end
53
-
54
- def respond_to_missing?(name, private = false)
55
- @options.key?(name) || ColorizedString.colors.include?(name) || super
56
- end
57
-
58
- private
59
-
60
- def nested_objects
61
- []
62
- end
63
-
64
- def nested_opts(new_options, increase_level: true)
65
- new_options = options.merge(new_options)
66
- new_options[:level] += 1 if increase_level
67
- new_options[:ignore_objects] = nested_objects
68
- new_options
69
- end
70
-
71
- def length_of(string)
72
- ColorizedString.new(string).uncolorize.length
73
- end
9
+ def self.instance_formatters
10
+ @instance_formatters ||= new
11
+ end
74
12
 
75
- def yield_lines(&block)
76
- LazyStringEvaluator.new(&block)
77
- end
13
+ def self.class_formatters
14
+ @class_formatters ||= new
78
15
  end
79
16
 
80
- def add(klass, &handler)
81
- define(klass) do
82
- define_method(:call, &handler)
83
- end
17
+ def add(mod, formatter)
18
+ handlers[mod] = formatter
84
19
  end
85
20
 
86
- def define(klass, &block)
87
- handlers[klass] = Class.new(Element, &block)
21
+ def define(mod, &block)
22
+ add(mod, Class.new(Formatter, &block))
88
23
  end
89
24
 
90
- def handler_for(object, **options)
91
- element_class = object.class.ancestors.find do |ancestor|
92
- break handlers[ancestor] if handlers.key?(ancestor)
93
- break handlers[ancestor.name] if handlers.key?(ancestor.name)
25
+ def handler_for(klass)
26
+ klass.ancestors.each do |ancestor|
27
+ result = handlers[ancestor] || handlers[ancestor.name]
28
+ return result if result
94
29
  end
95
- return unless element_class
96
-
97
- element_class.new(object, **options)
30
+ handlers[BasicObject]
98
31
  end
99
32
 
100
33
  private
@@ -11,8 +11,8 @@ module Helium
11
11
 
12
12
  attr_reader :runner, :after_key, :format_keys
13
13
 
14
- def row(key, value, **options)
15
- rows << [key, value, options]
14
+ def row(key, value, style = nil, **options)
15
+ rows << [key, value, style, options]
16
16
  end
17
17
 
18
18
  def rows
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Helium
4
4
  class Console
5
- VERSION = '0.1.11'
5
+ VERSION = '0.1.12'
6
6
  end
7
7
  end
@@ -10,6 +10,7 @@ require 'helium/console/table'
10
10
  require 'helium/console/registry'
11
11
 
12
12
  require 'helium/console/printer'
13
+ require 'helium/console/prompt'
13
14
 
14
15
  module Helium
15
16
  class Console
@@ -23,9 +24,30 @@ module Helium
23
24
  Symbol
24
25
  ].freeze
25
26
 
27
+ def self.start(target = nil, options = {})
28
+ prompt = ColorizedString.new("He\u269B").light_blue
29
+ line = 0
30
+
31
+ options = {
32
+ print: ColorPrinter.method(:default),
33
+ prompt: Prompt.new.pry_prompt
34
+ }.merge(options)
35
+
36
+ Pry.start(target, options)
37
+ end
38
+
39
+ def self.define_formatter_for(klass, &handler)
40
+ Registry.instance_formatters.define(klass, &handler)
41
+ end
42
+
43
+ def self.define_class_formatter_for(klass, &handler)
44
+ Registry.class_formatters.define(klass, &handler)
45
+ end
46
+
47
+
26
48
  class << self
27
49
  def instance
28
- @instance ||= new(registry: Registry.new)
50
+ @instance ||= new
29
51
  end
30
52
 
31
53
  def method_missing(name, *args, &block)
@@ -39,51 +61,31 @@ module Helium
39
61
  end
40
62
  end
41
63
 
42
- def initialize(registry:)
43
- @registry = registry
44
- end
45
-
46
- def format(object, **options)
64
+ def format(object, style = nil, **options)
47
65
  options = default_options.merge(options)
48
66
  return '(...)' if options[:ignore_objects].include?(object.object_id)
49
67
 
50
- handler = registry.handler_for(object, **options)
51
-
52
- if handler
53
- handler.()
54
- else
55
- format(object.inspect, **options)
56
- end
57
- end
58
-
59
- def register(klass, &handler)
60
- registry.add(klass, &handler)
61
- end
62
-
63
- def define_formatter_for(klass, &handler)
64
- registry.define(klass, &handler)
68
+ handler_for(object, style, **options).()
65
69
  end
66
70
 
67
- def simple?(object)
71
+ def simple?(object, style = nil, **options)
68
72
  SIMPLE_OBJECTS.any? { |simple_obj_class| object.is_a? simple_obj_class } ||
69
- registry.handler_for(object).simple?
73
+ handler_for(object, style, **options).simple?
70
74
  end
71
75
 
72
76
  def default_options
73
77
  {
74
78
  overflow: :wrap,
75
79
  indent: 0,
76
- max_width: `tput cols`.chomp.to_i,
77
80
  level: 1,
78
- ignore_objects: []
81
+ ignore_objects: [],
82
+ short: false
79
83
  }
80
84
  end
81
85
 
82
86
  def format_string(string, ellipses: '...', **options)
83
87
  options = default_options.merge(options)
84
-
85
88
  formatters = [
86
- Formatters::Overflow.get(options[:overflow]).new(max_width: options[:max_width] - options[:indent]),
87
89
  Formatters::Indent.new(options[:indent]),
88
90
  Formatters::MaxLines.new(
89
91
  max_lines: options[:max_lines],
@@ -91,6 +93,11 @@ module Helium
91
93
  ellipses: ellipses
92
94
  )
93
95
  ]
96
+ if options[:max_width]
97
+ formatters.unshift(
98
+ Formatters::Overflow.get(options[:overflow]).new(max_width: options[:max_width] - options[:indent]),
99
+ )
100
+ end
94
101
 
95
102
  formatters.inject(string) do |str, formatter|
96
103
  formatter.(str)
@@ -99,7 +106,15 @@ module Helium
99
106
 
100
107
  private
101
108
 
102
- attr_reader :registry
109
+ # TODO: Injection instead of hard dependency!
110
+ def handler_for(object, style, **options)
111
+ formatter_class = if object.is_a? Module
112
+ Registry.class_formatters.handler_for(object)
113
+ else
114
+ Registry.instance_formatters.handler_for(object.class)
115
+ end
116
+ formatter_class&.new(object, style, self, **options)
117
+ end
103
118
  end
104
119
  end
105
120
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: helium-console
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.11
4
+ version: 0.1.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stanislaw Klajn
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-03 00:00:00.000000000 Z
11
+ date: 2021-10-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -59,16 +59,20 @@ files:
59
59
  - bin/setup
60
60
  - helium-console.gemspec
61
61
  - lib/helium/console.rb
62
+ - lib/helium/console/colorized_string.rb
63
+ - lib/helium/console/formatter.rb
62
64
  - lib/helium/console/formatters/indent.rb
63
65
  - lib/helium/console/formatters/max_lines.rb
64
66
  - lib/helium/console/formatters/overflow.rb
65
67
  - lib/helium/console/formatters/overflow/wrap.rb
66
68
  - lib/helium/console/printer.rb
69
+ - lib/helium/console/prompt.rb
67
70
  - lib/helium/console/registry.rb
68
71
  - lib/helium/console/registry/array.rb
69
72
  - lib/helium/console/registry/booleans.rb
70
73
  - lib/helium/console/registry/date.rb
71
74
  - lib/helium/console/registry/hash.rb
75
+ - lib/helium/console/registry/method.rb
72
76
  - lib/helium/console/registry/module.rb
73
77
  - lib/helium/console/registry/nil.rb
74
78
  - lib/helium/console/registry/numeric.rb
@@ -102,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
102
106
  - !ruby/object:Gem::Version
103
107
  version: '0'
104
108
  requirements: []
105
- rubygems_version: 3.1.4
109
+ rubygems_version: 3.0.8
106
110
  signing_key:
107
111
  specification_version: 4
108
112
  summary: Collection of tools for smooth integration with console