cli_helper 0.0.4 → 0.1.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.
data/lib/cli_helper.rb CHANGED
@@ -6,22 +6,15 @@
6
6
  ## By: Dewayne VanHoozer (dvanhoozer@gmail.com)
7
7
  #
8
8
 
9
- #require 'test_inline'
10
-
11
- # NOTE: this conditional required by test_inline
12
- if caller.empty?
13
- required_by_filename = __FILE__
14
- else
15
- required_by_filename = caller.last.split(':').first
16
- end
17
-
18
- require 'debug_me'
19
- include DebugMe
20
-
21
- require 'awesome_print'
22
-
9
+ # System Libraries
23
10
  require 'pathname'
11
+ require 'erb'
12
+ require 'yaml'
13
+
14
+ # Third-party gems
15
+ require 'configatron'
24
16
  require 'nenv'
17
+ require 'parseconfig'
25
18
  require 'slop'
26
19
 
27
20
  # Example Custom Type for Slop
@@ -48,288 +41,269 @@ module Slop
48
41
  end
49
42
  end # module Slop
50
43
 
51
- $cli = 'a place holder'
52
- $errors = []
53
- $warnings = []
54
-
55
- $options = {
56
- version: '0.0.1',# the version of this program
57
- arguments: [], # whats left after options and parameters are extracted
58
- verbose: false,
59
- debug: false,
60
- help: false,
61
- user_name: Nenv.user || Nenv.user_name || Nenv.logname || 'Dewayne VanHoozer',
62
- me: Pathname.new(required_by_filename).realpath,
63
- home_path: Pathname.new(Nenv.home)
64
- }
65
-
66
- $options[:my_dir] = $options[:me].parent
67
- $options[:my_name] = $options[:me].basename.to_s
68
-
69
- # Return full pathname of program
70
- def me
71
- $options[:me]
72
- end
73
-
74
- # Returns the basename of the program as a string
75
- def my_name
76
- $options[:my_name]
77
- end
78
-
79
- # Returns the version of the program as a string
80
- def version
81
- $options[:version]
82
- end
83
-
84
- # Invoke Slop with common CLI parameters and custom
85
- # parameters provided via a block. Create '?'
86
- # for all boolean parameters that have a '--name' flag form.
87
- # Returns a Slop::Options object
88
- def cli_helper(my_banner='')
89
- param = Slop::Options.new
90
-
91
- if my_banner.empty?
92
- param.banner = "Usage: #{my_name} [options] ..."
93
- else
94
- param.banner = my_banner
95
- param.separator "\nUsage: #{my_name} [options] ..."
44
+ module CliHelper
45
+
46
+ DEFAULTS = {
47
+ version: '0.0.1',# the version of this program
48
+ arguments: [], # whats left after options and parameters are extracted
49
+ verbose: false,
50
+ debug: false,
51
+ help: false,
52
+ support_config_files: false,
53
+ disable_help: false,
54
+ disable_debug: false,
55
+ disable_verbose: false,
56
+ disable_version: false,
57
+ suppress_errors: false,
58
+ user_name: Nenv.user || Nenv.user_name || Nenv.logname || 'The Unknown Programmer',
59
+ home_path: Pathname.new(Nenv.home),
60
+ cli: 'a place holder for the Slop object',
61
+ errors: [],
62
+ warnings: []
63
+ }
64
+
65
+ configatron.configure_from_hash DEFAULTS
66
+
67
+ configatron.required_by_filename = caller.last.split(':').first
68
+ configatron.me = Pathname.new(configatron.required_by_filename).realpath
69
+ configatron.my_dir = Pathname.new(configatron.required_by_filename).realpath.parent
70
+ configatron.my_name = Pathname.new(configatron.required_by_filename).realpath.basename.to_s
71
+
72
+
73
+ # Return full pathname of program
74
+ def me
75
+ configatron.me
96
76
  end
97
77
 
98
- param.separator "\nWhere:"
99
- param.separator " Common Options Are:"
78
+ # Returns the basename of the program as a string
79
+ def my_name
80
+ configatron.my_name
81
+ end
100
82
 
101
- param.bool '-h', '--help', 'show this message'
102
- param.bool '-v', '--verbose', 'enable verbose mode'
103
- param.bool '-d', '--debug', 'enable debug mode'
83
+ # Returns the version of the program as a string
84
+ def version
85
+ configatron.version
86
+ end
104
87
 
105
- param.on '--version', "print the version: #{$options[:version]}" do
106
- puts $options[:version]
107
- exit
88
+ def cli_helper_process_erb(file_contents)
89
+ erb_contents = ERB.new(file_contents).result
90
+ return erb_contents
108
91
  end
109
92
 
110
- param.separator " Program Options Are:"
93
+ def cli_helper_process_yaml(file_contents='')
94
+ a_hash = YAML.load file_contents
95
+ return a_hash
96
+ end
111
97
 
112
- yield(param) if block_given?
98
+ def cli_helper_process_ini(file_path, file_contents='')
99
+ # FIXME: mod the parseconfig gem to use a parse method on strings
100
+ an_ini_object = ParseConfig.new(file_path)
101
+ return an_ini_object.params
102
+ end
113
103
 
114
- parser = Slop::Parser.new(param)
115
- $cli = parser.parse(ARGV)
104
+ # Invoke Slop with common CLI parameters and custom
105
+ # parameters provided via a block. Create '?'
106
+ # for all boolean parameters that have a '--name' flag form.
107
+ # Returns a Slop::Options object
108
+ def cli_helper(my_banner='')
109
+ param = Slop::Options.new
116
110
 
117
- $options.merge!($cli.to_hash)
118
- $options[:arguments] = $cli.arguments
111
+ if my_banner.empty?
112
+ param.banner = "Usage: #{my_name} [options] ..."
113
+ else
114
+ param.banner = my_banner
115
+ param.separator "\nUsage: #{my_name} [options] ..."
116
+ end
119
117
 
118
+ param.separator "\nWhere:"
120
119
 
121
- bools = param.options.select do |o|
122
- o.is_a? Slop::BoolOption
123
- end.select{|o| o.flags.select{|f|f.start_with?('--')}}.
124
- map{|o| o.flags.last.gsub('--','')} # SMELL: depends on convention
120
+ if configatron.disable_help &&
121
+ configatron.disable_verbose &&
122
+ configatron.disable_debug &&
123
+ configatron.disable_version
124
+ # NOOP
125
+ else
126
+ param.separator "\n Common Options Are:"
127
+ end
125
128
 
126
- bools.each do |m|
127
- s = m.to_sym
128
- define_method(m+'?') do
129
- $options[s]
130
- end unless self.respond_to?(m+'?')
131
- define_method(m+'!') do
132
- $options[s] = true
133
- end unless self.respond_to?(m+'!')
134
- end
129
+ unless configatron.disable_help
130
+ param.bool '-h', '--help', 'show this message'
131
+ end
135
132
 
136
- if help?
137
- show_usage
138
- exit
139
- end
133
+ unless configatron.disable_verbose
134
+ param.bool '-v', '--verbose', 'enable verbose mode'
135
+ end
140
136
 
141
- return param
142
- end # cli_helper
143
-
144
- # Returns the usage/help information as a string
145
- def usage
146
- a_string = $cli.to_s + "\n"
147
- a_string += HELP + "\n" if defined?(HELP)
148
- return a_string
149
- end
150
-
151
- # Prints to STDOUT the usage/help string
152
- def show_usage
153
- puts usage()
154
- end
155
-
156
-
157
- # Returns an array of valid files of one type
158
- def get_pathnames_from(an_array, extnames=['.json', '.txt', '.docx'])
159
- an_array = [an_array] unless an_array.is_a? Array
160
- extnames = [extnames] unless extnames.is_a? Array
161
- extnames = extnames.map{|e| e.downcase}
162
- file_array = []
163
- an_array.each do |a|
164
- pfn = Pathname.new(a)
165
- if pfn.directory?
166
- file_array << get_pathnames_from(pfn.children, extnames)
167
- else
168
- file_array << pfn if pfn.exist? && extnames.include?(pfn.extname.downcase)
137
+ unless configatron.disable_debug
138
+ param.bool '-d', '--debug', 'enable debug mode'
169
139
  end
170
- end
171
- return file_array.flatten
172
- end # def get_pathnames_from(an_array, extname='.json')
173
-
174
-
175
- # Display global warnings and errors arrays and exit if necessary
176
- def abort_if_errors
177
- unless $warnings.empty?
178
- STDERR.puts
179
- STDERR.puts "The following warnings were generated:"
180
- STDERR.puts
181
- $warnings.each do |w|
182
- STDERR.puts "\tWarning: #{w}"
140
+
141
+ unless configatron.disable_version
142
+ param.on '--version', "print the version: #{configatron.version}" do
143
+ puts configatron.version
144
+ exit
145
+ end
183
146
  end
184
- STDERR.print "\nAbort program? (y/N) "
185
- answer = (STDIN.gets).chomp.strip.downcase
186
- $errors << "Aborted by user" if answer.size>0 && 'y' == answer[0]
187
- $warnings = []
188
- end
189
- unless $errors.empty?
190
- STDERR.puts
191
- STDERR.puts "Correct the following errors and try again:"
192
- STDERR.puts
193
- $errors.each do |e|
194
- STDERR.puts "\t#{e}"
147
+
148
+ param.separator "\n Program Options Are:"
149
+
150
+ yield(param) if block_given?
151
+
152
+ if configatron.support_config_files
153
+ param.paths '--config', 'read config file(s) [*.rb, *.yml, *.ini]'
154
+ end
155
+
156
+ parser = Slop::Parser.new(param, suppress_errors: configatron.suppress_errors)
157
+ configatron.cli = parser.parse(ARGV)
158
+
159
+ # TODO: DRY this conditional block
160
+ if configatron.support_config_files
161
+
162
+ configatron.cli[:config].each do |cf|
163
+ unless cf.exist? || cf.directory?
164
+ error "Config file is missing: #{cf}"
165
+ else
166
+ file_type = case cf.extname.downcase
167
+ when '.rb'
168
+ :ruby
169
+ when '.yml', '.yaml'
170
+ :yaml
171
+ when '.ini', '.txt'
172
+ :ini
173
+ when '.erb'
174
+ extname = cf.basename.to_s.downcase.gsub('.erb','').split('.').last
175
+ if %w[ yml yaml].include? extname
176
+ :yaml
177
+ elsif %w[ ini txt ].include? extname
178
+ :ini
179
+ elsif 'rb' == extname
180
+ raise 'MakesNoSenseToMe: *.rb.erb is not supported'
181
+ else
182
+ :unknown
183
+ end
184
+ else
185
+ :unknown
186
+ end
187
+
188
+ case file_type
189
+ when :ruby
190
+ load cf
191
+ when :yaml
192
+ configatron.configure_from_hash(
193
+ config_file_hash = configatron.configure_from_hash(
194
+ cli_helper_process_yaml(
195
+ cli_helper_process_erb(cf.read)
196
+ )
197
+ )
198
+ )
199
+ when :ini
200
+ configatron.configure_from_hash(
201
+ configatron.configure_from_hash(
202
+ cli_helper_process_ini( cf # FIXME: fork parseconfig
203
+ # cli_helper_process_erb(cf.read)
204
+ )
205
+ )
206
+ )
207
+ else
208
+ error "Do not know how to parse this file: #{cf}"
209
+ end # case type_type
210
+ end # unless cf.exist? || cf.directory?
211
+ end # configatron.cli.config.each do |cf|
212
+ end # if configatron.support_config_files
213
+
214
+ configatron.configure_from_hash(configatron.cli.to_hash)
215
+ configatron.arguments = configatron.cli.arguments
216
+
217
+ bools = param.options.select do |o|
218
+ o.is_a? Slop::BoolOption
219
+ end.select{|o| o.flags.select{|f|f.start_with?('--')}}.
220
+ map{|o| o.flags.last.gsub('--','')} # SMELL: depends on convention
221
+
222
+ bools.each do |m|
223
+ s = m.to_sym
224
+ define_method(m+'?') do
225
+ configatron[s]
226
+ end unless self.respond_to?(m+'?')
227
+ define_method((m+'!').to_sym) do
228
+ configatron[s] = true
229
+ end unless self.respond_to?(m+'!')
195
230
  end
196
- STDERR.puts
197
- exit(-1)
231
+
232
+
233
+ if self.respond_to?(:help?) && help?
234
+ show_usage
235
+ exit
236
+ end
237
+
238
+ return param
239
+ end # def cli_helper
240
+
241
+ # Returns the usage/help information as a string
242
+ def usage
243
+ a_string = configatron.cli.to_s + "\n"
244
+ a_string += HELP + "\n" if defined?(HELP)
245
+ return a_string
198
246
  end
199
- end # def abort_if_errors
200
-
201
- # Adds a string to the global $errors array
202
- def error(a_string)
203
- $errors << a_string
204
- end
205
-
206
- # Adds a string to the global $warnings array
207
- def warning(a_string)
208
- $warnings << a_string
209
- end
210
-
211
-
212
- __END__
213
- ################################################
214
- ## Here is how it works
215
-
216
- Test '000 supports basic common parameters' do
217
- params = cli_helper
218
- assert params.is_a? Slop::Options
219
- assert usage.include?('--help')
220
- assert usage.include?('--debug')
221
- assert usage.include?('--verbose')
222
- assert usage.include?('--version')
223
- refute usage.include?('--xyzzy')
224
- end
225
-
226
- =begin
227
- # NOTE: The Test construct creates a dynamic class which
228
- # does not incorporate 'define_method' This Test results
229
- # in errors that are a consequence of the testing framework
230
- # not the object under test.
231
- Test '002 creates accessor methods to boolean options' do
232
- cli_helper
233
- all_methods = methods
234
- %w[ help? debug? verbose? version?
235
- help! debug! verbose! version!].each do |m|
236
- assert all_methods.include?(m)
247
+
248
+ # Prints to STDOUT the usage/help string
249
+ def show_usage
250
+ puts usage()
237
251
  end
238
- refute all_methods.include?('xyzzy?')
239
- refute all_methods.include?('xyzzy!')
240
- end
241
- =end
242
-
243
- Test '005 block inclusion' do
244
- cli_helper do |param|
245
- param.string '-x', '--xyxxy', 'example MAGIC parameter', default: 'IamDefault'
252
+
253
+
254
+ # Returns an array of valid files of one type
255
+ def get_pathnames_from(an_array, extnames=['.json', '.txt', '.docx'])
256
+ an_array = [an_array] unless an_array.is_a? Array
257
+ extnames = [extnames] unless extnames.is_a? Array
258
+ extnames = extnames.map{|e| e.downcase}
259
+ file_array = []
260
+ an_array.each do |a|
261
+ pfn = Pathname.new(a)
262
+ if pfn.directory?
263
+ file_array << get_pathnames_from(pfn.children, extnames)
264
+ else
265
+ file_array << pfn if pfn.exist? && extnames.include?(pfn.extname.downcase)
266
+ end
267
+ end
268
+ return file_array.flatten
269
+ end # def get_pathnames_from(an_array, extname='.json')
270
+
271
+
272
+ # Display global warnings and errors arrays and exit if necessary
273
+ def abort_if_errors
274
+ unless configatron.warnings.empty?
275
+ STDERR.puts
276
+ STDERR.puts "The following warnings were generated:"
277
+ STDERR.puts
278
+ configatron.warnings.each do |w|
279
+ STDERR.puts "\tWarning: #{w}"
280
+ end
281
+ STDERR.print "\nAbort program? (y/N) "
282
+ answer = (STDIN.gets).chomp.strip.downcase
283
+ configatron.errors << "Aborted by user" if answer.size>0 && 'y' == answer[0]
284
+ configatron.warnings = []
285
+ end
286
+ unless configatron.errors.empty?
287
+ STDERR.puts
288
+ STDERR.puts "Correct the following errors and try again:"
289
+ STDERR.puts
290
+ configatron.errors.each do |e|
291
+ STDERR.puts "\t#{e}"
292
+ end
293
+ STDERR.puts
294
+ exit(-1)
295
+ end
296
+ end # def abort_if_errors
297
+
298
+ # Adds a string to the global $errors array
299
+ def error(a_string)
300
+ configatron.errors << a_string
246
301
  end
247
- assert usage.include?('MAGIC')
248
- end
249
-
250
- Test '010 supports banner' do
251
- refute usage().include?('BANNER')
252
- cli_helper('This is my BANNER')
253
- assert usage().include?('BANNER')
254
- end
255
-
256
- Test '015 supports additional help in usage' do
257
- refute usage.include?('HELP')
258
- HELP = "Do you need some HELP?"
259
- assert usage.include?('HELP')
260
- end
261
-
262
- Test '020 put it all together' do
263
- cli_helper('This is my BANNER') do |o|
264
- o.string '-x', '--xyxxy', 'example MAGIC parameter', default: 'IamDefault'
302
+
303
+ # Adds a string to the global $warnings array
304
+ def warning(a_string)
305
+ configatron.warnings << a_string
265
306
  end
266
- HELP = "Do you need some HELP?"
267
- assert usage.include?('BANNER')
268
- assert usage.include?('MAGIC')
269
- assert usage.include?('HELP')
270
- end
271
-
272
- Test '025 Add to $errors' do
273
- assert $errors.empty?
274
- a_message = 'There is a serious problem here'
275
- error a_message
276
- refute $errors.empty?
277
- assert_equal 1, $errors.size
278
- assert_equal a_message, $errors.first
279
- end
280
-
281
- Test '030 Add to $warnings' do
282
- assert $warnings.empty?
283
- a_message = 'There is a minor problem here'
284
- warning a_message
285
- refute $warnings.empty?
286
- assert_equal 1, $warnings.size
287
- assert_equal a_message, $warnings.first
288
- end
289
-
290
- Test '035 Add to $errors' do
291
- refute $errors.empty?
292
- a_message = 'There is another serious problem here'
293
- error a_message
294
- assert_equal 2, $errors.size
295
- assert_equal a_message, $errors.last
296
- end
297
-
298
- Test '040 Add to $warnings' do
299
- refute $warnings.empty?
300
- a_message = 'There is a another minor problem here'
301
- warning a_message
302
- assert_equal 2, $warnings.size
303
- assert_equal a_message, $warnings.last
304
- end
305
-
306
-
307
-
308
-
309
-
310
- Test '999 prints usage()' do
311
- puts
312
- puts "="*45
313
- show_usage
314
- puts "="*45
315
- puts
316
- a_string = <<EOS
317
- This is my BANNER
318
-
319
- Usage: cli_helper.rb [options] ...
320
-
321
- Where:
322
- Common Options Are:
323
- -h, --help show this message
324
- -v, --verbose enable verbose mode
325
- -d, --debug enable debug mode
326
- --version print the version: 0.0.1
327
- Program Options Are:
328
- -x, --xyxxy example MAGIC parameter
329
-
330
- Do you need some HELP?
331
- EOS
332
-
333
- assert_equal a_string, usage
334
- end
307
+
308
+ end # module CliHelper
335
309
 
data/tests/README.txt ADDED
@@ -0,0 +1,18 @@
1
+ The minitest framework depends upon pry.
2
+
3
+ HOWEVER, pry currently requires an older version
4
+ of Slop. CliHelper is based upon version 4+ of Slop;
5
+ When pry/minitest gets updated, I will un update the
6
+ test suite for full automation.
7
+
8
+ For now the test file is more manual. Run tests like
9
+ the following from the command line:
10
+
11
+ ```bash
12
+ ./cli_helper_test.rb --config config/sample.ini,config/sample.ini.erb
13
+ ./cli_helper_test.rb --config config/sample.rb,config/sample.rb.erb
14
+ ./cli_helper_test.rb --config config/sample.txt,config/sample.txt.erb
15
+ ./cli_helper_test.rb --config config/sample.yml,config/sample.yml.erb
16
+ ```
17
+
18
+ The test with config/sample.rb.erb with raise a MakesNoSenseToMe exception.