scout-gear 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -1,3 +1,4 @@
1
+ require_relative 'misc/format'
1
2
  module Misc
2
3
  def self.in_dir(dir)
3
4
  old_pwd = FileUtils.pwd
@@ -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] : nil
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.char(0,1) == DOT && self.char(1,2) == SLASH) # || (resource != Rbbt && (Open.remote?(self) || Open.ssh?(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?(real_path)
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
@@ -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.search_paths
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, Path.caller_lib_dir, search_paths)
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
- location_paths[where] = paths
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\/persist.rb/
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 = 'scout'
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 ||= Path.caller_lib_dir
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