output_mode 1.5.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 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