scout-gear 1.1.1 → 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 -1
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/bin/scout +28 -0
- data/lib/scout/indiferent_hash.rb +0 -30
- data/lib/scout/log/progress/report.rb +1 -1
- data/lib/scout/log/progress/util.rb +0 -1
- data/lib/scout/log.rb +1 -1
- data/lib/scout/meta_extension.rb +15 -1
- data/lib/scout/misc/format.rb +227 -0
- data/lib/scout/misc.rb +14 -0
- data/lib/scout/path/find.rb +88 -33
- data/lib/scout/path/util.rb +51 -0
- data/lib/scout/path.rb +23 -10
- 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/tmpfile.rb +2 -6
- data/lib/scout-gear.rb +2 -0
- data/scout-gear.gemspec +19 -3
- data/test/scout/indiferent_hash/test_case_insensitive.rb +16 -0
- data/test/scout/path/test_find.rb +42 -1
- data/test/scout/path/test_util.rb +22 -0
- 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
- data/test/scout/test_meta_extension.rb +16 -2
- data/test/scout/test_misc.rb +13 -0
- data/test/scout/test_path.rb +16 -0
- metadata +18 -2
data/lib/scout/log.rb
CHANGED
data/lib/scout/meta_extension.rb
CHANGED
@@ -13,9 +13,23 @@ module MetaExtension
|
|
13
13
|
|
14
14
|
meta.define_method(:setup) do |obj,*rest|
|
15
15
|
obj.extend base
|
16
|
-
self.class_variable_get("@@extension_attrs")
|
16
|
+
attrs = self.class_variable_get("@@extension_attrs")
|
17
|
+
|
18
|
+
return if attrs.nil? || attrs.empty?
|
19
|
+
|
20
|
+
if rest.length == 1 && Hash === (rlast = rest.last) &&
|
21
|
+
! (rlkey = rlast.keys.first).nil? &&
|
22
|
+
attrs.include?(rlkey.to_sym)
|
23
|
+
|
24
|
+
pairs = rlast
|
25
|
+
else
|
26
|
+
pairs = attrs.zip(rest)
|
27
|
+
end
|
28
|
+
|
29
|
+
pairs.each do |name,value|
|
17
30
|
obj.instance_variable_set("@#{name}", value)
|
18
31
|
end
|
32
|
+
|
19
33
|
obj
|
20
34
|
end
|
21
35
|
|
@@ -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
ADDED
data/lib/scout/path/find.rb
CHANGED
@@ -1,65 +1,120 @@
|
|
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).
|
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).
|
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
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
def
|
44
|
-
|
29
|
+
def self.path_maps
|
30
|
+
@@path_maps ||= IndiferentHash.setup({
|
31
|
+
:current => File.join("{PWD}", "{TOPLEVEL}", "{SUBPATH}"),
|
32
|
+
:user => File.join(ENV['HOME'], ".{PKGDIR}", "{TOPLEVEL}", "{SUBPATH}"),
|
33
|
+
:global => File.join('/', "{TOPLEVEL}", "{PKGDIR}", "{SUBPATH}"),
|
34
|
+
:usr => File.join('/usr/', "{TOPLEVEL}", "{PKGDIR}", "{SUBPATH}"),
|
35
|
+
:local => File.join('/usr/local', "{TOPLEVEL}", "{PKGDIR}", "{SUBPATH}"),
|
36
|
+
:fast => File.join('/fast', "{TOPLEVEL}", "{PKGDIR}", "{SUBPATH}"),
|
37
|
+
:cache => File.join('/cache', "{TOPLEVEL}", "{PKGDIR}", "{SUBPATH}"),
|
38
|
+
:bulk => File.join('/bulk', "{TOPLEVEL}", "{PKGDIR}", "{SUBPATH}"),
|
39
|
+
:lib => File.join('{LIBDIR}', "{TOPLEVEL}", "{SUBPATH}"),
|
40
|
+
:base => File.join(Path.caller_lib_dir(__FILE__), "{TOPLEVEL}", "{SUBPATH}"),
|
41
|
+
:default => :user
|
42
|
+
})
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.map_search
|
46
|
+
@@map_search ||= %w(current workflow user local global lib fast cache bulk)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.search_order
|
50
|
+
@@search_order ||= (path_maps.keys & map_search) + (path_maps.keys - map_search)
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.add_path(name, map)
|
54
|
+
@@path_maps[name] = map
|
55
|
+
@@search_order = nil
|
56
|
+
end
|
57
|
+
|
58
|
+
SLASH = "/"[0]
|
59
|
+
DOT = "."[0]
|
60
|
+
def located?
|
61
|
+
# OPEN RESOURCE
|
62
|
+
self.slice(0,1) == SLASH || (self.slice(0,1) == DOT && self.slice(1,2) == SLASH) # || (resource != Rbbt && (Open.remote?(self) || Open.ssh?(self)))
|
63
|
+
end
|
64
|
+
|
65
|
+
def annotate_found_where(found, where)
|
66
|
+
self.annotate(found).tap{|p|
|
67
|
+
p.instance_variable_set("@where", where)
|
68
|
+
p.instance_variable_set("@original", self.dup)
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
def where
|
73
|
+
@where
|
74
|
+
end
|
75
|
+
|
76
|
+
def original
|
77
|
+
@original
|
78
|
+
end
|
79
|
+
|
80
|
+
def follow(map_name = :default, annotate = true)
|
81
|
+
map = Path.path_maps[map_name]
|
45
82
|
while Symbol === map
|
46
|
-
|
83
|
+
map_name = map
|
84
|
+
map = Path.path_maps[map_name]
|
47
85
|
end
|
48
|
-
Path.follow(self, map)
|
86
|
+
found = Path.follow(self, map)
|
87
|
+
|
88
|
+
annotate_found_where(found, map_name) if annotate
|
89
|
+
|
90
|
+
found
|
49
91
|
end
|
50
92
|
|
51
93
|
def find(where = nil)
|
52
|
-
return
|
94
|
+
return self if located?
|
95
|
+
return find_all if where == 'all' || where == :all
|
96
|
+
return follow(where) if where
|
53
97
|
|
54
|
-
|
55
|
-
|
98
|
+
Path.search_order.each do |map_name|
|
99
|
+
found = follow(map_name, false)
|
56
100
|
|
57
|
-
|
58
|
-
map = PATH_MAPS[name]
|
59
|
-
real_path = _follow(map)
|
60
|
-
return real_path if File.exists?(real_path)
|
101
|
+
return annotate_found_where(found, map_name) if File.exist?(found) || File.directory?(found)
|
61
102
|
end
|
62
103
|
|
63
|
-
return
|
104
|
+
return follow(:default)
|
105
|
+
end
|
106
|
+
|
107
|
+
def exist?
|
108
|
+
# OPEN
|
109
|
+
found = self.find
|
110
|
+
File.exist?(found) || File.directory?(found)
|
111
|
+
end
|
112
|
+
|
113
|
+
alias exists? exist?
|
114
|
+
|
115
|
+
def find_all(caller_lib = nil, search_paths = nil)
|
116
|
+
Path.search_order
|
117
|
+
.collect{|where| find(where) }
|
118
|
+
.select{|file| file.exist? }.uniq
|
64
119
|
end
|
65
120
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Path
|
2
|
+
def directory?
|
3
|
+
return nil unless self.exist?
|
4
|
+
File.directory?(self.find)
|
5
|
+
end
|
6
|
+
|
7
|
+
def dirname
|
8
|
+
self.annotate(File.dirname(self))
|
9
|
+
end
|
10
|
+
|
11
|
+
def basename
|
12
|
+
self.annotate(File.basename(self))
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def glob(pattern = '*')
|
17
|
+
if self.include? "*"
|
18
|
+
self.glob_all
|
19
|
+
else
|
20
|
+
return [] unless self.exist?
|
21
|
+
found = self.find
|
22
|
+
exp = File.join(found, pattern)
|
23
|
+
paths = Dir.glob(exp).collect{|f| self.annotate(f) }
|
24
|
+
|
25
|
+
paths.each do |p|
|
26
|
+
p.original = File.join(found.original, p.sub(/^#{found}/, ''))
|
27
|
+
end if found.original
|
28
|
+
|
29
|
+
paths
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def glob_all(pattern = nil, caller_lib = nil, search_paths = nil)
|
34
|
+
search_paths ||= Path.path_maps
|
35
|
+
search_paths = search_paths.dup
|
36
|
+
|
37
|
+
search_paths.keys.collect do |where|
|
38
|
+
found = find(where)
|
39
|
+
paths = pattern ? Dir.glob(File.join(found, pattern)) : Dir.glob(found)
|
40
|
+
|
41
|
+
paths = paths.collect{|p| self.annotate p }
|
42
|
+
|
43
|
+
paths = paths.each do |p|
|
44
|
+
p.original = File.join(found.original, p.sub(/^#{found}/, ''))
|
45
|
+
p.where = where
|
46
|
+
end if found.original and pattern
|
47
|
+
|
48
|
+
paths
|
49
|
+
end.flatten.uniq
|
50
|
+
end
|
51
|
+
end
|
data/lib/scout/path.rb
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
require_relative 'meta_extension'
|
2
|
+
require_relative 'path/find'
|
3
|
+
require_relative 'path/util'
|
2
4
|
|
3
5
|
module Path
|
4
6
|
extend MetaExtension
|
5
|
-
extension_attr :pkgdir, :libdir
|
7
|
+
extension_attr :pkgdir, :libdir, :path_maps
|
6
8
|
|
7
9
|
def self.caller_lib_dir(file = nil, relative_to = ['lib', 'bin'])
|
8
10
|
|
9
11
|
if file.nil?
|
10
12
|
caller_dup = caller.dup
|
11
13
|
while file = caller_dup.shift
|
12
|
-
break unless file =~ /scout\/(?:resource\.rb|workflow\.rb)/ or
|
13
|
-
file =~ /scout\/path\.rb/ or
|
14
|
-
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/
|
15
18
|
end
|
16
19
|
file = file.sub(/\.rb[^\w].*/,'.rb')
|
17
20
|
end
|
@@ -31,11 +34,21 @@ module Path
|
|
31
34
|
return nil
|
32
35
|
end
|
33
36
|
|
34
|
-
def self.
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
37
|
+
def self.default_pkgdir
|
38
|
+
@@default_pkgdir ||= 'scout'
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.default_pkgdir=(pkgdir)
|
42
|
+
@@default_pkgdir = pkgdir
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def pkgdir
|
47
|
+
@pkgdir ||= Path.default_pkgdir
|
48
|
+
end
|
49
|
+
|
50
|
+
def libdir
|
51
|
+
@libdir
|
39
52
|
end
|
40
53
|
|
41
54
|
def join(subpath, prevpath = nil)
|
@@ -43,7 +56,7 @@ module Path
|
|
43
56
|
prevpath = prevpath.to_s if Symbol === prevpath
|
44
57
|
|
45
58
|
subpath = File.join(prevpath.to_s, subpath) if prevpath
|
46
|
-
new = File.join(self, subpath)
|
59
|
+
new = self.empty? ? subpath : File.join(self, subpath)
|
47
60
|
self.annotate(new)
|
48
61
|
new
|
49
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
|