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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
require 'set'
class Option
include Comparable
attr_reader :name, :description, :flag
def initialize(name, description=nil)
@name, @flag = split_name(name)
@description = description.to_s
end
def to_s
flag
end
alias_method :to_str, :to_s
def <=>(other)
name <=> other.name
end
def eql?(other)
instance_of?(other.class) && name == other.name
end
def hash
name.hash
end
def inspect
"#<#{self.class}: #{flag.inspect}>"
end
private
def split_name(name)
case name
when /^[a-zA-Z]$/
[name, "-#{name}"]
when /^-[a-zA-Z]$/
[name[1..1], name]
when /^--(.+)$/
[$1, name]
else
[name, "--#{name}"]
end
end
end
class Options
include Enumerable
attr_reader :options
protected :options
def initialize(*args)
@options = Set.new(*args)
end
def initialize_copy(other)
super
@options = other.options.dup
end
def each(*args, &block)
@options.each(*args, &block)
end
def <<(o)
@options << o
self
end
def +(o)
Options.new(@options + o)
end
def -(o)
Options.new(@options - o)
end
def &(o)
Options.new(@options & o)
end
def *(arg)
@options.to_a * arg
end
def empty?
@options.empty?
end
def as_flags
map(&:flag)
end
def include?(o)
any? { |opt| opt == o || opt.name == o || opt.flag == o }
end
def concat(o)
o.each { |opt| @options << opt }
self
end
def to_a
@options.to_a
end
alias_method :to_ary, :to_a
def inspect
"#<#{self.class}: #{to_a.inspect}>"
end
def self.coerce(arg)
case arg
when self then arg
when Option then new << arg
when Array
opts = new
arg.each do |a|
case a
when /^-[^-]+$/
a[1..-1].split(//).each { |o| opts << Option.new(o) }
else
opts << Option.new(a)
end
end
opts
else
raise TypeError, "Cannot convert #{arg.inspect} to Options"
end
end
end
|