1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
class Puppet::String::Option
attr_reader :parent
attr_reader :name
attr_reader :aliases
attr_reader :optparse
attr_accessor :desc
def takes_argument?
!!@argument
end
def optional_argument?
!!@optional_argument
end
def initialize(parent, *declaration, &block)
@parent = parent
@optparse = []
# Collect and sort the arguments in the declaration.
dups = {}
declaration.each do |item|
if item.is_a? String and item.to_s =~ /^-/ then
unless item =~ /^-[a-z]\b/ or item =~ /^--[^-]/ then
raise ArgumentError, "#{item.inspect}: long options need two dashes (--)"
end
@optparse << item
# Duplicate checking...
name = optparse_to_name(item)
if dup = dups[name] then
raise ArgumentError, "#{item.inspect}: duplicates existing alias #{dup.inspect} in #{@parent}"
else
dups[name] = item
end
else
raise ArgumentError, "#{item.inspect} is not valid for an option argument"
end
end
if @optparse.empty? then
raise ArgumentError, "No option declarations found while building"
end
# Now, infer the name from the options; we prefer the first long option as
# the name, rather than just the first option.
@name = optparse_to_name(@optparse.find do |a| a =~ /^--/ end || @optparse.first)
@aliases = @optparse.map { |o| optparse_to_name(o) }
# Do we take an argument? If so, are we consistent about it, because
# incoherence here makes our life super-difficult, and we can more easily
# relax this rule later if we find a valid use case for it. --daniel 2011-03-30
@argument = @optparse.any? { |o| o =~ /[ =]/ }
if @argument and not @optparse.all? { |o| o =~ /[ =]/ } then
raise ArgumentError, "Option #{@name} is inconsistent about taking an argument"
end
# Is our argument optional? The rules about consistency apply here, also,
# just like they do to taking arguments at all. --daniel 2011-03-30
@optional_argument = @optparse.any? { |o| o.include? "[" }
if @optional_argument and not @optparse.all? { |o| o.include? "[" } then
raise ArgumentError, "Option #{@name} is inconsistent about the argument being optional"
end
end
# to_s and optparse_to_name are roughly mirrored, because they are used to
# transform strings to name symbols, and vice-versa.
def to_s
@name.to_s.tr('_', '-')
end
def optparse_to_name(declaration)
unless found = declaration.match(/^-+([^= ]+)/) or found.length != 1 then
raise ArgumentError, "Can't find a name in the declaration #{declaration.inspect}"
end
name = found.captures.first.tr('-', '_')
raise "#{name.inspect} is an invalid option name" unless name.to_s =~ /^[a-z]\w*$/
name.to_sym
end
end
|