| Class | Command::Definition |
| In: |
lib/command/definition.rb
|
| Parent: | Object |
| RequiredOptionArgument | = | /[A-Z][A-Z_]*/ |
| OptionArgument | = | /\[#{RequiredOptionArgument}\]|#{RequiredOptionArgument}/ |
| ShortOption | = | /\A-[A-Za-z](?: #{OptionArgument})?\z/ |
| NegationSequence | = | /\[(?:no-|with-|without-)\]/ |
| LongOption | = | /\A-- (?: #{NegationSequence}?[A-Za-z][A-Za-z0-9_-]* | [A-Za-z][A-Za-z0-9_-]*#{NegationSequence}[A-Za-z0-9][A-Za-z0-9_-] ) (?:\x20#{OptionArgument})?\z /x |
| argument_position | [R] | |
| arguments | [R] | |
| arguments_by_name | [R] | |
| commands_by_name | [R] | |
| default_command | [R] | |
| default_options | [R] | |
| env_by_variable | [R] | |
| options_by_flag | [R] | |
| options_by_name | [R] | |
| parent | [R] |
# File lib/command/definition.rb, line 23
23: def self.create_argument(*args)
24: name = Symbol === args.first && args.shift
25: usage = args.shift
26: bare = usage[/\w+/]
27: type = Symbol === args.first && args.shift
28: description = args.shift
29:
30: Argument.new(name, bare, usage, type, description)
31: end
valid arguments:
name # --> copy from parent name, short[, long][, type][, description] name, long[, type][, description]
short can be
where ? is any of A-Za-z examples:
long can be
where ? is [A-Za-z0-9][A-Za-z0-9-_]* It may contain a negation sequence, which is one of ’[no-]’, ’[with-]’, ’[without-]’ examples:
Only one of short and long may have the argument declared. Usually you‘ll have the argument in long and only have it in short if there‘s no long at all.
type can be
Exceptions (incomplete):
# File lib/command/definition.rb, line 82
82: def self.create_option(name, *args)
83: case args.first when nil, /\A-[^- ]/ then
84: short = args.shift
85: end
86: case args.first when nil, /\A--[^- ]/ then
87: long = args.shift
88: end
89: case args.first when nil, Symbol then
90: type = args.shift
91: end
92: declaration = short ? [short,long].compact.join(", ") : " #{long}"
93: description = args.shift
94:
95: raise ArgumentError, "Too many arguments" unless args.empty?
96: raise ArgumentError, "Invalid short declaration: #{short.inspect}" unless (short.nil? || short =~ ShortOption)
97: raise ArgumentError, "Invalid long declaration: #{long.inspect}" unless (long.nil? || long =~ LongOption)
98: raise ArgumentError, "Argument declaration must only be in one of short and long" if (short && long && short =~ /\s/ && long =~ /\s/)
99:
100: necessity = :none
101: extract_argument = nil
102: extract_argument = short if short =~ /\s/
103: extract_argument = long if long =~ /\s/
104: if extract_argument then
105: flag, *argument = extract_argument.split(/ /)
106: extract_argument.replace(flag) # long/short should only contain the flag, not the argument declaration as well
107: raise ArgumentError, "Multiple arguments for an option not yet supported" if argument.size > 1
108: if argument.empty?
109: necessity = :none
110: elsif argument.first =~ /\A\[.*\]\z/ then
111: necessity = :optional
112: else
113: necessity = :required
114: end
115: end
116:
117: negated = nil
118: if long =~ NegationSequence then
119: negated = long.delete('[]')
120: long = long.gsub(NegationSequence, '')
121: end
122:
123: Option.new(name, short, long, negated, necessity, type, declaration, description)
124: end
# File lib/command/definition.rb, line 138
138: def initialize(parent=nil, default_command=nil, default_options={}, &block)
139: @default_command = default_command
140: @default_options = DecoratingHash.new(@parent && @parent.default_options).update(default_options)
141: @elements = []
142: @parent = parent
143: @arguments_by_name = DecoratingHash.new(@parent && @parent.arguments_by_name)
144: @options_by_name = DecoratingHash.new(@parent && @parent.options_by_name)
145: @options_by_flag = DecoratingHash.new(@parent && @parent.options_by_flag)
146: @commands_by_name = DecoratingHash.new(@parent && @parent.commands_by_name)
147: @env_by_variable = DecoratingHash.new(@parent && @parent.env_by_variable)
148: @argument_position = {}
149: @text = []
150: @placeholders = {}
151: @content_for = [@elements]
152: instance_eval(&block) if block
153: end
# File lib/command/definition.rb, line 155
155: def [](command)
156: command ? @commands_by_name[command] : self
157: end
# File lib/command/definition.rb, line 216
216: def argument(*args)
217: unless @argument_position[args.first]
218: @argument_position[args.first] = @argument_position.size
219: end
220:
221: if args.size == 1 then
222: argument = @arguments_by_name[args.first]
223: raise ArgumentError, "No argument with name #{args.first.inspect} in any parent found." unless argument
224: else
225: argument = self.class.create_argument(*args)
226: @arguments_by_name[argument.name] = argument
227: end
228: @content_for.last << argument
229:
230: argument
231: end
# File lib/command/definition.rb, line 288
288: def command(*args, &block)
289: definition = Definition.new(self, *args, &block)
290: @commands_by_name[args.first] = definition
291: @content_for.last << definition
292: end
# File lib/command/definition.rb, line 159
159: def content_for(placeholder)
160: @placeholders[placeholder] ||= []
161: @content_for << @placeholders[placeholder]
162: yield(self)
163: @content_for.pop
164: end
# File lib/command/definition.rb, line 282
282: def env_option(name, variable)
283: env = Env.new(name, variable)
284: @env_by_variable[variable] = env
285: @content_for.last << env
286: end
# File lib/command/definition.rb, line 246
246: def option(*args)
247: if args.size == 1 then
248: inherited_option = @options_by_name[args.first]
249: raise ArgumentError, "No inherited option #{args.first.inspect}" unless inherited_option
250: @content_for.last << inherited_option
251:
252: inherited_option
253: else
254: option = self.class.create_option(*args)
255:
256: @options_by_name[option.name] = option
257: @options_by_flag[option.short] = option
258: @options_by_flag[option.long] = option
259: @options_by_flag[option.negated] = option
260: @content_for.last << option
261:
262: option
263: end
264: end
# File lib/command/definition.rb, line 278
278: def placeholder(identifier)
279: @content_for.last << identifier
280: end
# File lib/command/definition.rb, line 267
267: def text(*args)
268: if args.size == 2 then
269: indent, text = *args
270: text = text.gsub(/^/, indent)
271: else
272: text = args.first
273: end
274: @text << text
275: @content_for.last << text
276: end
# File lib/command/definition.rb, line 166
166: def usage_text(elements=@elements)
167: longest_arg_bare = elements.grep(Argument).max { |a,b|
168: a.bare.size <=> b.bare.size
169: }
170: longest_option = elements.grep(Option).max { |a,b|
171: a.declaration.size <=> b.declaration.size
172: }
173: longest_env_name = elements.grep(Env).max { |a,b|
174: a.variable.size <=> b.variable.size
175: }
176: longest_arg_bare = longest_arg_bare && longest_arg_bare.bare.size
177: longest_option = longest_option && longest_option.declaration.size
178: longest_env_name = longest_env_name && longest_env_name.variable.size
179: arguments = elements.grep(Argument)
180:
181: elements.map { |e|
182: case e
183: when :usage
184: "Usage: #{File.basename($0)} #{arguments.map{|a|a.usage}.join(' ')}\n"
185: when Symbol # placeholder
186: usage_text(@placeholders[e])
187: when Option
188: sprintf " %*s%s\n",
189: -(longest_option+2),
190: e.declaration,
191: e.description
192: when Env
193: sprintf "* %*s%s\n",
194: -longest_env_name-2,
195: e.variable,
196: @options_by_name[e.name].description
197: when String
198: e+"\n"
199: when Argument
200: indent = "\n "+(" "*longest_arg_bare)
201: sprintf " %*s%s\n",
202: -(longest_arg_bare+3),
203: "#{e.bare}:",
204: e.description.to_s.gsub(/\n/, indent)
205: when Definition
206: else
207: "unimplemented(#{e.class})"
208: end
209: }.join('')
210: end
# File lib/command/definition.rb, line 233
233: def virtual_argument(*args)
234: if args.size == 1 then
235: argument = @arguments_by_name[args.first]
236: raise ArgumentError, "No argument with name #{args.first.inspect} in any parent found." unless argument
237: else
238: argument = self.class.create_argument(*args)
239: @arguments_by_name[argument.name] = argument
240: end
241:
242: @content_for.last << argument
243: argument
244: end