output_mode 1.3.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +7 -0
- data/bin/bundle +114 -0
- data/bin/coderay +29 -0
- data/bin/demo +29 -2
- data/bin/htmldiff +29 -0
- data/bin/ldiff +29 -0
- data/bin/pry +29 -0
- data/bin/rake +29 -0
- data/bin/rspec +29 -0
- data/lib/output_mode/builder_dsl.rb +3 -1
- data/lib/output_mode/callable.rb +85 -7
- data/lib/output_mode/default_erb.rb +23 -1
- data/lib/output_mode/non_interactive_erb.rb +41 -0
- data/lib/output_mode/output.rb +16 -52
- data/lib/output_mode/outputs/delimited.rb +6 -1
- data/lib/output_mode/outputs/tabulated.rb +18 -16
- data/lib/output_mode/outputs/templated.rb +15 -18
- data/lib/output_mode/tldr/index.rb +34 -10
- data/lib/output_mode/tldr/show.rb +47 -23
- data/lib/output_mode/version.rb +1 -1
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e4d5f1fa1744eeff5535f33a65593b370d317124736089a8b24e2d76cb824b6e
|
4
|
+
data.tar.gz: 10e77ade81138ebe9c6ca3e6b3299ba864c213603e54682eebb611057f72e2d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a754089932ba840c19e0070b03e99e10fd4a957e4204ee08806dde91d54d51899950f817b8a34d3736f6c1fa9df4f85321fd938909c381f12230fe53df312ed1
|
7
|
+
data.tar.gz: 7d5858053e4d55868893bbfa2c13ed63a52bd39f05f6b4ae690a29072c0ab7f7a4d9919204c6fd387dc2bd0ad19efec2fa5e0d023e22929452d2efa616cdf6d6
|
data/Gemfile
CHANGED
@@ -28,3 +28,10 @@ source "https://rubygems.org"
|
|
28
28
|
|
29
29
|
# Specify your gem's dependencies in output_mode.gemspec
|
30
30
|
gemspec
|
31
|
+
|
32
|
+
# NOTE: Checks out the openflight version of tty-table with the 'rotate' flag
|
33
|
+
# fix. This should eventually become part of the mainline version of TTY::Table
|
34
|
+
#
|
35
|
+
# This is intentionally not part of the gemspec so older versions of TTY::Table
|
36
|
+
# can still be used
|
37
|
+
gem 'tty-table', github: 'openflighthpc/tty-table', branch: '9b326fcbe04968463da58c000fbb1dd5ce178243'
|
data/bin/bundle
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'bundle' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "rubygems"
|
12
|
+
|
13
|
+
m = Module.new do
|
14
|
+
module_function
|
15
|
+
|
16
|
+
def invoked_as_script?
|
17
|
+
File.expand_path($0) == File.expand_path(__FILE__)
|
18
|
+
end
|
19
|
+
|
20
|
+
def env_var_version
|
21
|
+
ENV["BUNDLER_VERSION"]
|
22
|
+
end
|
23
|
+
|
24
|
+
def cli_arg_version
|
25
|
+
return unless invoked_as_script? # don't want to hijack other binstubs
|
26
|
+
return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
|
27
|
+
bundler_version = nil
|
28
|
+
update_index = nil
|
29
|
+
ARGV.each_with_index do |a, i|
|
30
|
+
if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
|
31
|
+
bundler_version = a
|
32
|
+
end
|
33
|
+
next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
|
34
|
+
bundler_version = $1
|
35
|
+
update_index = i
|
36
|
+
end
|
37
|
+
bundler_version
|
38
|
+
end
|
39
|
+
|
40
|
+
def gemfile
|
41
|
+
gemfile = ENV["BUNDLE_GEMFILE"]
|
42
|
+
return gemfile if gemfile && !gemfile.empty?
|
43
|
+
|
44
|
+
File.expand_path("../../Gemfile", __FILE__)
|
45
|
+
end
|
46
|
+
|
47
|
+
def lockfile
|
48
|
+
lockfile =
|
49
|
+
case File.basename(gemfile)
|
50
|
+
when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
|
51
|
+
else "#{gemfile}.lock"
|
52
|
+
end
|
53
|
+
File.expand_path(lockfile)
|
54
|
+
end
|
55
|
+
|
56
|
+
def lockfile_version
|
57
|
+
return unless File.file?(lockfile)
|
58
|
+
lockfile_contents = File.read(lockfile)
|
59
|
+
return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
|
60
|
+
Regexp.last_match(1)
|
61
|
+
end
|
62
|
+
|
63
|
+
def bundler_version
|
64
|
+
@bundler_version ||=
|
65
|
+
env_var_version || cli_arg_version ||
|
66
|
+
lockfile_version
|
67
|
+
end
|
68
|
+
|
69
|
+
def bundler_requirement
|
70
|
+
return "#{Gem::Requirement.default}.a" unless bundler_version
|
71
|
+
|
72
|
+
bundler_gem_version = Gem::Version.new(bundler_version)
|
73
|
+
|
74
|
+
requirement = bundler_gem_version.approximate_recommendation
|
75
|
+
|
76
|
+
return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0")
|
77
|
+
|
78
|
+
requirement += ".a" if bundler_gem_version.prerelease?
|
79
|
+
|
80
|
+
requirement
|
81
|
+
end
|
82
|
+
|
83
|
+
def load_bundler!
|
84
|
+
ENV["BUNDLE_GEMFILE"] ||= gemfile
|
85
|
+
|
86
|
+
activate_bundler
|
87
|
+
end
|
88
|
+
|
89
|
+
def activate_bundler
|
90
|
+
gem_error = activation_error_handling do
|
91
|
+
gem "bundler", bundler_requirement
|
92
|
+
end
|
93
|
+
return if gem_error.nil?
|
94
|
+
require_error = activation_error_handling do
|
95
|
+
require "bundler/version"
|
96
|
+
end
|
97
|
+
return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
|
98
|
+
warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
|
99
|
+
exit 42
|
100
|
+
end
|
101
|
+
|
102
|
+
def activation_error_handling
|
103
|
+
yield
|
104
|
+
nil
|
105
|
+
rescue StandardError, LoadError => e
|
106
|
+
e
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
m.load_bundler!
|
111
|
+
|
112
|
+
if m.invoked_as_script?
|
113
|
+
load Gem.bin_path("bundler", "bundle")
|
114
|
+
end
|
data/bin/coderay
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'coderay' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("coderay", "coderay")
|
data/bin/demo
CHANGED
@@ -36,9 +36,22 @@ module DemoIndex
|
|
36
36
|
register_callable(header: 'Standard', header_color: [:strikethrough] ) { 'always visible' }
|
37
37
|
register_callable(header: 'Verbose', verbose: true) { 'verbose visible' }
|
38
38
|
register_callable(header: 'Simplified', verbose: false) { 'simplified visible' }
|
39
|
+
register_callable(header: 'Interactive', interactive: true) { 'interactive visible' }
|
40
|
+
register_callable(header: 'Non Interactive', interactive: false) { 'non-interactive visible' }
|
39
41
|
register_callable(header: 'Yes/True') { true }
|
40
42
|
register_callable(header: 'No/False', row_color: [:clear]) { false }
|
41
43
|
register_callable(header: 'Missing') { nil }
|
44
|
+
register_callable(header: 'Inline') do |interactive:, verbose:|
|
45
|
+
if interactive && verbose
|
46
|
+
'interactive-verbose'
|
47
|
+
elsif interactive
|
48
|
+
'interactive-simplified'
|
49
|
+
elsif verbose
|
50
|
+
'non-interactive-verbose'
|
51
|
+
else
|
52
|
+
'non-interactive-simplified'
|
53
|
+
end
|
54
|
+
end
|
42
55
|
end
|
43
56
|
|
44
57
|
module DemoShow
|
@@ -48,9 +61,13 @@ module DemoShow
|
|
48
61
|
register_callable(header: 'Standard') { 'always visible' }
|
49
62
|
register_callable(header: 'Verbose', verbose: true) { 'verbose visible' }
|
50
63
|
register_callable(header: 'Simplified', verbose: false) { 'simplified visible' }
|
64
|
+
register_callable(header: 'Interactive', interactive: true) { 'interactive visible' }
|
65
|
+
register_callable(header: 'Non Interactive', interactive: false) { 'non-interactive visible' }
|
51
66
|
register_callable(header: 'Yes/True', section: :boolean) { true }
|
52
67
|
register_callable(header: 'No/False', section: :boolean) { false }
|
53
68
|
register_callable(header: 'Missing') { nil }
|
69
|
+
register_callable(header: 'Tab') { "tab1\ttab2" }
|
70
|
+
register_callable(header: 'New line') { "line1\nline2" }
|
54
71
|
end
|
55
72
|
|
56
73
|
data = [1, 2, 3]
|
@@ -74,6 +91,12 @@ puts <<~EOF
|
|
74
91
|
#==============================================================================
|
75
92
|
#==============================================================================
|
76
93
|
|
94
|
+
#==============================================================================
|
95
|
+
# Default Demo Index
|
96
|
+
# Simplified in interactive shells, verbose in non-interactive
|
97
|
+
#==============================================================================
|
98
|
+
#{DemoIndex.build_output.render(*data)}
|
99
|
+
|
77
100
|
#==============================================================================
|
78
101
|
# Demo Verbose Index
|
79
102
|
#==============================================================================
|
@@ -81,7 +104,6 @@ puts <<~EOF
|
|
81
104
|
|
82
105
|
#==============================================================================
|
83
106
|
# Demo "Simplified" Index
|
84
|
-
# NOTE: Disabled for non-interactive shell, shows the verbose output instead
|
85
107
|
#==============================================================================
|
86
108
|
#{DemoIndex.build_output(verbose: false).render(*data)}
|
87
109
|
|
@@ -108,6 +130,12 @@ puts <<~EOF
|
|
108
130
|
#==============================================================================
|
109
131
|
#==============================================================================
|
110
132
|
|
133
|
+
#==============================================================================
|
134
|
+
# Default Settings
|
135
|
+
# Simplified in interactive shells, verbose in non-interactive
|
136
|
+
#==============================================================================
|
137
|
+
#{DemoShow.build_output.render(*data)}
|
138
|
+
|
111
139
|
#==============================================================================
|
112
140
|
# Demo Verbose Show
|
113
141
|
#==============================================================================
|
@@ -115,7 +143,6 @@ puts <<~EOF
|
|
115
143
|
|
116
144
|
#==============================================================================
|
117
145
|
# Demo "Simplified" Show
|
118
|
-
# NOTE: Disabled for non-interactive shell, shows the verbose output instead
|
119
146
|
#==============================================================================
|
120
147
|
#{DemoShow.build_output(verbose: false).render(*data)}
|
121
148
|
|
data/bin/htmldiff
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'htmldiff' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("diff-lcs", "htmldiff")
|
data/bin/ldiff
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'ldiff' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("diff-lcs", "ldiff")
|
data/bin/pry
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'pry' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("pry", "pry")
|
data/bin/rake
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rake' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rake", "rake")
|
data/bin/rspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rspec' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rspec-core", "rspec")
|
@@ -36,7 +36,9 @@ module OutputMode
|
|
36
36
|
# @param config Directly provided to {OutputMode::Callable#initialize}
|
37
37
|
# @yield Directly provided to {OutputMode::Callable#initialize}
|
38
38
|
def register_callable(**config, &b)
|
39
|
-
|
39
|
+
Callable.new(**config, &b).tap do |c|
|
40
|
+
output_callables << c
|
41
|
+
end
|
40
42
|
end
|
41
43
|
|
42
44
|
# Provides the base method signature
|
data/lib/output_mode/callable.rb
CHANGED
@@ -26,16 +26,19 @@
|
|
26
26
|
|
27
27
|
module OutputMode
|
28
28
|
# Internal array like object that will convert procs to Callable
|
29
|
-
class Callables
|
29
|
+
class Callables
|
30
|
+
include Enumerable
|
31
|
+
|
30
32
|
# @api private
|
31
33
|
def initialize(callables = nil)
|
34
|
+
@callables = []
|
32
35
|
case callables
|
33
|
-
when Array
|
34
|
-
|
35
|
-
callables.
|
36
|
+
when Array, Callables
|
37
|
+
callables.each do |c|
|
38
|
+
@callables << (c.is_a?(Callable) ? c : Callable.new(&c))
|
36
39
|
end
|
37
40
|
when nil
|
38
|
-
|
41
|
+
# NOOP
|
39
42
|
else
|
40
43
|
raise "Can not convert #{callables.class} into a #{self.class}"
|
41
44
|
end
|
@@ -43,13 +46,65 @@ module OutputMode
|
|
43
46
|
|
44
47
|
def <<(item)
|
45
48
|
if item.is_a? Callable
|
46
|
-
|
49
|
+
@callables << item
|
47
50
|
elsif item.respond_to?(:call)
|
48
|
-
|
51
|
+
@callables << Callable.new(&item)
|
49
52
|
else
|
50
53
|
raise Error, "#{item.class} is not callable"
|
51
54
|
end
|
52
55
|
end
|
56
|
+
|
57
|
+
def each(&block)
|
58
|
+
@callables.each(&block)
|
59
|
+
end
|
60
|
+
|
61
|
+
def pad_each(*ctx, **input_opts)
|
62
|
+
fields = self.map do |callables|
|
63
|
+
field = callables.config[:header]
|
64
|
+
if field.respond_to?(:call)
|
65
|
+
opts = if field.parameters.include?(:keyrest)
|
66
|
+
input_opts.dup
|
67
|
+
else
|
68
|
+
keys = field.parameters
|
69
|
+
.select { |type, _| [:key, :keyreq].include?(type) }
|
70
|
+
.map { |_, k| k }
|
71
|
+
input_opts.slice(*keys)
|
72
|
+
end
|
73
|
+
opts.empty? ? field.call(*ctx) : field.call(*ctx, **opts)
|
74
|
+
else
|
75
|
+
field
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
max_length = fields.map { |f| f.to_s.length }.max
|
80
|
+
pads = self.each_with_index.map do |callable, idx|
|
81
|
+
field = fields[idx]
|
82
|
+
length = max_length - field.to_s.length
|
83
|
+
[callable, { padding: ' ' * length, field: field }]
|
84
|
+
end
|
85
|
+
|
86
|
+
if block_given?
|
87
|
+
pads.each { |c, opts| yield(c, **opts) }
|
88
|
+
else
|
89
|
+
pads.each
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def config_select(key, *values)
|
94
|
+
selected = self.select do |callable|
|
95
|
+
conf = callable.config[key]
|
96
|
+
if conf.is_a? Array
|
97
|
+
!(conf & values).empty?
|
98
|
+
else
|
99
|
+
values.include?(conf)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
Callables.new(selected)
|
103
|
+
end
|
104
|
+
|
105
|
+
def length
|
106
|
+
@callables.length
|
107
|
+
end
|
53
108
|
end
|
54
109
|
|
55
110
|
class Callable
|
@@ -141,6 +196,29 @@ module OutputMode
|
|
141
196
|
def call(*a)
|
142
197
|
callable.call(*a)
|
143
198
|
end
|
199
|
+
|
200
|
+
def generator(output)
|
201
|
+
->(*a) do
|
202
|
+
# Implicitly determine which parts of the context can be passed through
|
203
|
+
ctx = if callable.parameters.any? { |type, _| type == :keyrest }
|
204
|
+
output.context
|
205
|
+
else
|
206
|
+
keys = callable.parameters.select { |type, _| [:key, :keyreq].include?(type) }
|
207
|
+
.map { |_, k| k }
|
208
|
+
output.context.slice(*keys)
|
209
|
+
end
|
210
|
+
raw = call(*a, **ctx)
|
211
|
+
if raw == true
|
212
|
+
config[:yes] || output.yes
|
213
|
+
elsif raw == false
|
214
|
+
config[:no] || output.no
|
215
|
+
elsif [nil, ''].include?(raw)
|
216
|
+
config[:default] || output.default
|
217
|
+
else
|
218
|
+
raw
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
144
222
|
end
|
145
223
|
end
|
146
224
|
|
@@ -1,5 +1,27 @@
|
|
1
1
|
#==============================================================================
|
2
|
-
#
|
2
|
+
# Copyright 2021 William McCumstie
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice,
|
8
|
+
# this list of conditions and the following disclaimer.
|
9
|
+
#
|
10
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
#
|
14
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
15
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
16
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
17
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
18
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
19
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
20
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
21
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
22
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
23
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
24
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
3
25
|
#==============================================================================
|
4
26
|
|
5
27
|
require 'erb'
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#==============================================================================
|
2
|
+
# Copyright 2021 William McCumstie
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are met:
|
6
|
+
#
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice,
|
8
|
+
# this list of conditions and the following disclaimer.
|
9
|
+
#
|
10
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
#
|
14
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
15
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
16
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
17
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
18
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
19
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
20
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
21
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
22
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
23
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
24
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
25
|
+
#==============================================================================
|
26
|
+
|
27
|
+
require 'erb'
|
28
|
+
|
29
|
+
module OutputMode
|
30
|
+
NON_INTERACTIVE_ERB = ERB.new(<<~TEMPLATE, nil, '-')
|
31
|
+
<% each do |value, field:, padding:, **_| -%>
|
32
|
+
<% if value.nil? && field.nil? -%>
|
33
|
+
\t
|
34
|
+
<% elsif field.nil? -%>
|
35
|
+
\t<%= value %>
|
36
|
+
<% else -%>
|
37
|
+
<%= field -%>\t<%= value.to_s.dump[1...-1] %>
|
38
|
+
<% end -%>
|
39
|
+
<% end -%>
|
40
|
+
TEMPLATE
|
41
|
+
end
|
data/lib/output_mode/output.rb
CHANGED
@@ -36,45 +36,41 @@ module OutputMode
|
|
36
36
|
# @!attribute [r] config
|
37
37
|
# @return [Hash] additional key-values to modify the render
|
38
38
|
# @!attribute [r] default
|
39
|
-
# @return either a static default
|
39
|
+
# @return either a static default
|
40
40
|
# @!attribute [r] yes
|
41
|
-
# @return either a static yes value
|
41
|
+
# @return either a static yes value
|
42
42
|
# @!attribute [r] no
|
43
|
-
# @return either a static no value
|
44
|
-
|
43
|
+
# @return either a static no value
|
44
|
+
# @!attribute [r] context
|
45
|
+
# @return a hash of keys to be provided to the callables
|
46
|
+
attr_reader :procs, :config, :yes, :no, :default, :context
|
45
47
|
|
46
48
|
# Creates a new outputting instance from an array of procs
|
47
49
|
#
|
48
50
|
# @param *procs [Array<#call>] an array of procs (or callable objects)
|
49
51
|
# @param default: [String] replaces _blanks_ with a static string
|
50
|
-
# @param default: [Array] replace _blanks_ on a per column basis. The last value is repeated if the +procs+ are longer.
|
51
52
|
# @param yes: [String] replaces +true+ with a static string
|
52
|
-
# @param yes: [Array] replaces +true+ on a per column basis. The last value is repeated if the +procs+ are longer.
|
53
53
|
# @param no: [String] replaces +false+ with a static string
|
54
|
-
# @param
|
54
|
+
# @param context: [Hash] of keys to be provided to the callables
|
55
55
|
# @param **config [Hash] a hash of additional keys to be stored
|
56
|
-
def initialize(*procs, default: nil, yes: 'true', no: 'false', **config)
|
57
|
-
@procs = procs
|
56
|
+
def initialize(*procs, default: nil, yes: 'true', no: 'false', context: {}, **config)
|
57
|
+
@procs = Callables.new(procs)
|
58
58
|
@config = config
|
59
59
|
@yes = yes
|
60
60
|
@no = no
|
61
61
|
@default = default
|
62
|
+
@context = context
|
63
|
+
end
|
64
|
+
|
65
|
+
def callables
|
66
|
+
procs
|
62
67
|
end
|
63
68
|
|
64
69
|
# Returns the results of the +procs+ for a particular +object+. It will apply the
|
65
70
|
# +default+, +yes+, and +no+ values.
|
66
71
|
def generate(object)
|
67
|
-
procs.
|
68
|
-
|
69
|
-
if raw == true
|
70
|
-
index_selector(:yes, idx)
|
71
|
-
elsif raw == false
|
72
|
-
index_selector(:no, idx)
|
73
|
-
elsif !default.nil? && (raw.nil? || raw == '')
|
74
|
-
index_selector(:default, idx)
|
75
|
-
else
|
76
|
-
raw
|
77
|
-
end
|
72
|
+
procs.map do |callable|
|
73
|
+
callable.generator(self).call(object)
|
78
74
|
end
|
79
75
|
end
|
80
76
|
|
@@ -91,37 +87,5 @@ module OutputMode
|
|
91
87
|
def render(*data)
|
92
88
|
raise NotImplementedError
|
93
89
|
end
|
94
|
-
|
95
|
-
# A helper method for selecting elements from a source array or return
|
96
|
-
# a static value.
|
97
|
-
#
|
98
|
-
# @param [Symbol] method The source method on the +output+
|
99
|
-
# @param [Integer] index The index to lookup
|
100
|
-
#
|
101
|
-
# @overload index_selector(array_method, valid_index)
|
102
|
-
# @param array_method A method that returns an array
|
103
|
-
# @param valid_index An index that is less than the array's length
|
104
|
-
# @return the value at the index
|
105
|
-
#
|
106
|
-
# @overload index_selector(array_method, out_of_bounds)
|
107
|
-
# @param array_method A method that returns an array
|
108
|
-
# @param out_of_bounds An index greater than the maximum array length
|
109
|
-
# @return the last element of the array
|
110
|
-
#
|
111
|
-
# @overload index_selector(non_array_method, _)
|
112
|
-
# @param non_array_method A method that does not return an array
|
113
|
-
# @param _ The index is ignored
|
114
|
-
# @return the result of the non_array_method
|
115
|
-
def index_selector(method, index)
|
116
|
-
source = public_send(method)
|
117
|
-
is_array = source.is_a? Array
|
118
|
-
if is_array && source.length > index
|
119
|
-
source[index]
|
120
|
-
elsif is_array
|
121
|
-
source.last
|
122
|
-
else
|
123
|
-
source
|
124
|
-
end
|
125
|
-
end
|
126
90
|
end
|
127
91
|
end
|
@@ -40,7 +40,12 @@ module OutputMode
|
|
40
40
|
def render(*data)
|
41
41
|
io = StringIO.new
|
42
42
|
csv = CSV.new(io, **config)
|
43
|
-
data.each
|
43
|
+
data.each do |datum|
|
44
|
+
csv << generate(datum).map do |value|
|
45
|
+
next nil if value.nil?
|
46
|
+
value.to_s.dump[1...-1]
|
47
|
+
end
|
48
|
+
end
|
44
49
|
io.tap(&:rewind).read
|
45
50
|
end
|
46
51
|
end
|
@@ -31,8 +31,6 @@ module OutputMode
|
|
31
31
|
class Tabulated < Output
|
32
32
|
# @!attribute [r] renderer
|
33
33
|
# @return [Symbol] the renderer type, see: https://github.com/piotrmurach/tty-table#32-renderer
|
34
|
-
# @!attribute [r] header
|
35
|
-
# @return [Array] An optional header row for the table
|
36
34
|
# @!attribute [r] block
|
37
35
|
# @return [#call] an optional block of code that configures the renderer
|
38
36
|
# @!attribute [r] colorize
|
@@ -41,28 +39,25 @@ module OutputMode
|
|
41
39
|
# @return An optional header color or array of colors
|
42
40
|
# @!attribute [r] row_color
|
43
41
|
# @return An optional data color or array of colors
|
44
|
-
attr_reader :renderer, :
|
42
|
+
attr_reader :renderer, :default, :block, :yes, :no,
|
45
43
|
:header_color, :row_color, :colorize
|
46
44
|
|
47
45
|
# @return [Hash] additional options to +TTY::Table+ renderer
|
48
46
|
# @see https://github.com/piotrmurach/tty-table#33-options
|
49
47
|
def config; super; end
|
50
48
|
|
51
|
-
# @overload initialize(*procs, renderer: nil,
|
49
|
+
# @overload initialize(*procs, renderer: nil, **config)
|
52
50
|
# @param [Array] *procs see {OutputMode::Outputs::Base#initialize}
|
53
51
|
# @param [Symbol] :renderer override the default renderer
|
54
|
-
# @param [Array<String>] :header the header row of the table
|
55
52
|
# @param [Hash] **config additional options to the renderer
|
56
53
|
# @yieldparam tty_table_renderer [TTY::Table::Renderer::Base] optional access the underlining TTY::Table renderer
|
57
54
|
def initialize(*procs,
|
58
55
|
renderer: :unicode,
|
59
56
|
colorize: false,
|
60
|
-
header: nil,
|
61
57
|
header_color: nil,
|
62
58
|
row_color: nil,
|
63
59
|
**config,
|
64
60
|
&block)
|
65
|
-
@header = header
|
66
61
|
@renderer = renderer
|
67
62
|
@block = block
|
68
63
|
@header_color = header_color
|
@@ -76,31 +71,38 @@ module OutputMode
|
|
76
71
|
# @see https://github.com/piotrmurach/tty-table
|
77
72
|
def render(*data)
|
78
73
|
table = TTY::Table.new header: processed_header
|
79
|
-
data.each { |d| table << process_row(
|
74
|
+
data.each { |d| table << process_row(d) }
|
80
75
|
table.render(renderer, **config, &block) || ''
|
81
76
|
end
|
82
77
|
|
83
78
|
private
|
84
79
|
|
80
|
+
def has_header?
|
81
|
+
callables.any? { |c| c.config.key?(:header) }
|
82
|
+
end
|
83
|
+
|
85
84
|
# Colorizes the header when requested
|
86
85
|
def processed_header
|
87
|
-
|
88
|
-
|
86
|
+
return nil unless has_header?
|
87
|
+
callables.map do |callable|
|
88
|
+
header = callable.config.fetch(:header, '')
|
89
|
+
color = callable.config.fetch(:header_color, nil) || header_color
|
89
90
|
case color
|
90
91
|
when nil
|
91
|
-
|
92
|
+
header.to_s
|
92
93
|
when Array
|
93
|
-
pastel.decorate(
|
94
|
+
pastel.decorate(header.to_s, *color)
|
94
95
|
else
|
95
|
-
pastel.decorate(
|
96
|
+
pastel.decorate(header.to_s, color)
|
96
97
|
end
|
97
98
|
end
|
98
99
|
end
|
99
100
|
|
100
101
|
# Colorizes the row when requested
|
101
|
-
def process_row(
|
102
|
-
|
103
|
-
|
102
|
+
def process_row(model)
|
103
|
+
callables.map do |callable|
|
104
|
+
d = callable.generator(self).call(model)
|
105
|
+
color = callable.config[:row_color] || row_color
|
104
106
|
case color
|
105
107
|
when NilClass
|
106
108
|
d.to_s
|
@@ -38,27 +38,24 @@ module OutputMode
|
|
38
38
|
# @yieldparam field: An optional field header for the value
|
39
39
|
# @yieldparam padding: A padding string which will right align the +field+
|
40
40
|
# @yieldparam **config TBA
|
41
|
-
def each(section = nil)
|
42
|
-
# Select the
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
# Find the max field length
|
51
|
-
max = indices.map do |idx|
|
52
|
-
output.index_selector(:fields, idx).to_s.length
|
53
|
-
end.max
|
41
|
+
def each(section = nil, &block)
|
42
|
+
# Select the callable objects
|
43
|
+
callables = if section == nil
|
44
|
+
output.callables
|
45
|
+
elsif section == :default
|
46
|
+
output.callables.config_select(:section, :default, nil)
|
47
|
+
else
|
48
|
+
output.callables.config_select(:section, section)
|
49
|
+
end
|
54
50
|
|
55
51
|
# Yield each selected attribute
|
56
|
-
|
57
|
-
value =
|
58
|
-
|
59
|
-
padding = ' ' * (max - field.to_s.length)
|
60
|
-
yield(value, field: field, padding: padding)
|
52
|
+
objs = callables.pad_each(model, **output.context).map do |callable, padding:, field:|
|
53
|
+
value = callable.generator(output).call(model)
|
54
|
+
[value, { field: field, padding: padding }]
|
61
55
|
end
|
56
|
+
|
57
|
+
# Runs the provided block
|
58
|
+
objs.each(&block)
|
62
59
|
end
|
63
60
|
|
64
61
|
# Renders an ERB object within the entry's context. This provides access to the
|
@@ -35,12 +35,18 @@ module OutputMode
|
|
35
35
|
# @overload register_callable(header:, verbose: true)
|
36
36
|
# @param header: The column's header field when displaying to humans
|
37
37
|
# @param verbose: Whether the column will be shown in the verbose output
|
38
|
+
# @param interactive: Whether the field will be show in the interactive output
|
38
39
|
# @param header_color: Override the default color for the header
|
39
40
|
# @param row_color: Override the default color for the row
|
41
|
+
# @param modes: Additional modes flags for the callable
|
40
42
|
# @yieldparam model The subject the column is describing, some sort of data model
|
41
|
-
def register_callable(header:, verbose: nil, header_color: nil, row_color: nil, &b)
|
42
|
-
|
43
|
-
|
43
|
+
def register_callable(modes: {}, header:, verbose: nil, interactive: nil, header_color: nil, row_color: nil, &b)
|
44
|
+
modes = modes.map { |m| [m, true] }.to_h if modes.is_a? Array
|
45
|
+
super(modes: modes.merge(verbose: verbose, interactive: interactive),
|
46
|
+
header: header,
|
47
|
+
header_color: header_color,
|
48
|
+
row_color: row_color,
|
49
|
+
&b)
|
44
50
|
end
|
45
51
|
alias_method :register_column, :register_callable
|
46
52
|
|
@@ -65,8 +71,16 @@ module OutputMode
|
|
65
71
|
#
|
66
72
|
# An interative/ non-interactive output can be forced by setting the
|
67
73
|
# +interactive+ flag to +true+/+false+ respectively
|
68
|
-
def build_output(verbose:
|
69
|
-
|
74
|
+
def build_output(verbose: nil, ascii: nil, interactive: nil, header_color: [:blue, :bold], row_color: :green, context: {})
|
75
|
+
# Set the interactive and verbose flags if not provided
|
76
|
+
interactive = $stdout.tty? if interactive.nil?
|
77
|
+
verbose = !interactive if verbose.nil?
|
78
|
+
ascii = !interactive if ascii.nil?
|
79
|
+
|
80
|
+
# Update the rendering context with the verbosity/interactive settings
|
81
|
+
context = context.merge(interactive: interactive, verbose: verbose, ascii: ascii)
|
82
|
+
|
83
|
+
callables = if verbose
|
70
84
|
# Filter out columns that are explicitly not verbose
|
71
85
|
output_callables.select { |o| o.verbose?(true) }
|
72
86
|
else
|
@@ -74,27 +88,37 @@ module OutputMode
|
|
74
88
|
output_callables.reject(&:verbose?)
|
75
89
|
end
|
76
90
|
|
77
|
-
|
91
|
+
callables = if interactive
|
92
|
+
# Filter out columns that are explicitly not interactive
|
93
|
+
callables.select { |o| o.interactive?(true) }
|
94
|
+
else
|
95
|
+
# Filter out columns that are explicitly interactive
|
96
|
+
callables.reject { |o| o.interactive? }
|
97
|
+
end
|
98
|
+
|
99
|
+
if interactive
|
78
100
|
# Creates the human readable output
|
79
101
|
opts = if ascii
|
80
102
|
{ yes: 'yes', no: 'no', renderer: :ascii }
|
81
103
|
else
|
82
104
|
{
|
83
105
|
yes: '✓', no: '✕', renderer: :unicode, colorize: TTY::Color.color?,
|
84
|
-
header_color:
|
85
|
-
row_color:
|
106
|
+
header_color: header_color,
|
107
|
+
row_color: row_color
|
86
108
|
}
|
87
109
|
end
|
88
110
|
|
89
111
|
Outputs::Tabulated.new(*callables,
|
90
|
-
|
112
|
+
rotate: false,
|
91
113
|
padding: [0,1],
|
92
114
|
default: '(none)',
|
115
|
+
context: context,
|
93
116
|
**opts
|
94
117
|
)
|
95
118
|
else
|
96
119
|
# Creates the machine readable output
|
97
|
-
Outputs::Delimited.new(*callables, col_sep: "\t", yes: 'yes', no: 'no', default:
|
120
|
+
Outputs::Delimited.new(*callables, col_sep: "\t", yes: 'yes', no: 'no', default: nil,
|
121
|
+
context: context)
|
98
122
|
end
|
99
123
|
end
|
100
124
|
end
|
@@ -25,6 +25,8 @@
|
|
25
25
|
#==============================================================================
|
26
26
|
|
27
27
|
require 'tty-color'
|
28
|
+
require 'output_mode/default_erb'
|
29
|
+
require 'output_mode/non_interactive_erb'
|
28
30
|
|
29
31
|
module OutputMode
|
30
32
|
module TLDR
|
@@ -35,10 +37,16 @@ module OutputMode
|
|
35
37
|
# @overload register_callable(header:, verbose: true)
|
36
38
|
# @param header: The human readable key to the field, uses the term 'header' for consistency
|
37
39
|
# @param verbose: Whether the field will be shown in the verbose output
|
40
|
+
# @param interactive: Whether the field will be show in the interactive output
|
38
41
|
# @param section: Define the grouping a callable belongs to. Ignored by default
|
42
|
+
# @param modes: Additional modes flags for the callable
|
39
43
|
# @yieldparam model The subject the column is describing, some sort of data model
|
40
|
-
def register_callable(header:, verbose: nil, section: :
|
41
|
-
|
44
|
+
def register_callable(modes: {}, header:, verbose: nil, interactive: nil, section: :default, &b)
|
45
|
+
modes = modes.map { |m| [m, true] }.to_h if modes.is_a? Array
|
46
|
+
super(modes: modes.merge(verbose: verbose, interactive: interactive),
|
47
|
+
header: header,
|
48
|
+
section: section,
|
49
|
+
&b)
|
42
50
|
end
|
43
51
|
alias_method :register_attribute, :register_callable
|
44
52
|
|
@@ -61,12 +69,24 @@ module OutputMode
|
|
61
69
|
# for consumption by machines. This output ignores the provided +verbose+
|
62
70
|
# flag as it is always verbose.
|
63
71
|
#
|
64
|
-
# The +template+ overrides the default erb template for
|
72
|
+
# The +template+ overrides the default erb template for interactive sessions.
|
73
|
+
# The +non_interactive_template+ overrides the template for non-interactive
|
74
|
+
# sessions.
|
65
75
|
#
|
66
76
|
# An interative/ non-interactive output can be forced by setting the
|
67
77
|
# +interactive+ flag to +true+/+false+ respectively
|
68
|
-
def build_output(verbose:
|
69
|
-
|
78
|
+
def build_output(verbose: nil, ascii: nil, interactive: nil, context: {},
|
79
|
+
template: OutputMode::DEFAULT_ERB,
|
80
|
+
non_interactive_template: OutputMode::NON_INTERACTIVE_ERB)
|
81
|
+
# Set the interactive and verbose flags if not provided
|
82
|
+
interactive = $stdout.tty? if interactive.nil?
|
83
|
+
verbose = !interactive if verbose.nil?
|
84
|
+
ascii = !interactive if ascii.nil?
|
85
|
+
|
86
|
+
# Update the rendering context with the verbosity/interactive settings
|
87
|
+
context = context.merge(interactive: interactive, verbose: verbose, ascii: ascii)
|
88
|
+
|
89
|
+
callables = if verbose
|
70
90
|
# Filter out columns that are explicitly not verbose
|
71
91
|
output_callables.select { |o| o.verbose?(true) }
|
72
92
|
else
|
@@ -74,26 +94,30 @@ module OutputMode
|
|
74
94
|
output_callables.reject(&:verbose?)
|
75
95
|
end
|
76
96
|
|
77
|
-
|
78
|
-
#
|
79
|
-
|
80
|
-
{ yes: 'yes', no: 'no', colorize: false }
|
81
|
-
else
|
82
|
-
{ yes: '✓', no: '✕', colorize: TTY::Color.color? }
|
83
|
-
end
|
84
|
-
|
85
|
-
sections = callables.map { |o| o.config[:section] }
|
86
|
-
|
87
|
-
Outputs::Templated.new(*callables,
|
88
|
-
fields: callables.map { |c| c.config.fetch(:header, 'missing') },
|
89
|
-
default: '(none)',
|
90
|
-
sections: sections,
|
91
|
-
template: template,
|
92
|
-
**opts)
|
97
|
+
callables = if interactive
|
98
|
+
# Filter out columns that are explicitly not interactive
|
99
|
+
callables.select { |o| o.interactive?(true) }
|
93
100
|
else
|
94
|
-
#
|
95
|
-
|
101
|
+
# Filter out columns that are explicitly interactive
|
102
|
+
callables.reject { |o| o.interactive? }
|
96
103
|
end
|
104
|
+
|
105
|
+
# Define the templating parameters
|
106
|
+
opts = if ascii && interactive
|
107
|
+
{ yes: 'yes', no: 'no', colorize: false, default: '(none)', template: template }
|
108
|
+
elsif interactive
|
109
|
+
{ yes: '✓', no: '✕', colorize: TTY::Color.color?, default: '(none)', template: template }
|
110
|
+
else
|
111
|
+
{ yes: 'yes', no: 'no', colorize: false, default: '', template: non_interactive_template }
|
112
|
+
end
|
113
|
+
|
114
|
+
sections = callables.map { |o| o.config[:section] }
|
115
|
+
|
116
|
+
Outputs::Templated.new(*callables,
|
117
|
+
fields: callables.map { |c| c.config.fetch(:header, 'missing') },
|
118
|
+
sections: sections,
|
119
|
+
context: context,
|
120
|
+
**opts)
|
97
121
|
end
|
98
122
|
end
|
99
123
|
end
|
data/lib/output_mode/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: output_mode
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- William McCumsite
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-05-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tty-table
|
@@ -122,14 +122,22 @@ files:
|
|
122
122
|
- LICENSE.txt
|
123
123
|
- README.md
|
124
124
|
- Rakefile
|
125
|
+
- bin/bundle
|
126
|
+
- bin/coderay
|
125
127
|
- bin/console
|
126
128
|
- bin/demo
|
129
|
+
- bin/htmldiff
|
130
|
+
- bin/ldiff
|
131
|
+
- bin/pry
|
132
|
+
- bin/rake
|
133
|
+
- bin/rspec
|
127
134
|
- bin/setup
|
128
135
|
- lib/output_mode.rb
|
129
136
|
- lib/output_mode/builder_dsl.rb
|
130
137
|
- lib/output_mode/callable.rb
|
131
138
|
- lib/output_mode/default_erb.rb
|
132
139
|
- lib/output_mode/errors.rb
|
140
|
+
- lib/output_mode/non_interactive_erb.rb
|
133
141
|
- lib/output_mode/output.rb
|
134
142
|
- lib/output_mode/outputs.rb
|
135
143
|
- lib/output_mode/outputs/delimited.rb
|