output_mode 1.5.0 → 1.7.0

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: 33db72e9e5872a974df80e11a0d4bae3735c13d49d3be4d4ab1366b7e461551f
4
- data.tar.gz: f1ac7923d6cb9beda1f3af36ebaa41b84cdb6567d5fb71db4f2d1a2503ee731b
3
+ metadata.gz: 4beed6d9f51548ef131e475bb68aa9c6d6fe079e39672b4691566ff80ffb65c2
4
+ data.tar.gz: df648ec5ee82875c189123dca55bfaabfa3bf4d5ba24e160be1d0f15bb1a624b
5
5
  SHA512:
6
- metadata.gz: f12f87485cdad45ceb4fba9b9b26c405366009b1ad39e87c223fc246424bd0501421a75570caf48c351523d55483f4ea1d705659a3e6185ae8213c6147d9ad96
7
- data.tar.gz: cafd82a58648d5e4900c91d242a1128b2b1c5d1123716385160801a3d85959324df691ecd7c8443e038612e4c2b2afb221745da598483e239a15a7ef9a701c0a
6
+ metadata.gz: 4e19a13c9e5b0b6e3fa497aadd4d1ed59bb6297fd8063f88d7f6a01bd4dd84f801baae9be8efe46a0e42e63024824d227fa51c0f7b84ad283baec7f5960fb2f6
7
+ data.tar.gz: b9ea560f3b42886ca8baaa04452cc5e4557c82ddf23068b095b544f2649b425b5b30a30212d6ef7955cd1fde41c624b4f9fbe73cfc32a3a2ddb1092f6d16fd54
data/.travis.yml CHANGED
@@ -3,7 +3,6 @@ sudo: false
3
3
  language: ruby
4
4
  cache: bundler
5
5
  rvm:
6
- - 2.6.5
7
6
  - 2.7.0
8
7
  before_install: gem install bundler -v 2.0.2
9
8
  script: bundle exec rspec --format documentation --order random
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/byebug 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 'byebug' 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("byebug", "byebug")
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
@@ -29,61 +29,50 @@ require "bundler/setup"
29
29
  require "output_mode"
30
30
  require 'erb'
31
31
 
32
- module DemoIndex
33
- extend OutputMode::TLDR::Index
34
-
35
- register_callable(header: 'Integer', row_color: [:yellow, :bold]) { |i| i }
36
- register_callable(header: 'Standard', header_color: [:strikethrough] ) { 'always visible' }
37
- register_callable(header: 'Verbose', verbose: true) { 'verbose visible' }
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' }
41
- register_callable(header: 'Yes/True') { true }
42
- register_callable(header: 'No/False', row_color: [:clear]) { false }
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'
32
+ class DemoIndex < OutputMode::Formatters::Index
33
+ constructor do
34
+ register(header: 'Integer', row_color: [:yellow, :bold]) { |i| i }
35
+ register(header: 'Standard', header_color: [:strikethrough] ) { 'always visible' }
36
+ if verbose?
37
+ register(header: 'Verbose') { 'verbose visible' }
51
38
  else
52
- 'non-interactive-simplified'
39
+ register(header: 'Simplified') { 'simplified visible' }
53
40
  end
41
+ if interactive?
42
+ register(header: 'Interactive') { 'interactive visible' }
43
+ else
44
+ register(header: 'Non Interactive') { 'non-interactive visible' }
45
+ end
46
+ register(header: 'Yes/True') { true }
47
+ register(header: 'No/False', row_color: [:clear]) { false }
48
+ register(header: 'Missing') { nil }
54
49
  end
55
50
  end
56
51
 
57
- module DemoShow
58
- extend OutputMode::TLDR::Show
59
-
60
- register_callable(header: 'Integer') { |i| i }
61
- register_callable(header: 'Standard') { 'always visible' }
62
- register_callable(header: 'Verbose', verbose: true) { 'verbose visible' }
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' }
66
- register_callable(header: 'Yes/True', section: :boolean) { true }
67
- register_callable(header: 'No/False', section: :boolean) { false }
68
- register_callable(header: 'Missing') { nil }
69
- register_callable(header: 'Tab') { "tab1\ttab2" }
70
- register_callable(header: 'New line') { "line1\nline2" }
52
+ class DemoShow < OutputMode::Formatters::Show
53
+ constructor do
54
+ register(header: 'Integer') { |i| i }
55
+ register(header: 'Standard') { 'always visible' }
56
+ if verbose?
57
+ register(header: 'Verbose') { 'verbose visible' }
58
+ else
59
+ register(header: 'Simplified') { 'simplified visible' }
60
+ end
61
+ if interactive?
62
+ register(header: 'Interactive') { 'interactive visible' }
63
+ else
64
+ register(header: 'Non Interactive') { 'non-interactive visible' }
65
+ end
66
+ register(header: 'Yes/True', section: :boolean) { true }
67
+ register(header: 'No/False', section: :boolean) { false }
68
+ register(header: 'Missing') { nil }
69
+ register(header: 'Tab') { "tab1\ttab2" }
70
+ register(header: 'New line') { "line1\nline2" }
71
+ end
71
72
  end
72
73
 
73
74
  data = [1, 2, 3]
74
75
 
75
- other_template = ERB.new(<<~TEMPLATE, nil, '-')
76
- # Non boolean values
77
- <% each(:other) do |value, field:, padding:, **_| -%>
78
- <%= padding -%><%= pastel.blue.bold field -%><%= pastel.bold ':' -%> <%= pastel.green value %>
79
- <% end -%>
80
-
81
- # Boolean Values
82
- <% each(:boolean) do |value, field:, padding:, **_| -%>
83
- <%= padding -%><%= pastel.blue.bold field -%><%= pastel.bold ':' -%> <%= pastel.green value %>
84
- <% end -%>
85
- TEMPLATE
86
-
87
76
  puts <<~EOF
88
77
  #==============================================================================
89
78
  #==============================================================================
@@ -95,34 +84,34 @@ puts <<~EOF
95
84
  # Default Demo Index
96
85
  # Simplified in interactive shells, verbose in non-interactive
97
86
  #==============================================================================
98
- #{DemoIndex.build_output.render(*data)}
87
+ #{DemoIndex.render(*data)}
99
88
 
100
89
  #==============================================================================
101
90
  # Demo Verbose Index
102
91
  #==============================================================================
103
- #{DemoIndex.build_output(verbose: true).render(*data)}
92
+ #{DemoIndex.render(*data, verbose: true)}
104
93
 
105
94
  #==============================================================================
106
95
  # Demo "Simplified" Index
107
96
  #==============================================================================
108
- #{DemoIndex.build_output(verbose: false).render(*data)}
97
+ #{DemoIndex.render(*data, verbose: false)}
109
98
 
110
99
  #==============================================================================
111
100
  # Force Interactive
112
101
  # Always print as if the shell is interactive
113
102
  #==============================================================================
114
- #{DemoIndex.build_output(interactive: true).render(*data)}
103
+ #{DemoIndex.render(*data, interactive: true)}
115
104
 
116
105
  #==============================================================================
117
106
  # Force Non-Interactive
118
107
  # Always print as if the shell is non-interactive
119
108
  #==============================================================================
120
- #{DemoIndex.build_output(interactive: false).render(*data)}
109
+ #{DemoIndex.render(*data, interactive: false)}
121
110
 
122
111
  #==============================================================================
123
112
  # Demo ASCII Index
124
113
  #==============================================================================
125
- #{DemoIndex.build_output(ascii: true).render(*data)}
114
+ #{DemoIndex.render(*data, ascii: true)}
126
115
 
127
116
  #==============================================================================
128
117
  #==============================================================================
@@ -134,39 +123,32 @@ puts <<~EOF
134
123
  # Default Settings
135
124
  # Simplified in interactive shells, verbose in non-interactive
136
125
  #==============================================================================
137
- #{DemoShow.build_output.render(*data)}
126
+ #{DemoShow.render(data.first)}
138
127
 
139
128
  #==============================================================================
140
129
  # Demo Verbose Show
141
130
  #==============================================================================
142
- #{DemoShow.build_output(verbose: true).render(*data)}
131
+ #{DemoShow.render(data.first, verbose: true)}
143
132
 
144
133
  #==============================================================================
145
134
  # Demo "Simplified" Show
146
135
  #==============================================================================
147
- #{DemoShow.build_output(verbose: false).render(*data)}
136
+ #{DemoShow.render(data.first, verbose: false)}
148
137
 
149
138
  #==============================================================================
150
139
  # Force Interactive
151
140
  # Always print as if the shell is interactive
152
141
  #==============================================================================
153
- #{DemoShow.build_output(interactive: true).render(*data)}
142
+ #{DemoShow.render(data.first, interactive: true)}
154
143
 
155
144
  #==============================================================================
156
145
  # Force Non-Interactive
157
146
  # Always print as if the shell is non-interactive
158
147
  #==============================================================================
159
- #{DemoShow.build_output(interactive: false).render(*data)}
148
+ #{DemoShow.render(data.first, interactive: false)}
160
149
 
161
150
  #==============================================================================
162
151
  # Demo ASCII Index
163
152
  #==============================================================================
164
- #{DemoShow.build_output(ascii: true).render(*data)}
165
-
166
- #==============================================================================
167
- # Group the boolean value separately
168
- # NOTE: This only occurs in interactive mode
169
- # Non-Interactive sessions have a fix order
170
- #==============================================================================
171
- #{DemoShow.build_output(template: other_template).render(*data)}
153
+ #{DemoShow.render(data.first, ascii: true)}
172
154
  EOF
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")
@@ -34,7 +34,9 @@ module OutputMode
34
34
  @callables = []
35
35
  case callables
36
36
  when Array, Callables
37
- callables.each { |c| @callables << c }
37
+ callables.each do |c|
38
+ @callables << (c.is_a?(Callable) ? c : Callable.new(&c))
39
+ end
38
40
  when nil
39
41
  # NOOP
40
42
  else
@@ -56,20 +58,39 @@ module OutputMode
56
58
  @callables.each(&block)
57
59
  end
58
60
 
59
- def pad_each(key = :header)
60
- max_length = self.map { |c| c.config[key].to_s.length }
61
- .max
61
+ def pad_each(*ctx, **input_opts, &block)
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
62
78
 
63
- pads = self.map do |callable|
64
- length = max_length - callable.config[key].to_s.length
65
- [callable, { padding: ' ' * length }]
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 }]
66
84
  end
67
85
 
68
- if block_given?
69
- pads.each { |*args| yield(*args) }
70
- else
71
- pads.each
86
+ # Generate an enum
87
+ # NOTE: This fixes the double splate deprecation warning
88
+ enum = Enumerator.new do |yielder|
89
+ pads.each do |callable, opts|
90
+ yielder.yield(callable, **opts)
91
+ end
72
92
  end
93
+ enum.each(&block)
73
94
  end
74
95
 
75
96
  def config_select(key, *values)
@@ -83,6 +104,10 @@ module OutputMode
83
104
  end
84
105
  Callables.new(selected)
85
106
  end
107
+
108
+ def length
109
+ @callables.length
110
+ end
86
111
  end
87
112
 
88
113
  class Callable
@@ -116,6 +141,8 @@ module OutputMode
116
141
 
117
142
  # Handles the dynamic +<query>?+ and +<explicit-negation>!+ methods
118
143
  #
144
+ # DEPRECATED: The explicit! negation operator should not be used
145
+ #
119
146
  # @return [Boolean] The result of the query or explicit-negation
120
147
  # @raise [NoMethodError] All other method calls
121
148
  def method_missing(s, *args, &b)
@@ -175,6 +202,7 @@ module OutputMode
175
202
  callable.call(*a)
176
203
  end
177
204
 
205
+ # DEPRECATED: Use a Formatter class
178
206
  def generator(output)
179
207
  ->(*a) do
180
208
  # Implicitly determine which parts of the context can be passed through
@@ -1,5 +1,27 @@
1
1
  #==============================================================================
2
- # Refer to LICENSE.txt for licensing terms
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,146 @@
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 'tty-color'
28
+
29
+ module OutputMode
30
+ class Formatter
31
+ def self.constructor(&block)
32
+ @constructor ||= block
33
+ end
34
+
35
+ def self.build(*objects, **opts)
36
+ new(*objects, **opts).tap do |policy|
37
+ next unless constructor
38
+ policy.instance_exec(&constructor)
39
+ end
40
+ end
41
+
42
+ def self.render(*objects, **opts)
43
+ build(*objects, **opts).render
44
+ end
45
+
46
+ def initialize(*objects, verbose: nil, ascii: nil, interactive: nil, color: nil)
47
+ @verbose = verbose
48
+ @ascii = ascii
49
+ @interactive = interactive
50
+ @color = color
51
+
52
+ # NOTE: This is intentionally not exposed on the base class
53
+ # It is up to the individual implementations to expose it
54
+ @objects = objects
55
+ end
56
+
57
+ def callables
58
+ @callables ||= Callables.new
59
+ end
60
+
61
+ def register(**config, &block)
62
+ callables << Callable.new(**config) do |*args, **opts|
63
+ value = block.call(*args, **opts)
64
+ format(value, **config)
65
+ end
66
+ end
67
+
68
+ def format(value, **config)
69
+ case value
70
+ when TrueClass
71
+ config[:yes] || yes
72
+ when FalseClass
73
+ config[:no] || no
74
+ when NilClass
75
+ config[:default] || default
76
+ when Time
77
+ format = config[:time] || time
78
+ value.strftime(format)
79
+ else
80
+ value
81
+ end
82
+ end
83
+
84
+ def build_output
85
+ raise NotImplementedError
86
+ end
87
+
88
+ def render
89
+ build_output.render(*@objects)
90
+ end
91
+
92
+ def interactive?
93
+ if @interactive.nil?
94
+ $stdout.tty?
95
+ else
96
+ @interactive
97
+ end
98
+ end
99
+
100
+ def color?
101
+ if @color.nil? && (ascii? || !interactive?)
102
+ false
103
+ elsif @color.nil?
104
+ TTY::Color.color?
105
+ else
106
+ @color
107
+ end
108
+ end
109
+
110
+ def ascii?
111
+ if @ascii.nil?
112
+ !interactive?
113
+ else
114
+ @ascii
115
+ end
116
+ end
117
+
118
+ def verbose?
119
+ if @verbose.nil?
120
+ !interactive?
121
+ else
122
+ @verbose
123
+ end
124
+ end
125
+
126
+ def yes(value = nil)
127
+ @yes = value unless value.nil?
128
+ @yes ? @yes : (ascii? ? 'yes' : '✓')
129
+ end
130
+
131
+ def no(value = nil)
132
+ @no = value unless value.nil?
133
+ @no ? @no : (ascii? ? 'no' : '✕')
134
+ end
135
+
136
+ def default(value = nil)
137
+ @default = value unless value.nil?
138
+ @default ? @default : (interactive? ? '(none)' : '')
139
+ end
140
+
141
+ def time(value = nil)
142
+ @time = value unless value.nil?
143
+ @time ? @time : (verbose? ? "%Y-%m-%dT%H:%M:%S%:z" : "%d/%m/%y %H:%M")
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,59 @@
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
+ module OutputMode
28
+ module Formatters
29
+ class Index < Formatter
30
+ attr_reader :objects
31
+
32
+ def header_color(value = nil)
33
+ @header_color = value unless value.nil?
34
+ @header_color ? @header_color : :bold
35
+ end
36
+
37
+ def row_color(value = nil)
38
+ @row_color = value unless value.nil?
39
+ @row_color ? @row_color : :cyan
40
+ end
41
+
42
+ def build_output
43
+ if interactive?
44
+ opts = {
45
+ renderer: ascii? ? :ascii : :unicode,
46
+ header_color: header_color,
47
+ row_color: row_color,
48
+ colorize: color?,
49
+ rotate: false,
50
+ padding: [0, 1]
51
+ }
52
+ Outputs::Tabulated.new(*callables, **opts)
53
+ else
54
+ Outputs::Delimited.new(*callables, col_sep: "\t")
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,98 @@
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 'output_mode/default_erb'
28
+ require 'output_mode/non_interactive_erb'
29
+
30
+ module OutputMode
31
+ module Formatters
32
+ class Show < Formatter
33
+ include Enumerable
34
+
35
+ # Limit the policy to a single object
36
+ def initialize(object, **opts)
37
+ super
38
+ end
39
+
40
+ def object
41
+ @objects.first
42
+ end
43
+
44
+ def template(value = nil)
45
+ @template = value unless value.nil?
46
+ @template ? @template : (interactive? ? DEFAULT_ERB : NON_INTERACTIVE_ERB)
47
+ end
48
+
49
+ def scope(value = nil)
50
+ @scope = value unless value.nil?
51
+ @scope ? @scope : self
52
+ end
53
+
54
+ def build_output
55
+ opts = {
56
+ template: template,
57
+ colorize: color?,
58
+ bind: scope.instance_exec { binding }
59
+ }
60
+ OutputMode::Outputs::Templated.new(*callables, **opts)
61
+ end
62
+
63
+ # @yieldparam value An attribute to be rendered
64
+ # @yieldparam field: An optional field header for the value
65
+ # @yieldparam padding: A padding string which will right align the +field+
66
+ # @yieldparam **config TBA
67
+ def each(section = nil, &block)
68
+ # Select the callable objects
69
+ selected = if section == nil
70
+ callables
71
+ elsif section == :default
72
+ callables.config_select(:section, :default, nil)
73
+ else
74
+ callables.config_select(:section, section)
75
+ end
76
+
77
+ # Yield each selected attribute
78
+ objs = selected.pad_each(object).map do |callable, opts|
79
+ field = opts[:field]
80
+ padding = opts[:padding]
81
+ value = callable.call(object)
82
+ [value, { field: field, padding: padding }]
83
+ end
84
+
85
+ # Runs the provided block
86
+ objs.each do |model, opts|
87
+ block.call(model, **opts)
88
+ end
89
+ end
90
+
91
+ # Library for colorizing the output. It is automatically disabled when the
92
+ # +colorize+ flag is +false+
93
+ def pastel
94
+ @pastel ||= Pastel.new(enabled: color?)
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,36 @@
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
+ module OutputMode
28
+ autoload 'Formatter', File.expand_path('formatter.rb', __dir__)
29
+
30
+ module Formatters
31
+ Dir.glob(File.expand_path('formatters/*.rb', __dir__)).each do |path|
32
+ autoload File.basename(path).chomp('.rb').capitalize, path
33
+ end
34
+ end
35
+ end
36
+
@@ -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
@@ -77,11 +77,16 @@ module OutputMode
77
77
 
78
78
  private
79
79
 
80
+ def has_header?
81
+ callables.any? { |c| c.config.key?(:header) }
82
+ end
83
+
80
84
  # Colorizes the header when requested
81
85
  def processed_header
86
+ return nil unless has_header?
82
87
  callables.map do |callable|
83
88
  header = callable.config.fetch(:header, '')
84
- color = callable.config.fetch(:header_color) || header_color
89
+ color = callable.config.fetch(:header_color, nil) || header_color
85
90
  case color
86
91
  when nil
87
92
  header.to_s
@@ -49,14 +49,15 @@ module OutputMode
49
49
  end
50
50
 
51
51
  # Yield each selected attribute
52
- objs = callables.pad_each.map do |callable, padding:|
52
+ objs = callables.pad_each(model, **output.context).map do |callable, padding:, field:|
53
53
  value = callable.generator(output).call(model)
54
- field = callable.config[:header]
55
- [value, {field: field, padding: padding }]
54
+ [value, { field: field, padding: padding }]
56
55
  end
57
56
 
58
57
  # Runs the provided block
59
- objs.each(&block)
58
+ objs.each do |model, opts|
59
+ block.call(model, **opts)
60
+ end
60
61
  end
61
62
 
62
63
  # Renders an ERB object within the entry's context. This provides access to the
@@ -87,7 +88,8 @@ module OutputMode
87
88
  # @!attribute [r] fields
88
89
  # @!attribute [r] colorize
89
90
  # @!attribute [r] sections
90
- attr_reader :erb, :fields, :separator, :colorize, :sections
91
+ # @!attribute [r] bind
92
+ attr_reader :erb, :fields, :separator, :colorize, :sections, :bind
91
93
 
92
94
  # Create a new +output+ which will render using +ERB+. The provided +template+ should
93
95
  # only render the +output+ for a single +entry+ (aka model, record, data object, etc).
@@ -105,10 +107,11 @@ module OutputMode
105
107
  # @param [Array] *procs see {OutputMode::Output#initialize}
106
108
  # @param [ERB] template: The +template+ object used by the renderer
107
109
  # @param [Array] fields: An optional array of field headers that map to the procs, repeating the last value if required
108
- # @param fields: A static value to use as all field headers
110
+ # @param fields: DEPRECATED A static value to use as all field headers
109
111
  # @param separator: The character(s) used to join the "entries" together
110
112
  # @param colorize: Flags if the caller wants the colorized version, this maybe ignored by +template+
111
- # @param sections: An optional array that groups the procs into sections. This is ignored by default
113
+ # @param sections: DEPRECATED An optional array that groups the procs into sections
114
+ # @param bind: An optional execution context to render the template within
112
115
  # @param [Hash] **config see {OutputMode::Output#initialize}
113
116
  def initialize(*procs,
114
117
  template: nil,
@@ -116,6 +119,7 @@ module OutputMode
116
119
  separator: "\n",
117
120
  colorize: false,
118
121
  sections: nil,
122
+ bind: nil,
119
123
  **config)
120
124
  @erb = case template
121
125
  when String
@@ -129,6 +133,7 @@ module OutputMode
129
133
  @separator = separator
130
134
  @colorize = colorize
131
135
  @sections = sections
136
+ @bind = bind
132
137
  super(*procs, **config)
133
138
  end
134
139
 
@@ -138,11 +143,17 @@ module OutputMode
138
143
  #
139
144
  # @see OutputMode::Output#render
140
145
  def render(*data)
141
- data.map { |d| Entry.new(self, d, colorize).render(erb) }
142
- .join(separator)
146
+ data.map do |datum|
147
+ if bind
148
+ erb.result(bind)
149
+ else
150
+ Entry.new(self, datum, colorize).render(erb)
151
+ end
152
+ end.join(separator)
143
153
  end
144
154
 
145
155
  # Returns the length of the maximum field
156
+ # DEPRECATED
146
157
  def max_field_length
147
158
  if fields.is_a? Array
148
159
  fields.map { |f| f.to_s.length }.max
@@ -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
@@ -39,7 +41,7 @@ module OutputMode
39
41
  # @param section: Define the grouping a callable belongs to. Ignored by default
40
42
  # @param modes: Additional modes flags for the callable
41
43
  # @yieldparam model The subject the column is describing, some sort of data model
42
- def register_callable(modes: {}, header:, verbose: nil, interactive: nil, section: :other, &b)
44
+ def register_callable(modes: {}, header:, verbose: nil, interactive: nil, section: :default, &b)
43
45
  modes = modes.map { |m| [m, true] }.to_h if modes.is_a? Array
44
46
  super(modes: modes.merge(verbose: verbose, interactive: interactive),
45
47
  header: header,
@@ -67,11 +69,15 @@ module OutputMode
67
69
  # for consumption by machines. This output ignores the provided +verbose+
68
70
  # flag as it is always verbose.
69
71
  #
70
- # The +template+ overrides the default erb template for the output
72
+ # The +template+ overrides the default erb template for interactive sessions.
73
+ # The +non_interactive_template+ overrides the template for non-interactive
74
+ # sessions.
71
75
  #
72
76
  # An interative/ non-interactive output can be forced by setting the
73
77
  # +interactive+ flag to +true+/+false+ respectively
74
- def build_output(verbose: nil, ascii: nil, interactive: nil, template: nil, context: {})
78
+ def build_output(verbose: nil, ascii: nil, interactive: nil, context: {},
79
+ template: OutputMode::DEFAULT_ERB,
80
+ non_interactive_template: OutputMode::NON_INTERACTIVE_ERB)
75
81
  # Set the interactive and verbose flags if not provided
76
82
  interactive = $stdout.tty? if interactive.nil?
77
83
  verbose = !interactive if verbose.nil?
@@ -96,28 +102,22 @@ module OutputMode
96
102
  callables.reject { |o| o.interactive? }
97
103
  end
98
104
 
99
- if interactive
100
- # Creates the human readable output
101
- opts = if ascii
102
- { yes: 'yes', no: 'no', colorize: false }
103
- else
104
- { yes: '✓', no: '✕', colorize: TTY::Color.color? }
105
- end
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
106
113
 
107
- sections = callables.map { |o| o.config[:section] }
114
+ sections = callables.map { |o| o.config[:section] }
108
115
 
109
- Outputs::Templated.new(*callables,
110
- fields: callables.map { |c| c.config.fetch(:header, 'missing') },
111
- default: '(none)',
112
- sections: sections,
113
- template: template,
114
- context: context,
115
- **opts)
116
- else
117
- # Creates the machine readable output
118
- Outputs::Delimited.new(*callables, col_sep: "\t", yes: 'yes', no: 'no', default: nil,
119
- context: context)
120
- end
116
+ Outputs::Templated.new(*callables,
117
+ fields: callables.map { |c| c.config.fetch(:header, 'missing') },
118
+ sections: sections,
119
+ context: context,
120
+ **opts)
121
121
  end
122
122
  end
123
123
  end
@@ -25,5 +25,5 @@
25
25
  #==============================================================================
26
26
 
27
27
  module OutputMode
28
- VERSION = "1.5.0"
28
+ VERSION = "1.7.0"
29
29
  end
data/lib/output_mode.rb CHANGED
@@ -29,6 +29,7 @@ require 'output_mode/errors'
29
29
 
30
30
  require 'output_mode/outputs'
31
31
  require 'output_mode/callable'
32
+ require 'output_mode/formatters'
32
33
  require 'output_mode/builder_dsl'
33
34
  require 'output_mode/tldr'
34
35
 
data/output_mode.gemspec CHANGED
@@ -57,4 +57,5 @@ Gem::Specification.new do |spec|
57
57
  spec.add_development_dependency "rake", ">= 12.3.3"
58
58
  spec.add_development_dependency "rspec", "~> 3.0"
59
59
  spec.add_development_dependency "pry", "> 0.11"
60
+ spec.add_development_dependency "pry-byebug", "~> 3.0"
60
61
  end
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.5.0
4
+ version: 1.7.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: 2021-04-10 00:00:00.000000000 Z
11
+ date: 2021-10-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tty-table
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">"
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0.11'
111
+ - !ruby/object:Gem::Dependency
112
+ name: pry-byebug
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '3.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '3.0'
111
125
  description:
112
126
  email:
113
127
  - openlicense.williams@gmail.com
@@ -122,14 +136,27 @@ files:
122
136
  - LICENSE.txt
123
137
  - README.md
124
138
  - Rakefile
139
+ - bin/bundle
140
+ - bin/byebug
141
+ - bin/coderay
125
142
  - bin/console
126
143
  - bin/demo
144
+ - bin/htmldiff
145
+ - bin/ldiff
146
+ - bin/pry
147
+ - bin/rake
148
+ - bin/rspec
127
149
  - bin/setup
128
150
  - lib/output_mode.rb
129
151
  - lib/output_mode/builder_dsl.rb
130
152
  - lib/output_mode/callable.rb
131
153
  - lib/output_mode/default_erb.rb
132
154
  - lib/output_mode/errors.rb
155
+ - lib/output_mode/formatter.rb
156
+ - lib/output_mode/formatters.rb
157
+ - lib/output_mode/formatters/index.rb
158
+ - lib/output_mode/formatters/show.rb
159
+ - lib/output_mode/non_interactive_erb.rb
133
160
  - lib/output_mode/output.rb
134
161
  - lib/output_mode/outputs.rb
135
162
  - lib/output_mode/outputs/delimited.rb