helium-console 0.1.11 → 0.1.12

Sign up to get free protection for your applications and to get access to all the features.
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