output_mode 1.6.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: e4d5f1fa1744eeff5535f33a65593b370d317124736089a8b24e2d76cb824b6e
4
- data.tar.gz: 10e77ade81138ebe9c6ca3e6b3299ba864c213603e54682eebb611057f72e2d6
3
+ metadata.gz: 4beed6d9f51548ef131e475bb68aa9c6d6fe079e39672b4691566ff80ffb65c2
4
+ data.tar.gz: df648ec5ee82875c189123dca55bfaabfa3bf4d5ba24e160be1d0f15bb1a624b
5
5
  SHA512:
6
- metadata.gz: a754089932ba840c19e0070b03e99e10fd4a957e4204ee08806dde91d54d51899950f817b8a34d3736f6c1fa9df4f85321fd938909c381f12230fe53df312ed1
7
- data.tar.gz: 7d5858053e4d55868893bbfa2c13ed63a52bd39f05f6b4ae690a29072c0ab7f7a4d9919204c6fd387dc2bd0ad19efec2fa5e0d023e22929452d2efa616cdf6d6
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/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/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
@@ -58,7 +58,7 @@ module OutputMode
58
58
  @callables.each(&block)
59
59
  end
60
60
 
61
- def pad_each(*ctx, **input_opts)
61
+ def pad_each(*ctx, **input_opts, &block)
62
62
  fields = self.map do |callables|
63
63
  field = callables.config[:header]
64
64
  if field.respond_to?(:call)
@@ -83,11 +83,14 @@ module OutputMode
83
83
  [callable, { padding: ' ' * length, field: field }]
84
84
  end
85
85
 
86
- if block_given?
87
- pads.each { |c, opts| yield(c, **opts) }
88
- else
89
- 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
90
92
  end
93
+ enum.each(&block)
91
94
  end
92
95
 
93
96
  def config_select(key, *values)
@@ -138,6 +141,8 @@ module OutputMode
138
141
 
139
142
  # Handles the dynamic +<query>?+ and +<explicit-negation>!+ methods
140
143
  #
144
+ # DEPRECATED: The explicit! negation operator should not be used
145
+ #
141
146
  # @return [Boolean] The result of the query or explicit-negation
142
147
  # @raise [NoMethodError] All other method calls
143
148
  def method_missing(s, *args, &b)
@@ -197,6 +202,7 @@ module OutputMode
197
202
  callable.call(*a)
198
203
  end
199
204
 
205
+ # DEPRECATED: Use a Formatter class
200
206
  def generator(output)
201
207
  ->(*a) do
202
208
  # Implicitly determine which parts of the context can be passed through
@@ -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
+
@@ -55,7 +55,9 @@ module OutputMode
55
55
  end
56
56
 
57
57
  # Runs the provided block
58
- objs.each(&block)
58
+ objs.each do |model, opts|
59
+ block.call(model, **opts)
60
+ end
59
61
  end
60
62
 
61
63
  # Renders an ERB object within the entry's context. This provides access to the
@@ -86,7 +88,8 @@ module OutputMode
86
88
  # @!attribute [r] fields
87
89
  # @!attribute [r] colorize
88
90
  # @!attribute [r] sections
89
- attr_reader :erb, :fields, :separator, :colorize, :sections
91
+ # @!attribute [r] bind
92
+ attr_reader :erb, :fields, :separator, :colorize, :sections, :bind
90
93
 
91
94
  # Create a new +output+ which will render using +ERB+. The provided +template+ should
92
95
  # only render the +output+ for a single +entry+ (aka model, record, data object, etc).
@@ -104,10 +107,11 @@ module OutputMode
104
107
  # @param [Array] *procs see {OutputMode::Output#initialize}
105
108
  # @param [ERB] template: The +template+ object used by the renderer
106
109
  # @param [Array] fields: An optional array of field headers that map to the procs, repeating the last value if required
107
- # @param fields: A static value to use as all field headers
110
+ # @param fields: DEPRECATED A static value to use as all field headers
108
111
  # @param separator: The character(s) used to join the "entries" together
109
112
  # @param colorize: Flags if the caller wants the colorized version, this maybe ignored by +template+
110
- # @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
111
115
  # @param [Hash] **config see {OutputMode::Output#initialize}
112
116
  def initialize(*procs,
113
117
  template: nil,
@@ -115,6 +119,7 @@ module OutputMode
115
119
  separator: "\n",
116
120
  colorize: false,
117
121
  sections: nil,
122
+ bind: nil,
118
123
  **config)
119
124
  @erb = case template
120
125
  when String
@@ -128,6 +133,7 @@ module OutputMode
128
133
  @separator = separator
129
134
  @colorize = colorize
130
135
  @sections = sections
136
+ @bind = bind
131
137
  super(*procs, **config)
132
138
  end
133
139
 
@@ -137,11 +143,17 @@ module OutputMode
137
143
  #
138
144
  # @see OutputMode::Output#render
139
145
  def render(*data)
140
- data.map { |d| Entry.new(self, d, colorize).render(erb) }
141
- .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)
142
153
  end
143
154
 
144
155
  # Returns the length of the maximum field
156
+ # DEPRECATED
145
157
  def max_field_length
146
158
  if fields.is_a? Array
147
159
  fields.map { |f| f.to_s.length }.max
@@ -25,5 +25,5 @@
25
25
  #==============================================================================
26
26
 
27
27
  module OutputMode
28
- VERSION = "1.6.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.6.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-05-24 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
@@ -123,6 +137,7 @@ files:
123
137
  - README.md
124
138
  - Rakefile
125
139
  - bin/bundle
140
+ - bin/byebug
126
141
  - bin/coderay
127
142
  - bin/console
128
143
  - bin/demo
@@ -137,6 +152,10 @@ files:
137
152
  - lib/output_mode/callable.rb
138
153
  - lib/output_mode/default_erb.rb
139
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
140
159
  - lib/output_mode/non_interactive_erb.rb
141
160
  - lib/output_mode/output.rb
142
161
  - lib/output_mode/outputs.rb