scout-gear 1.2.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitmodules +4 -0
- data/.vimproject +604 -2
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/bin/scout +28 -0
- data/lib/scout/indiferent_hash.rb +0 -30
- data/lib/scout/misc/format.rb +227 -0
- data/lib/scout/misc.rb +1 -0
- data/lib/scout/path/find.rb +15 -9
- data/lib/scout/path/util.rb +4 -5
- data/lib/scout/path.rb +13 -7
- data/lib/scout/simple_opt/accessor.rb +54 -0
- data/lib/scout/simple_opt/doc.rb +120 -0
- data/lib/scout/simple_opt/get.rb +57 -0
- data/lib/scout/simple_opt/parse.rb +66 -0
- data/lib/scout/simple_opt/setup.rb +26 -0
- data/lib/scout/simple_opt.rb +5 -0
- data/lib/scout-gear.rb +1 -0
- data/scout-gear.gemspec +15 -3
- data/test/scout/indiferent_hash/test_case_insensitive.rb +16 -0
- data/test/scout/path/test_find.rb +9 -1
- data/test/scout/simple_opt/test_get.rb +11 -0
- data/test/scout/simple_opt/test_parse.rb +10 -0
- data/test/scout/simple_opt/test_setup.rb +77 -0
- metadata +14 -2
@@ -0,0 +1,227 @@
|
|
1
|
+
module Misc
|
2
|
+
COLOR_LIST = %w(#BC80BD #CCEBC5 #FFED6F #8DD3C7 #FFFFB3 #BEBADA #FB8072 #80B1D3 #FDB462 #B3DE69 #FCCDE5 #D9D9D9)
|
3
|
+
|
4
|
+
def self.colors_for(list)
|
5
|
+
unused = COLOR_LIST.dup
|
6
|
+
|
7
|
+
used = {}
|
8
|
+
colors = list.collect do |elem|
|
9
|
+
if used.include? elem
|
10
|
+
used[elem]
|
11
|
+
else
|
12
|
+
color = unused.shift
|
13
|
+
used[elem]=color
|
14
|
+
color
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
[colors, used]
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.format_seconds(time, extended = false)
|
22
|
+
seconds = time.to_i
|
23
|
+
str = [seconds/3600, seconds/60 % 60, seconds % 60].map{|t| "%02i" % t }.join(':')
|
24
|
+
str << ".%02i" % ((time - seconds) * 100) if extended
|
25
|
+
str
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.format_paragraph(text, size = 80, indent = 0, offset = 0)
|
29
|
+
i = 0
|
30
|
+
size = size + offset + indent
|
31
|
+
re = /((?:\n\s*\n\s*)|(?:\n\s*(?=\*)))/
|
32
|
+
text.split(re).collect do |paragraph|
|
33
|
+
i += 1
|
34
|
+
str = if i % 2 == 1
|
35
|
+
words = paragraph.gsub(/\s+/, "\s").split(" ")
|
36
|
+
lines = []
|
37
|
+
line = " "*offset
|
38
|
+
word = words.shift
|
39
|
+
while word
|
40
|
+
word = word[0..size-indent-offset-4] + '...' if word.length >= size - indent - offset
|
41
|
+
while word and Log.uncolor(line).length + Log.uncolor(word).length <= size - indent
|
42
|
+
line << word << " "
|
43
|
+
word = words.shift
|
44
|
+
end
|
45
|
+
offset = 0
|
46
|
+
lines << ((" " * indent) << line[0..-2])
|
47
|
+
line = ""
|
48
|
+
end
|
49
|
+
(lines * "\n")
|
50
|
+
else
|
51
|
+
paragraph
|
52
|
+
end
|
53
|
+
offset = 0
|
54
|
+
str
|
55
|
+
end*""
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.format_definition_list_item(dt, dd, size = 80, indent = 20, color = :yellow)
|
59
|
+
dd = "" if dd.nil?
|
60
|
+
dt = Log.color color, dt if color
|
61
|
+
dt = dt.to_s unless dd.empty?
|
62
|
+
len = Log.uncolor(dt).length
|
63
|
+
|
64
|
+
if indent < 0
|
65
|
+
text = format_paragraph(dd, size, indent.abs-1, 0)
|
66
|
+
text = dt << "\n" << text
|
67
|
+
else
|
68
|
+
offset = len - indent
|
69
|
+
offset = 0 if offset < 0
|
70
|
+
text = format_paragraph(dd, size, indent.abs+1, offset)
|
71
|
+
text[0..len-1] = dt
|
72
|
+
end
|
73
|
+
text
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.format_definition_list(defs, size = 80, indent = 20, color = :yellow, sep = "\n\n")
|
77
|
+
entries = []
|
78
|
+
defs.each do |dt,dd|
|
79
|
+
text = format_definition_list_item(dt,dd,size,indent,color)
|
80
|
+
entries << text
|
81
|
+
end
|
82
|
+
entries * sep
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.camel_case(string)
|
86
|
+
return string if string !~ /_/ && string =~ /[A-Z]+.*/
|
87
|
+
string.split(/_|(\d+)/).map{|e|
|
88
|
+
(e =~ /^[A-Z]{2,}$/ ? e : e.capitalize)
|
89
|
+
}.join
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.camel_case_lower(string)
|
93
|
+
string.split('_').inject([]){ |buffer,e|
|
94
|
+
buffer.push(buffer.empty? ? e.downcase : (e =~ /^[A-Z]{2,}$/ ? e : e.capitalize))
|
95
|
+
}.join
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.snake_case(string)
|
99
|
+
return nil if string.nil?
|
100
|
+
string = string.to_s if Symbol === string
|
101
|
+
string.
|
102
|
+
gsub(/([A-Z]{2,})([A-Z][a-z])/,'\1_\2').
|
103
|
+
gsub(/([a-z])([A-Z])/,'\1_\2').
|
104
|
+
gsub(/\s/,'_').gsub(/[^\w_]/, '').
|
105
|
+
split("_").collect{|p| p.match(/[A-Z]{2,}/) ? p : p.downcase } * "_"
|
106
|
+
end
|
107
|
+
|
108
|
+
# source: https://gist.github.com/ekdevdes/2450285
|
109
|
+
# author: Ethan Kramer (https://github.com/ekdevdes)
|
110
|
+
def self.humanize(value, options = {})
|
111
|
+
if options.empty?
|
112
|
+
options[:format] = :sentence
|
113
|
+
end
|
114
|
+
|
115
|
+
values = value.to_s.split('_')
|
116
|
+
values.each_index do |index|
|
117
|
+
# lower case each item in array
|
118
|
+
# Miguel Vazquez edit: Except for acronyms
|
119
|
+
values[index].downcase! unless values[index].match(/[a-zA-Z][A-Z]/)
|
120
|
+
end
|
121
|
+
if options[:format] == :allcaps
|
122
|
+
values.each do |value|
|
123
|
+
value.capitalize!
|
124
|
+
end
|
125
|
+
|
126
|
+
if options.empty?
|
127
|
+
options[:seperator] = " "
|
128
|
+
end
|
129
|
+
|
130
|
+
return values.join " "
|
131
|
+
end
|
132
|
+
|
133
|
+
if options[:format] == :class
|
134
|
+
values.each do |value|
|
135
|
+
value.capitalize!
|
136
|
+
end
|
137
|
+
|
138
|
+
return values.join ""
|
139
|
+
end
|
140
|
+
|
141
|
+
if options[:format] == :sentence
|
142
|
+
values[0].capitalize! unless values[0].match(/[a-zA-Z][A-Z]/)
|
143
|
+
|
144
|
+
return values.join " "
|
145
|
+
end
|
146
|
+
|
147
|
+
if options[:format] == :nocaps
|
148
|
+
return values.join " "
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def self.fixascii(string)
|
153
|
+
if string.respond_to?(:encode)
|
154
|
+
self.fixutf8(string).encode("ASCII-8BIT")
|
155
|
+
else
|
156
|
+
string
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def self.to_utf8(string)
|
161
|
+
string.encode("UTF-16BE", :invalid => :replace, :undef => :replace, :replace => "?").encode('UTF-8')
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.fixutf8(string)
|
165
|
+
return nil if string.nil?
|
166
|
+
return string if string.respond_to?(:encoding) && string.encoding.to_s == "UTF-8" && (string.respond_to?(:valid_encoding?) && string.valid_encoding?) ||
|
167
|
+
(string.respond_to?(:valid_encoding) && string.valid_encoding)
|
168
|
+
|
169
|
+
if string.respond_to?(:encode)
|
170
|
+
string.encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
|
171
|
+
else
|
172
|
+
require 'iconv'
|
173
|
+
@@ic ||= Iconv.new('UTF-8//IGNORE', 'UTF-8')
|
174
|
+
@@ic.iconv(string)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.humanize_list(list)
|
179
|
+
return "" if list.empty?
|
180
|
+
if list.length == 1
|
181
|
+
list.first
|
182
|
+
else
|
183
|
+
list[0..-2].collect{|e| e.to_s} * ", " << " and " << list[-1].to_s
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def self.parse_sql_values(txt)
|
188
|
+
io = StringIO.new txt.strip
|
189
|
+
|
190
|
+
values = []
|
191
|
+
fields = []
|
192
|
+
current = nil
|
193
|
+
quoted = false
|
194
|
+
while c = io.getc
|
195
|
+
if quoted
|
196
|
+
if c == "'"
|
197
|
+
quoted = false
|
198
|
+
else
|
199
|
+
current << c
|
200
|
+
end
|
201
|
+
else
|
202
|
+
case c
|
203
|
+
when "("
|
204
|
+
current = ""
|
205
|
+
when ")"
|
206
|
+
fields << current
|
207
|
+
values << fields
|
208
|
+
fields = []
|
209
|
+
current = nil
|
210
|
+
when ','
|
211
|
+
if not current.nil?
|
212
|
+
fields << current
|
213
|
+
current = ""
|
214
|
+
end
|
215
|
+
when "'"
|
216
|
+
quoted = true
|
217
|
+
when ";"
|
218
|
+
break
|
219
|
+
else
|
220
|
+
current << c
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
values
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
data/lib/scout/misc.rb
CHANGED
data/lib/scout/path/find.rb
CHANGED
@@ -1,25 +1,27 @@
|
|
1
|
+
require_relative '../indiferent_hash'
|
1
2
|
module Path
|
3
|
+
|
2
4
|
def _parts
|
3
5
|
@_parts ||= self.split("/")
|
4
6
|
end
|
5
7
|
|
6
8
|
def _subpath
|
7
|
-
@subpath ||= _parts.length > 1 ? _parts[1..-1] * "/" : _parts[0]
|
9
|
+
@subpath ||= _parts.length > 1 ? _parts[1..-1] * "/" : _parts[0] || ""
|
8
10
|
end
|
9
11
|
|
10
12
|
def _toplevel
|
11
|
-
@toplevel ||= _parts.length > 1 ? _parts[0] :
|
13
|
+
@toplevel ||= _parts.length > 1 ? _parts[0] : ""
|
12
14
|
end
|
13
15
|
|
14
16
|
def self.follow(path, map)
|
15
|
-
map.sub('{PKGDIR}', path.pkgdir || Path.default_pkgdir).
|
16
|
-
sub('{RESOURCE}', path.to_s).
|
17
|
+
map.sub('{PKGDIR}', path.pkgdir.respond_to?(:subdir) ? path.pkgdir.pkgdir : path.pkgdir || Path.default_pkgdir).
|
18
|
+
sub('{RESOURCE}', path.pkgdir.to_s).
|
17
19
|
sub('{PWD}', FileUtils.pwd).
|
18
20
|
sub('{TOPLEVEL}', path._toplevel).
|
19
21
|
sub('{SUBPATH}', path._subpath).
|
20
22
|
sub('{BASENAME}', File.basename(path)).
|
21
23
|
sub('{PATH}', path).
|
22
|
-
sub('{LIBDIR}', path.libdir || Path.caller_lib_dir).
|
24
|
+
sub('{LIBDIR}', path.libdir || (path.pkgdir.respond_to?(:libdir) && path.pkgdir.libdir) || Path.caller_lib_dir).
|
23
25
|
sub('{REMOVE}/', '').
|
24
26
|
sub('{REMOVE}', '').gsub(/\/+/,'/')
|
25
27
|
end
|
@@ -48,11 +50,16 @@ module Path
|
|
48
50
|
@@search_order ||= (path_maps.keys & map_search) + (path_maps.keys - map_search)
|
49
51
|
end
|
50
52
|
|
53
|
+
def self.add_path(name, map)
|
54
|
+
@@path_maps[name] = map
|
55
|
+
@@search_order = nil
|
56
|
+
end
|
57
|
+
|
51
58
|
SLASH = "/"[0]
|
52
59
|
DOT = "."[0]
|
53
60
|
def located?
|
54
61
|
# OPEN RESOURCE
|
55
|
-
self.slice(0,1) == SLASH || (self.
|
62
|
+
self.slice(0,1) == SLASH || (self.slice(0,1) == DOT && self.slice(1,2) == SLASH) # || (resource != Rbbt && (Open.remote?(self) || Open.ssh?(self)))
|
56
63
|
end
|
57
64
|
|
58
65
|
def annotate_found_where(found, where)
|
@@ -85,13 +92,13 @@ module Path
|
|
85
92
|
|
86
93
|
def find(where = nil)
|
87
94
|
return self if located?
|
95
|
+
return find_all if where == 'all' || where == :all
|
88
96
|
return follow(where) if where
|
89
97
|
|
90
|
-
|
91
98
|
Path.search_order.each do |map_name|
|
92
99
|
found = follow(map_name, false)
|
93
100
|
|
94
|
-
return annotate_found_where(found, map_name) if File.exist?(found) || File.directory?(
|
101
|
+
return annotate_found_where(found, map_name) if File.exist?(found) || File.directory?(found)
|
95
102
|
end
|
96
103
|
|
97
104
|
return follow(:default)
|
@@ -110,5 +117,4 @@ module Path
|
|
110
117
|
.collect{|where| find(where) }
|
111
118
|
.select{|file| file.exist? }.uniq
|
112
119
|
end
|
113
|
-
|
114
120
|
end
|
data/lib/scout/path/util.rb
CHANGED
@@ -31,12 +31,11 @@ module Path
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def glob_all(pattern = nil, caller_lib = nil, search_paths = nil)
|
34
|
-
search_paths ||= Path.
|
34
|
+
search_paths ||= Path.path_maps
|
35
35
|
search_paths = search_paths.dup
|
36
36
|
|
37
|
-
location_paths = {}
|
38
37
|
search_paths.keys.collect do |where|
|
39
|
-
found = find(where
|
38
|
+
found = find(where)
|
40
39
|
paths = pattern ? Dir.glob(File.join(found, pattern)) : Dir.glob(found)
|
41
40
|
|
42
41
|
paths = paths.collect{|p| self.annotate p }
|
@@ -46,7 +45,7 @@ module Path
|
|
46
45
|
p.where = where
|
47
46
|
end if found.original and pattern
|
48
47
|
|
49
|
-
|
50
|
-
end
|
48
|
+
paths
|
49
|
+
end.flatten.uniq
|
51
50
|
end
|
52
51
|
end
|
data/lib/scout/path.rb
CHANGED
@@ -4,16 +4,17 @@ require_relative 'path/util'
|
|
4
4
|
|
5
5
|
module Path
|
6
6
|
extend MetaExtension
|
7
|
-
extension_attr :pkgdir, :libdir
|
7
|
+
extension_attr :pkgdir, :libdir, :path_maps
|
8
8
|
|
9
9
|
def self.caller_lib_dir(file = nil, relative_to = ['lib', 'bin'])
|
10
10
|
|
11
11
|
if file.nil?
|
12
12
|
caller_dup = caller.dup
|
13
13
|
while file = caller_dup.shift
|
14
|
-
break unless file =~ /scout\/(?:resource\.rb|workflow\.rb)/ or
|
15
|
-
file =~ /scout\/path\.rb/ or
|
16
|
-
file =~ /scout\/
|
14
|
+
break unless file =~ /(?:scout|rbbt)\/(?:resource\.rb|workflow\.rb)/ or
|
15
|
+
file =~ /(?:scout|rbbt)\/(?:.*\/)?path\.rb/ or
|
16
|
+
file =~ /(?:scout|rbbt)\/(?:.*\/)?path\/(?:find|refactor|util)\.rb/ or
|
17
|
+
file =~ /(?:scout|rbbt)\/persist.rb/
|
17
18
|
end
|
18
19
|
file = file.sub(/\.rb[^\w].*/,'.rb')
|
19
20
|
end
|
@@ -34,15 +35,20 @@ module Path
|
|
34
35
|
end
|
35
36
|
|
36
37
|
def self.default_pkgdir
|
37
|
-
@@default_pkgdir
|
38
|
+
@@default_pkgdir ||= 'scout'
|
38
39
|
end
|
40
|
+
|
41
|
+
def self.default_pkgdir=(pkgdir)
|
42
|
+
@@default_pkgdir = pkgdir
|
43
|
+
end
|
44
|
+
|
39
45
|
|
40
46
|
def pkgdir
|
41
47
|
@pkgdir ||= Path.default_pkgdir
|
42
48
|
end
|
43
49
|
|
44
50
|
def libdir
|
45
|
-
@libdir
|
51
|
+
@libdir
|
46
52
|
end
|
47
53
|
|
48
54
|
def join(subpath, prevpath = nil)
|
@@ -50,7 +56,7 @@ module Path
|
|
50
56
|
prevpath = prevpath.to_s if Symbol === prevpath
|
51
57
|
|
52
58
|
subpath = File.join(prevpath.to_s, subpath) if prevpath
|
53
|
-
new = File.join(self, subpath)
|
59
|
+
new = self.empty? ? subpath : File.join(self, subpath)
|
54
60
|
self.annotate(new)
|
55
61
|
new
|
56
62
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module SOPT
|
2
|
+
class << self
|
3
|
+
attr_accessor :inputs, :input_shortcuts, :input_types, :input_descriptions, :input_defaults
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.all
|
7
|
+
@all ||= {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.shortcuts
|
11
|
+
@shortcuts ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.inputs
|
15
|
+
@inputs ||= []
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.input_shortcuts
|
19
|
+
@input_shortcuts ||= {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.input_types
|
23
|
+
@input_types ||= {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.input_descriptions
|
27
|
+
@input_descriptions ||= {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.input_defaults
|
31
|
+
@input_defaults ||= {}
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.reset
|
35
|
+
@shortcuts = {}
|
36
|
+
@all = {}
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.delete_inputs(inputs)
|
40
|
+
inputs.each do |input|
|
41
|
+
input = input.to_s
|
42
|
+
self.shortcuts.delete self.input_shortcuts.delete(input)
|
43
|
+
self.inputs.delete input
|
44
|
+
self.input_types.delete input
|
45
|
+
self.input_defaults.delete input
|
46
|
+
self.input_descriptions.delete input
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.usage
|
51
|
+
puts SOPT.doc
|
52
|
+
exit 0
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require_relative '../log'
|
2
|
+
module SOPT
|
3
|
+
|
4
|
+
class << self
|
5
|
+
attr_accessor :command, :summary, :synopsys, :description
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.command
|
9
|
+
@command ||= File.basename($0)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.summary
|
13
|
+
@summary ||= ""
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.synopsys
|
17
|
+
@synopsys ||= begin
|
18
|
+
"#{command} " <<
|
19
|
+
inputs.collect{|name|
|
20
|
+
"[" << input_format(name, input_types[name] || :string, input_defaults[name], input_shortcuts[name]).sub(/:$/,'') << "]"
|
21
|
+
} * " "
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.description
|
26
|
+
@description ||= "Missing"
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.input_format(name, type = nil, default = nil, short = nil)
|
30
|
+
input_str = (short.nil? or short.empty?) ? "--#{name}" : "-#{short},--#{name}"
|
31
|
+
input_str = Log.color(:blue, input_str)
|
32
|
+
extra = case type
|
33
|
+
when nil
|
34
|
+
""
|
35
|
+
when :boolean
|
36
|
+
"[=false]"
|
37
|
+
when :tsv, :text
|
38
|
+
"=<file|->"
|
39
|
+
when :array
|
40
|
+
"=<list|file|->"
|
41
|
+
else
|
42
|
+
"=<#{ type }>"
|
43
|
+
end
|
44
|
+
#extra << " (default: #{Array === default ? (default.length > 3 ? default[0..2]*", " + ', ...' : default*", " ): default})" if default != nil
|
45
|
+
extra << " (default: #{Misc.fingerprint(default)})" if default != nil
|
46
|
+
input_str << Log.color(:green, extra)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.input_doc(inputs, input_types = nil, input_descriptions = nil, input_defaults = nil, input_shortcuts = nil)
|
50
|
+
type = description = default = nil
|
51
|
+
shortcut = ""
|
52
|
+
seen = []
|
53
|
+
inputs.collect do |name|
|
54
|
+
next if seen.include? name
|
55
|
+
seen << name
|
56
|
+
|
57
|
+
type = input_types[name] unless input_types.nil?
|
58
|
+
description = input_descriptions[name] unless input_descriptions.nil?
|
59
|
+
default = input_defaults[name] unless input_defaults.nil?
|
60
|
+
|
61
|
+
name = name.to_s
|
62
|
+
|
63
|
+
case input_shortcuts
|
64
|
+
when nil, FalseClass
|
65
|
+
shortcut = nil
|
66
|
+
when Hash
|
67
|
+
shortcut = input_shortcuts[name]
|
68
|
+
when TrueClass
|
69
|
+
shortcut = fix_shortcut(name[0], name)
|
70
|
+
end
|
71
|
+
|
72
|
+
type = :string if type.nil?
|
73
|
+
register(shortcut, name, type, description) unless self.inputs.include? name
|
74
|
+
|
75
|
+
name = SOPT.input_format(name, type.to_sym, default, shortcut)
|
76
|
+
description
|
77
|
+
Misc.format_definition_list_item(name, description, 80, 31, nil)
|
78
|
+
end * "\n"
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.doc
|
82
|
+
doc = <<-EOF
|
83
|
+
#{Log.color :magenta}#{command}(1) -- #{summary}
|
84
|
+
#{"=" * (command.length + summary.length + 7)}#{Log.color :reset}
|
85
|
+
|
86
|
+
#{ Log.color :magenta, "## SYNOPSYS"}
|
87
|
+
|
88
|
+
#{Log.color :blue, synopsys}
|
89
|
+
|
90
|
+
#{ Log.color :magenta, "## DESCRIPTION"}
|
91
|
+
|
92
|
+
#{Misc.format_paragraph description}
|
93
|
+
|
94
|
+
#{ Log.color :magenta, "## OPTIONS"}
|
95
|
+
|
96
|
+
#{input_doc(inputs, input_types, input_descriptions, input_defaults, input_shortcuts)}
|
97
|
+
EOF
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.doc
|
101
|
+
doc = <<-EOF
|
102
|
+
#{Log.color :magenta}#{command}(1) -- #{summary}
|
103
|
+
#{"=" * (command.length + summary.length + 7)}#{Log.color :reset}
|
104
|
+
|
105
|
+
EOF
|
106
|
+
|
107
|
+
if synopsys and not synopsys.empty?
|
108
|
+
doc << Log.color(:magenta, "## SYNOPSYS") << "\n\n"
|
109
|
+
doc << Log.color(:blue, synopsys) << "\n\n"
|
110
|
+
end
|
111
|
+
|
112
|
+
if description and not description.empty?
|
113
|
+
doc << Log.color(:magenta, "## DESCRIPTION") << "\n\n"
|
114
|
+
doc << Misc.format_paragraph(description) << "\n\n"
|
115
|
+
end
|
116
|
+
|
117
|
+
doc << Log.color(:magenta, "## OPTIONS") << "\n\n"
|
118
|
+
doc << input_doc(inputs, input_types, input_descriptions, input_defaults, input_shortcuts)
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module SOPT
|
2
|
+
GOT_OPTIONS= IndiferentHash.setup({})
|
3
|
+
def self.current_options=(options)
|
4
|
+
@@current_options = options
|
5
|
+
end
|
6
|
+
def self.consume(args = ARGV)
|
7
|
+
i = 0
|
8
|
+
@@current_options ||= {}
|
9
|
+
while i < args.length do
|
10
|
+
current = args[i]
|
11
|
+
break if current == "--"
|
12
|
+
if m = current.match(/--?(.+?)(?:=(.+))?$/)
|
13
|
+
key = $1
|
14
|
+
value = $2
|
15
|
+
|
16
|
+
input = inputs.include?(key)? key : shortcuts[key]
|
17
|
+
|
18
|
+
if input.nil?
|
19
|
+
i += 1
|
20
|
+
next
|
21
|
+
else
|
22
|
+
args.delete_at i
|
23
|
+
end
|
24
|
+
else
|
25
|
+
i += 1
|
26
|
+
next
|
27
|
+
end
|
28
|
+
|
29
|
+
if input_types[input] == :string
|
30
|
+
value = args.delete_at(i) if value.nil?
|
31
|
+
@@current_options[input] = value
|
32
|
+
else
|
33
|
+
if value.nil? and %w(F false FALSE no).include?(args[i])
|
34
|
+
Log.warn "Boolean values are best specified as #{current}=[true|false], not #{ current } [true|false]. Token '#{args[i]}' following '#{current}' automatically assigned as value"
|
35
|
+
value = args.delete_at(i)
|
36
|
+
end
|
37
|
+
@@current_options[input] = %w(F false FALSE no).include?(value)? false : true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
IndiferentHash.setup @@current_options
|
42
|
+
GOT_OPTIONS.merge! @@current_options
|
43
|
+
|
44
|
+
@@current_options
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.get(opt_str)
|
48
|
+
SOPT.parse(opt_str)
|
49
|
+
SOPT.consume(ARGV)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.require(options, *parameters)
|
53
|
+
parameters.flatten.each do |parameter|
|
54
|
+
raise ParameterException, "Parameter '#{ Log.color :blue, parameter }' not given" if options[parameter].nil?
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module SOPT
|
2
|
+
def self.fix_shortcut(short, long)
|
3
|
+
return short unless short and shortcuts.include?(short)
|
4
|
+
|
5
|
+
current = shortcuts.select{|s,l| l == long}.collect{|s,l| s }.first
|
6
|
+
return current if current
|
7
|
+
|
8
|
+
chars = long.chars.to_a
|
9
|
+
current = [chars.shift]
|
10
|
+
short = current * ""
|
11
|
+
|
12
|
+
if (shortcuts.include?(short) and not shortcuts[short] == long)
|
13
|
+
if long.index "-" or long.index "_"
|
14
|
+
parts = long.split(/[_-]/)
|
15
|
+
acc = parts.collect{|s| s[0] } * ""
|
16
|
+
return acc unless shortcuts.include? acc
|
17
|
+
elsif m = long.match(/(\d+)/)
|
18
|
+
n = m[0]
|
19
|
+
acc = long[0] + n
|
20
|
+
return acc unless shortcuts.include? acc
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
while shortcuts.include?(short) && shortcuts[short] != long
|
25
|
+
next_letter = chars.shift
|
26
|
+
next_letter = chars.shift while %w(. - _).include?(next_letter)
|
27
|
+
return nil if next_letter.nil?
|
28
|
+
current << next_letter
|
29
|
+
short = current * ""
|
30
|
+
end
|
31
|
+
|
32
|
+
return nil if shortcuts.include? short
|
33
|
+
|
34
|
+
short
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.register(short, long, asterisk, description)
|
38
|
+
short = fix_shortcut(short, long)
|
39
|
+
shortcuts[short] = long if short
|
40
|
+
inputs << long
|
41
|
+
input_shortcuts[long] = short
|
42
|
+
input_descriptions[long] = description
|
43
|
+
input_types[long] = asterisk ? :string : :boolean
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.parse(opt_str)
|
47
|
+
info = {}
|
48
|
+
|
49
|
+
inputs = []
|
50
|
+
if opt_str.include? "\n"
|
51
|
+
re = /\n+/
|
52
|
+
else
|
53
|
+
re = /:/
|
54
|
+
end
|
55
|
+
opt_str.split(re).each do |entry|
|
56
|
+
entry.strip!
|
57
|
+
next if entry.empty?
|
58
|
+
names, _sep, description = entry.partition /\s+/
|
59
|
+
short, long, asterisk = names.match(/\s*(?:-(.+))?(?:--(.+?))([*])?$/).values_at 1,2,3
|
60
|
+
|
61
|
+
inputs << long
|
62
|
+
register short, long, asterisk, description
|
63
|
+
end
|
64
|
+
inputs
|
65
|
+
end
|
66
|
+
end
|