cmdline 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/cmdline.rb ADDED
@@ -0,0 +1,251 @@
1
+
2
+
3
+ class CommandLine
4
+
5
+ FLAG_1=0
6
+ FLAG_2=1
7
+ ACCESSOR=2
8
+ DISP_NAME=3
9
+ REQUIRED=4
10
+ DEFAULT=5
11
+ DOC=6
12
+ CHECK=7
13
+
14
+ @@add_help=true
15
+
16
+
17
+
18
+ def self.add_help= bool
19
+ @@add_help=bool
20
+ end
21
+
22
+
23
+
24
+ # definition
25
+ # [ :command, nil, <accessor>, <display name>, <required?>, <default>, <doc>, <check allowed commands> ]
26
+ # command is a subcommand, cf. `svn help`,
27
+ # [ <flag1>, <flag2/nil>, <accessor>, <display name>, <required?>, <default>, <doc>, <check: optional> ]
28
+ #
29
+ # commandline taking arguments, e.g. `mv src target` are specified like this:
30
+ # [ :args, nil, <accessor>, <display name>, <required>, <default>, <doc>, <check: optional> ]
31
+ # the entire rest of the commandline arg array after the first unrecognized options
32
+ # will then be available under `cmdline.<accessor>` the check proc will either be able to check the entire
33
+ # array or, if that fails with an exception, will test each element individually.
34
+ def initialize definition
35
+ self.definition= definition
36
+ @output_io ||= STDERR
37
+ @exit_on_usage=true
38
+
39
+ end
40
+
41
+ def output= io
42
+ @output_io = io
43
+ end
44
+
45
+ # whether `exit` will be called to terminate the program if `usage` is
46
+ # called. Default behaviour is to call `exit`
47
+ # If this behaviour is turned off, a call to usage will result in an exception
48
+ # instead.
49
+ def exit_on_usage= bool
50
+ @exit_on_usage= bool
51
+ end
52
+
53
+ def definition= definition
54
+ definition.push(["-h", "--help", :help, false, false, nil, "print this message"]) if @@add_help
55
+ cl = class << self; self; end
56
+ # add an accessor to self for each definition.
57
+ cl.instance_eval { attr_accessor *definition.map{|arg_def| arg_def[ACCESSOR]} }
58
+
59
+
60
+ definition.each {|arg_def|
61
+ #check if cmdline takes a command
62
+ if arg_def[FLAG_1]==:command
63
+ @has_command = true
64
+ end
65
+ #set default values
66
+ set arg_def[ACCESSOR], arg_def[DEFAULT]
67
+ }
68
+
69
+ @definition=definition
70
+
71
+ class << @definition
72
+ def retrieve_flag flag
73
+ find { |arg|
74
+ arg[FLAG_1]==flag || arg[FLAG_2]==flag
75
+ }
76
+ end
77
+ end
78
+
79
+ end # definition
80
+
81
+ def usage mes=""
82
+ raise mes unless @exit_on_usage
83
+
84
+
85
+ # put together usage information for flags.
86
+ max = 0 #max flag length for formatting
87
+ has_required=false
88
+ has_options=false
89
+ us = @definition.map {|arg_def|
90
+ if arg_def[FLAG_1] == :command
91
+ flag=:command
92
+ elsif arg_def[FLAG_1] == :args
93
+ flag=:args
94
+ else
95
+ # create a usage string of the form:
96
+ # -f/-flag <value>* must start with a number
97
+ # for each definition. (commands and args are treated seperately)
98
+ flag = "#{arg_def[FLAG_1]}"
99
+ flag << "/#{arg_def[FLAG_2]}" if arg_def[FLAG_2]
100
+ flag << " <#{arg_def[DISP_NAME]}>" if arg_def[DISP_NAME]
101
+ flag << "*" if arg_def[REQUIRED]
102
+ has_required = true if arg_def[REQUIRED]
103
+ has_options = true
104
+ max = max > flag.length ? max : flag.length
105
+ end
106
+ [flag, arg_def[DOC]]
107
+ }
108
+
109
+ usage = "usage: #{$0}"
110
+
111
+ if command=@definition.retrieve_flag(:command)
112
+ fmt = command[REQUIRED] ? " %s" : " [%s]"
113
+ usage << sprintf(fmt,command[DISP_NAME])
114
+ end
115
+
116
+ if has_options
117
+ usage << (has_required ? " options" : " [options]")
118
+ end
119
+
120
+ args_doc=false
121
+ if command=@definition.retrieve_flag(:args)
122
+ fmt = command[REQUIRED] ? " %s" : " [%s]"
123
+ usage << sprintf(fmt,command[DISP_NAME])
124
+ args_doc = "#{command[DISP_NAME]}: #{command[DOC]}"
125
+ end
126
+ usage << "\n"
127
+
128
+ us.each { |arg_def|
129
+ if arg_def[0].kind_of? String
130
+ usage << sprintf(" %-#{max}s %s\n", arg_def[0], arg_def[1])
131
+ elsif arg_def[0] == :command
132
+ # command
133
+ usage << arg_def[1] if arg_def[1]
134
+ end
135
+
136
+ }
137
+ @output_io.puts usage
138
+ @output_io.puts "* required flags" if has_required
139
+ @output_io.puts "\n#{args_doc}" if args_doc
140
+ @output_io.puts
141
+ @output_io.puts mes
142
+ exit
143
+ end
144
+
145
+ def parse args=ARGV
146
+ @found = []
147
+ i=0
148
+ # handle svn like command
149
+ if definition = @definition.retrieve_flag(:command)
150
+
151
+ if definition[REQUIRED] && args.length==0
152
+ usage "missing mandatory command"
153
+ elsif test_def = @definition.retrieve_flag(args[i])
154
+ usage "missing mandatory command" if definition[REQUIRED]
155
+ else
156
+
157
+ check definition, args[i]
158
+ set definition[ACCESSOR], args[i]
159
+
160
+ i+=1
161
+ end
162
+
163
+ end
164
+
165
+ while i<args.length do
166
+ @found.push args[i]
167
+ if definition = @definition.retrieve_flag(args[i]) # is there a definition for this flag?
168
+ if definition[DISP_NAME]
169
+ # takes a parameter
170
+ check definition, args[i+=1]
171
+ set definition[ACCESSOR], args[i]
172
+ else
173
+ # plain flag
174
+ set definition[ACCESSOR], true
175
+ end
176
+ else # are unknown flags ok? i.e. is there an :args definition.
177
+ if definition = @definition.retrieve_flag(:args)
178
+ check_args definition, args[i, args.length-1]
179
+ set definition[ACCESSOR], args[i, args.length-1]
180
+ break
181
+ end
182
+ usage "unknown flag: #{args[i]}"
183
+ end
184
+ i+=1
185
+ end
186
+
187
+ if definition = @definition.retrieve_flag(:args) # are :args required?
188
+ if definition[REQUIRED]
189
+ args = self.send definition[ACCESSOR]
190
+ usage "missing mandatory args" unless args && args.length>1
191
+ end
192
+ end
193
+
194
+ usage if self.help # call usage if the -h/--help flag was set.
195
+
196
+ # check all mandatory args are present.
197
+ @definition.each {|definition|
198
+
199
+ if definition[REQUIRED] && !([:command, :args].include? definition[FLAG_1])
200
+ usage "missing mandatory flag #{definition [FLAG_1]?definition[FLAG_1]:definition[FLAG_2]}" unless ((@found.include? definition[FLAG_1]) || (@found.include? definition[FLAG_2]))
201
+ end
202
+ }
203
+ end
204
+
205
+ private
206
+
207
+ def set sym, value
208
+ self.send((sym.to_s+"=").to_sym, value)
209
+ end
210
+
211
+ #
212
+ # check the argument's value against allowed values,
213
+ # check may be a Regexp, an Array or a Proc taking the value.
214
+ #
215
+ def check definition, val
216
+ check=definition[CHECK]
217
+ return true unless check
218
+ if check.kind_of? Regexp
219
+ if !check.match val
220
+ usage "illegal value: #{val} for: #{definition[FLAG_1]}"
221
+ end
222
+ elsif check.kind_of? Proc
223
+ usage "illegal value: #{val} for: #{definition[FLAG1]}" unless definition[CHECK].call val
224
+ elsif check.kind_of? Array
225
+ usage "illegal value: #{val} for: #{definition[FLAG1]}" unless definition[CHECK].include? val
226
+ end
227
+
228
+ return true
229
+ end
230
+
231
+ def check_args definition, arr
232
+ ret = false
233
+ # might be a proc to check the entire array
234
+ if definition[CHECK].kind_of? Proc
235
+ begin
236
+ return definition[CHECK].call(arr)
237
+ rescue
238
+ end
239
+ end
240
+ # or something else to check each arg against
241
+ unless ret
242
+ arr.each {|val|
243
+ ret= check definition, val
244
+ return false unless ret
245
+ }
246
+ end
247
+ return ret
248
+ end
249
+
250
+ end
251
+
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.2
3
+ specification_version: 1
4
+ name: cmdline
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.0
7
+ date: 2007-05-10 00:00:00 +02:00
8
+ summary: "cmdline: Yet Another Command Line Tool"
9
+ require_paths:
10
+ - lib
11
+ email:
12
+ homepage:
13
+ rubyforge_project:
14
+ description: Library used to handle command line arguments.
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: false
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors: []
30
+
31
+ files:
32
+ - lib/cmdline.rb
33
+ - examples/example.rb
34
+ - examples/long_example.rb
35
+ - examples/plain_args_example.rb
36
+ - examples/regexp_example.rb
37
+ - examples/subcommand_example.rb
38
+ - AUTHORS
39
+ - CHANGELOG
40
+ - COPYING
41
+ - LICENSE
42
+ - Rakefile
43
+ - README
44
+ test_files: []
45
+
46
+ rdoc_options: []
47
+
48
+ extra_rdoc_files: []
49
+
50
+ executables: []
51
+
52
+ extensions: []
53
+
54
+ requirements:
55
+ - none
56
+ dependencies: []
57
+