cli_helper 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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.