scout-essentials 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.vimproject +78 -0
  4. data/Gemfile +14 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.rdoc +18 -0
  7. data/Rakefile +47 -0
  8. data/VERSION +1 -0
  9. data/lib/scout/cmd.rb +348 -0
  10. data/lib/scout/concurrent_stream.rb +284 -0
  11. data/lib/scout/config.rb +168 -0
  12. data/lib/scout/exceptions.rb +77 -0
  13. data/lib/scout/indiferent_hash/case_insensitive.rb +30 -0
  14. data/lib/scout/indiferent_hash/options.rb +115 -0
  15. data/lib/scout/indiferent_hash.rb +96 -0
  16. data/lib/scout/log/color.rb +224 -0
  17. data/lib/scout/log/color_class.rb +269 -0
  18. data/lib/scout/log/fingerprint.rb +69 -0
  19. data/lib/scout/log/progress/report.rb +244 -0
  20. data/lib/scout/log/progress/util.rb +173 -0
  21. data/lib/scout/log/progress.rb +106 -0
  22. data/lib/scout/log/trap.rb +107 -0
  23. data/lib/scout/log.rb +441 -0
  24. data/lib/scout/meta_extension.rb +100 -0
  25. data/lib/scout/misc/digest.rb +63 -0
  26. data/lib/scout/misc/filesystem.rb +25 -0
  27. data/lib/scout/misc/format.rb +255 -0
  28. data/lib/scout/misc/helper.rb +31 -0
  29. data/lib/scout/misc/insist.rb +56 -0
  30. data/lib/scout/misc/monitor.rb +66 -0
  31. data/lib/scout/misc/system.rb +73 -0
  32. data/lib/scout/misc.rb +10 -0
  33. data/lib/scout/named_array.rb +138 -0
  34. data/lib/scout/open/lock/lockfile.rb +587 -0
  35. data/lib/scout/open/lock.rb +68 -0
  36. data/lib/scout/open/remote.rb +135 -0
  37. data/lib/scout/open/stream.rb +491 -0
  38. data/lib/scout/open/util.rb +244 -0
  39. data/lib/scout/open.rb +170 -0
  40. data/lib/scout/path/find.rb +204 -0
  41. data/lib/scout/path/tmpfile.rb +8 -0
  42. data/lib/scout/path/util.rb +127 -0
  43. data/lib/scout/path.rb +51 -0
  44. data/lib/scout/persist/open.rb +17 -0
  45. data/lib/scout/persist/path.rb +15 -0
  46. data/lib/scout/persist/serialize.rb +157 -0
  47. data/lib/scout/persist.rb +104 -0
  48. data/lib/scout/resource/open.rb +8 -0
  49. data/lib/scout/resource/path.rb +80 -0
  50. data/lib/scout/resource/produce/rake.rb +69 -0
  51. data/lib/scout/resource/produce.rb +151 -0
  52. data/lib/scout/resource/scout.rb +3 -0
  53. data/lib/scout/resource/software.rb +178 -0
  54. data/lib/scout/resource/util.rb +59 -0
  55. data/lib/scout/resource.rb +40 -0
  56. data/lib/scout/simple_opt/accessor.rb +54 -0
  57. data/lib/scout/simple_opt/doc.rb +126 -0
  58. data/lib/scout/simple_opt/get.rb +57 -0
  59. data/lib/scout/simple_opt/parse.rb +67 -0
  60. data/lib/scout/simple_opt/setup.rb +26 -0
  61. data/lib/scout/simple_opt.rb +5 -0
  62. data/lib/scout/tmpfile.rb +129 -0
  63. data/lib/scout-essentials.rb +10 -0
  64. data/scout-essentials.gemspec +143 -0
  65. data/share/color/color_names +507 -0
  66. data/share/color/diverging_colors.hex +12 -0
  67. data/share/software/install_helpers +523 -0
  68. data/test/scout/indiferent_hash/test_case_insensitive.rb +16 -0
  69. data/test/scout/indiferent_hash/test_options.rb +46 -0
  70. data/test/scout/log/test_color.rb +0 -0
  71. data/test/scout/log/test_progress.rb +108 -0
  72. data/test/scout/misc/test_digest.rb +30 -0
  73. data/test/scout/misc/test_filesystem.rb +30 -0
  74. data/test/scout/misc/test_insist.rb +13 -0
  75. data/test/scout/misc/test_system.rb +21 -0
  76. data/test/scout/open/test_lock.rb +52 -0
  77. data/test/scout/open/test_remote.rb +25 -0
  78. data/test/scout/open/test_stream.rb +676 -0
  79. data/test/scout/open/test_util.rb +73 -0
  80. data/test/scout/path/test_find.rb +110 -0
  81. data/test/scout/path/test_util.rb +22 -0
  82. data/test/scout/persist/test_open.rb +37 -0
  83. data/test/scout/persist/test_path.rb +37 -0
  84. data/test/scout/persist/test_serialize.rb +114 -0
  85. data/test/scout/resource/test_path.rb +58 -0
  86. data/test/scout/resource/test_produce.rb +94 -0
  87. data/test/scout/resource/test_software.rb +24 -0
  88. data/test/scout/resource/test_util.rb +38 -0
  89. data/test/scout/simple_opt/test_doc.rb +16 -0
  90. data/test/scout/simple_opt/test_get.rb +11 -0
  91. data/test/scout/simple_opt/test_parse.rb +10 -0
  92. data/test/scout/simple_opt/test_setup.rb +77 -0
  93. data/test/scout/test_cmd.rb +85 -0
  94. data/test/scout/test_concurrent_stream.rb +29 -0
  95. data/test/scout/test_config.rb +66 -0
  96. data/test/scout/test_indiferent_hash.rb +26 -0
  97. data/test/scout/test_log.rb +32 -0
  98. data/test/scout/test_meta_extension.rb +80 -0
  99. data/test/scout/test_misc.rb +6 -0
  100. data/test/scout/test_named_array.rb +43 -0
  101. data/test/scout/test_open.rb +146 -0
  102. data/test/scout/test_path.rb +54 -0
  103. data/test/scout/test_persist.rb +186 -0
  104. data/test/scout/test_resource.rb +26 -0
  105. data/test/scout/test_tmpfile.rb +53 -0
  106. data/test/test_helper.rb +50 -0
  107. metadata +247 -0
@@ -0,0 +1,284 @@
1
+ require_relative 'indiferent_hash'
2
+
3
+ module AbortedStream
4
+ attr_accessor :exception
5
+ def self.setup(obj, exception = nil)
6
+ obj.extend AbortedStream
7
+ obj.exception = exception
8
+ end
9
+ end
10
+
11
+ module ConcurrentStream
12
+ attr_accessor :threads, :pids, :callback, :abort_callback, :filename, :joined, :aborted, :autojoin, :lock, :no_fail, :pair, :thread, :stream_exception, :log, :std_err, :next
13
+
14
+ def self.setup(stream, options = {}, &block)
15
+ threads, pids, callback, abort_callback, filename, autojoin, lock, no_fail, pair, next_stream = IndiferentHash.process_options options, :threads, :pids, :callback, :abort_callback, :filename, :autojoin, :lock, :no_fail, :pair, :next
16
+ stream.extend ConcurrentStream unless ConcurrentStream === stream
17
+
18
+ stream.threads ||= []
19
+ stream.pids ||= []
20
+ stream.threads.concat(Array === threads ? threads : [threads]) unless threads.nil?
21
+ stream.pids.concat(Array === pids ? pids : [pids]) unless pids.nil? or pids.empty?
22
+ stream.autojoin = autojoin unless autojoin.nil?
23
+ stream.no_fail = no_fail unless no_fail.nil?
24
+ stream.std_err = ""
25
+
26
+ stream.next = next_stream unless next_stream.nil?
27
+ stream.pair = pair unless pair.nil?
28
+
29
+ callback = block if block_given?
30
+ if callback
31
+ if stream.callback
32
+ old_callback = stream.callback
33
+ stream.callback = Proc.new do
34
+ old_callback.call
35
+ callback.call
36
+ end
37
+ else
38
+ stream.callback = callback
39
+ end
40
+ end
41
+
42
+ if abort_callback
43
+ if stream.abort_callback
44
+ old_abort_callback = stream.abort_callback
45
+ stream.abort_callback = Proc.new do
46
+ old_abort_callback.call
47
+ abort_callback.call
48
+ end
49
+ else
50
+ stream.abort_callback = abort_callback
51
+ end
52
+ end
53
+
54
+ stream.filename = filename.nil? ? stream.inspect.split(":").last[0..-2] : filename
55
+
56
+ stream.lock = lock unless lock.nil?
57
+
58
+ stream.aborted = false
59
+
60
+ stream
61
+ end
62
+
63
+ def annotate(stream)
64
+ ConcurrentStream.setup(stream, :threads => threads, :pids => pids, :callback => callback, :abort_callback => abort_callback, :filename => filename, :autojoin => autojoin, :lock => lock)
65
+ stream
66
+ end
67
+
68
+ def clear
69
+ @threads = @pids = @callback = @abort_callback = @joined = nil
70
+ end
71
+
72
+ def joined?
73
+ @joined
74
+ end
75
+
76
+ def aborted?
77
+ @aborted
78
+ end
79
+
80
+ def join_threads
81
+ if @threads
82
+ @threads.each do |t|
83
+ next if t == Thread.current
84
+ begin
85
+ t.join
86
+ if Process::Status === t.value
87
+ if ! (t.value.success? || no_fail)
88
+
89
+ if log
90
+ msg = "Error joining #{self.filename || self.inspect}. Last log line: #{log}"
91
+ else
92
+ msg = "Error joining #{self.filename || self.inspect}"
93
+ end
94
+
95
+ raise ConcurrentStreamProcessFailed.new t.pid, msg, self
96
+ end
97
+ end
98
+ rescue Exception
99
+ if no_fail
100
+ Log.low "Not failing on exception joining thread in ConcurrenStream - #{filename} - #{$!.message}"
101
+ else
102
+ Log.low "Exception joining thread in ConcurrenStream #{Log.fingerprint self} - #{Log.fingerprint t} - #{$!.message}"
103
+ stream_raise_exception $!
104
+ end
105
+ end
106
+ end
107
+ end
108
+ @threads = []
109
+ end
110
+
111
+ def join_pids
112
+ if @pids and @pids.any?
113
+ @pids.each do |pid|
114
+ begin
115
+ Process.waitpid(pid, Process::WUNTRACED)
116
+ stream_raise_exception ConcurrentStreamProcessFailed.new(pid, "Error in waitpid", self) unless $?.success? or no_fail
117
+ rescue Errno::ECHILD
118
+ end
119
+ end
120
+ @pids = []
121
+ end
122
+ end
123
+
124
+ def join_callback
125
+ if @callback and not joined?
126
+ begin
127
+ @callback.call
128
+ ensure
129
+ @callback = nil
130
+ end
131
+ end
132
+ end
133
+
134
+ def join
135
+ begin
136
+ join_threads
137
+ join_pids
138
+ raise stream_exception if stream_exception
139
+ join_callback
140
+ close unless closed?
141
+ ensure
142
+ @joined = true
143
+ begin
144
+ lock.unlock if lock && lock.locked?
145
+ rescue
146
+ Log.exception $!
147
+ end
148
+ raise stream_exception if stream_exception
149
+ end
150
+ end
151
+
152
+ def abort_threads(exception = nil)
153
+ return unless @threads and @threads.any?
154
+ name = Log.fingerprint(Thread.current)
155
+ name += " - file:#{filename}" if filename
156
+ Log.low "Aborting threads (#{name}) - #{@threads.collect{|t| Log.fingerprint(t) } * ", "}"
157
+
158
+ threads = @threads.dup
159
+ @threads.clear
160
+ threads.each do |t|
161
+ next if t == Thread.current
162
+ next if t["aborted"]
163
+ t["aborted"] = true
164
+ exception = exception.nil? ? Aborted.new : exception
165
+ Log.debug "Aborting thread #{Log.fingerprint(t)} with exception: #{exception}"
166
+ t.raise(exception)
167
+ t.join
168
+ end
169
+ end
170
+
171
+ def abort_pids
172
+ @pids.each do |pid|
173
+ begin
174
+ Log.low "Killing PID #{pid} in ConcurrentStream #{filename}"
175
+ Process.kill :INT, pid
176
+ rescue Errno::ESRCH
177
+ end
178
+ end if @pids
179
+ @pids = []
180
+ end
181
+
182
+ def abort(exception = nil)
183
+ self.stream_exception ||= exception
184
+ if @aborted
185
+ Log.medium "Already aborted stream #{Log.fingerprint self} [#{@aborted}]"
186
+ return
187
+ else
188
+ Log.medium "Aborting stream #{Log.fingerprint self} [#{@aborted}]"
189
+ end
190
+ AbortedStream.setup(self, exception)
191
+ @aborted = true
192
+ begin
193
+ @abort_callback.call exception if @abort_callback
194
+
195
+ abort_threads(exception)
196
+ abort_pids
197
+
198
+ @callback = nil
199
+ @abort_callback = nil
200
+
201
+ if @pair && @pair.respond_to?(:abort) && ! @pair.aborted?
202
+ Log.medium "Aborting pair stream #{Log.fingerprint self}: #{Log.fingerprint @pair }"
203
+ @pair.abort exception
204
+ end
205
+ ensure
206
+ close unless closed?
207
+
208
+ if lock and lock.locked?
209
+ lock.unlock
210
+ end
211
+ end
212
+ end
213
+
214
+ def close(*args)
215
+ if autojoin
216
+ begin
217
+ super(*args)
218
+ rescue
219
+ self.abort
220
+ self.join
221
+ stream_raise_exception $!
222
+ ensure
223
+ self.join if ! @stream_exception && (self.closed? || self.eof?)
224
+ end
225
+ else
226
+ super(*args)
227
+ end
228
+ end
229
+
230
+ def read(*args)
231
+ begin
232
+ super(*args)
233
+ rescue Exception
234
+ @stream_exception ||= $!
235
+ raise @stream_exception
236
+ ensure
237
+ if ! @stream_exception && autojoin && ! closed?
238
+ begin
239
+ done = eof?
240
+ rescue Exception
241
+ self.abort($!)
242
+ raise $!
243
+ end
244
+ close if done
245
+ end
246
+ end
247
+ end
248
+
249
+ def add_callback(&block)
250
+ old_callback = callback
251
+ @callback = Proc.new do
252
+ old_callback.call if old_callback
253
+ block.call
254
+ end
255
+ end
256
+
257
+ def stream_raise_exception(exception)
258
+ self.stream_exception = exception
259
+ threads.each do |thread|
260
+ thread.raise exception
261
+ end
262
+ self.abort
263
+ end
264
+
265
+ def self.process_stream(stream, close: true, join: true, message: "process_stream", **kwargs, &block)
266
+ ConcurrentStream.setup(stream, **kwargs)
267
+ begin
268
+ begin
269
+ yield
270
+ ensure
271
+ stream.close if close && stream.respond_to?(:close) && ! (stream.respond_to?(:closed?) && stream.closed?)
272
+ stream.join if join && stream.respond_to?(:join) && ! stream.joined?
273
+ end
274
+ rescue Aborted
275
+ Log.low "Aborted #{message}: #{$!.message}"
276
+ stream.abort($!) if stream.respond_to?(:abort) && ! stream.aborted?
277
+ raise $!
278
+ rescue Exception
279
+ Log.low "Exception #{message}: #{$!.message}"
280
+ stream.abort($!) if stream.respond_to?(:abort) && ! stream.aborted?
281
+ raise $!
282
+ end
283
+ end
284
+ end
@@ -0,0 +1,168 @@
1
+ require_relative 'path'
2
+ require_relative 'resource'
3
+ require_relative 'resource/scout'
4
+
5
+ module Scout::Config
6
+
7
+ CACHE ||= IndiferentHash.setup({})
8
+
9
+ GOT_KEYS=[]
10
+
11
+ def self.add_entry(key, value, tokens)
12
+ tokens = [tokens] unless Array === tokens
13
+ tokens << "key:#{key}" unless tokens.include?("key:#{key}")
14
+ CACHE[key.to_s] ||= []
15
+ CACHE[key.to_s] << [tokens, value]
16
+ end
17
+
18
+ def self.load_file(file)
19
+ Log.debug "Loading config file: #{ file }"
20
+ TSV.traverse file, :type => :array do |line|
21
+ next if line =~ /^#/
22
+ key, value, *tokens = line.strip.split(/\s/)
23
+
24
+ self.add_entry(key, value, tokens) if key
25
+ end
26
+ end
27
+
28
+ def self.load_config
29
+ Scout.etc.config.find_all.reverse.each do |file|
30
+ self.load_file(file)
31
+ end
32
+ end
33
+
34
+ def self.set(values, *tokens)
35
+ if not Hash === values
36
+ values = {values => tokens.shift}
37
+ end
38
+
39
+ values.each do |key,value|
40
+ add_entry key, value, tokens
41
+ end
42
+ end
43
+
44
+ def self.token_priority(token)
45
+ token, _sep, priority = token.to_s.partition("::")
46
+
47
+ if priority.nil? || priority.empty?
48
+ type, _sep, rest = token.partition(":")
49
+ priority = case type
50
+ when "workflow"
51
+ 4
52
+ when "task"
53
+ 3
54
+ when "file"
55
+ 2
56
+ when "line"
57
+ 1
58
+ when "key"
59
+ 20
60
+ else
61
+ 10
62
+ end
63
+ else
64
+ priority = priority.to_i
65
+ end
66
+
67
+ [token, priority]
68
+ end
69
+
70
+ def self.match(entries, give_token)
71
+ priorities = {}
72
+ entries.each do |tokens, value|
73
+ best_prio = nil
74
+ tokens = [tokens] unless Array === tokens
75
+ tokens.each do |tok|
76
+ tok, prio = token_priority tok
77
+ next unless tok == give_token
78
+
79
+ best_prio = prio if best_prio.nil? or best_prio > prio
80
+ next if prio > best_prio
81
+
82
+ priorities[prio] ||= []
83
+ priorities[prio].unshift value
84
+ end
85
+ end if entries
86
+ priorities
87
+ end
88
+
89
+ # For equal priorities the matching prioritizes tokens ealier in the list
90
+ def self.get(key, *tokens)
91
+ options = tokens.pop if Hash === tokens.last
92
+ default = options.nil? ? nil : options[:default]
93
+
94
+ tokens = ["key:" + key] if tokens.empty?
95
+
96
+ tokens = tokens.flatten
97
+ file, _sep, line = caller.reject{|l|
98
+ l =~ /rbbt\/(?:resource\.rb|workflow\.rb)/ or
99
+ l =~ /rbbt\/resource\/path\.rb/ or
100
+ l =~ /rbbt\/util\/misc\.rb/ or
101
+ l =~ /accessor\.rb/ or
102
+ l =~ /progress-monitor\.rb/
103
+ }.first.partition(":")
104
+
105
+ File.expand_path(file)
106
+
107
+ tokens << ("file:" << file)
108
+ tokens << ("line:" << file << ":" << line.sub(/:in \`.*/,''))
109
+
110
+ entries = CACHE[key.to_s]
111
+ priorities = {}
112
+ tokens.each do |token|
113
+ token_prio = match entries, token.to_s
114
+ token_prio.each do |prio, values|
115
+ priorities[prio] ||= []
116
+ priorities[prio].concat(values)
117
+ end
118
+ end
119
+
120
+ value = priorities.empty? ? default : priorities.collect{|p| p }.sort_by{|p,v| p}.first.last.first
121
+ value = false if value == 'false'
122
+
123
+ Log.debug "Value #{value.inspect} for config key '#{ key }': #{tokens * ", "}"
124
+ GOT_KEYS << [key, value, tokens]
125
+
126
+ if String === value && m = value.match(/^env:(.*)/)
127
+ variable = m.captures.first
128
+ ENV[variable]
129
+ elsif value == 'nil'
130
+ nil
131
+ else
132
+ value
133
+ end
134
+ end
135
+
136
+ def self.with_config
137
+ saved_config = {}
138
+ CACHE.each do |k,v|
139
+ saved_config[k] = v.dup
140
+ end
141
+ saved_got_keys = GOT_KEYS.dup
142
+ begin
143
+ yield
144
+ ensure
145
+ CACHE.replace(saved_config)
146
+ GOT_KEYS.replace(saved_got_keys)
147
+ end
148
+ end
149
+
150
+ def self.process_config(config)
151
+ if Path.is_filename?(config) && File.exist?(config)
152
+ Scout::Config.load_file(config)
153
+ elsif Scout.etc.config_profile[config].exists?
154
+ Scout::Config.load_file(Scout.etc.config_profile[config].find)
155
+ else
156
+ key, value, *tokens = config.split(/\s/)
157
+ tokens = tokens.collect do |tok|
158
+ tok, _sep, prio = tok.partition("::")
159
+ prio = "0" if prio.nil? or prio.empty?
160
+ [tok, prio] * "::"
161
+ end
162
+ Scout::Config.set({key => value}, *tokens)
163
+ end
164
+ end
165
+
166
+
167
+ self.load_config
168
+ end
@@ -0,0 +1,77 @@
1
+ class ScoutDeprecated < StandardError; end
2
+ class ScoutException < StandardError; end
3
+
4
+ class FieldNotFoundError < StandardError;end
5
+
6
+ class TryAgain < StandardError; end
7
+ class StopInsist < Exception
8
+ attr_accessor :exception
9
+ def initialize(exception)
10
+ @exception = exception
11
+ end
12
+ end
13
+
14
+ class Aborted < StandardError; end
15
+
16
+ class ParameterException < ScoutException; end
17
+ class MissingParameterException < ParameterException
18
+ def initialize(parameter)
19
+ super("Missing parameter '#{parameter}'")
20
+ end
21
+ end
22
+ class ProcessFailed < StandardError;
23
+ attr_accessor :pid, :msg
24
+ def initialize(pid = Process.pid, msg = nil)
25
+ @pid = pid
26
+ @msg = msg
27
+ if @pid
28
+ if @msg
29
+ message = "Process #{@pid} failed - #{@msg}"
30
+ else
31
+ message = "Process #{@pid} failed"
32
+ end
33
+ else
34
+ message = "Failed to run #{@msg}"
35
+ end
36
+ super(message)
37
+ end
38
+ end
39
+
40
+ class ConcurrentStreamProcessFailed < ProcessFailed
41
+ attr_accessor :concurrent_stream
42
+ def initialize(pid = Process.pid, msg = nil, concurrent_stream = nil)
43
+ super(pid, msg)
44
+ @concurrent_stream = concurrent_stream
45
+ end
46
+ end
47
+
48
+ class OpenURLError < StandardError; end
49
+
50
+ class DontClose < Exception
51
+ attr_accessor :payload
52
+ def initialize(payload = nil)
53
+ @payload = payload
54
+ end
55
+ end
56
+
57
+
58
+ class KeepLocked < Exception
59
+ attr_accessor :payload
60
+ def initialize(payload)
61
+ @payload = payload
62
+ end
63
+ end
64
+
65
+ class KeepBar < Exception
66
+ attr_accessor :payload
67
+ def initialize(payload)
68
+ @payload = payload
69
+ end
70
+ end
71
+
72
+ class LockInterrupted < TryAgain; end
73
+
74
+ class ClosedStream < StandardError; end
75
+
76
+ class ResourceNotFound < ScoutException; end
77
+
@@ -0,0 +1,30 @@
1
+ module CaseInsensitiveHash
2
+
3
+ def self.setup(hash)
4
+ hash.extend CaseInsensitiveHash
5
+ end
6
+
7
+ def downcase_keys
8
+ @downcase_keys ||= begin
9
+ down = {}
10
+ keys.collect{|key|
11
+ down[key.to_s.downcase] = key
12
+ }
13
+ down
14
+ end
15
+ end
16
+
17
+ def [](key, *rest)
18
+ value = super(key, *rest)
19
+ return value unless value.nil?
20
+ key_downcase = key.to_s.downcase
21
+ super(downcase_keys[key_downcase])
22
+ end
23
+
24
+ def values_at(*keys)
25
+ keys.collect do |key|
26
+ self[key]
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,115 @@
1
+ module IndiferentHash
2
+ def self.add_defaults(options, defaults = {})
3
+ options = string2hash options if String === options
4
+ IndiferentHash.setup(options)
5
+
6
+ defaults = string2hash defaults if String === defaults
7
+
8
+ defaults.each do |key, value|
9
+ next if options.include?(key)
10
+
11
+ options[key] = value
12
+ end
13
+
14
+ options
15
+ end
16
+
17
+ def self.process_options(hash, *keys)
18
+ IndiferentHash.setup(hash)
19
+
20
+ defaults = keys.pop if Hash === keys.last
21
+ hash = IndiferentHash.add_defaults hash, defaults if defaults
22
+
23
+ if keys.length == 1
24
+ hash.include?(keys.first.to_sym) ? hash.delete(keys.first.to_sym) : hash.delete(keys.first.to_s)
25
+ else
26
+ keys.collect do |key| hash.include?(key.to_sym) ? hash.delete(key.to_sym) : hash.delete(key.to_s) end
27
+ end
28
+ end
29
+
30
+ def self.pull_keys(hash, prefix)
31
+ new = {}
32
+ prefix = prefix.to_s
33
+ hash.keys.each do |key|
34
+ if key.to_s =~ /#{ prefix }_(.*)/
35
+ case
36
+ when String === key
37
+ new[$1] = hash.delete key
38
+ when Symbol === key
39
+ new[$1.to_sym] = hash.delete key
40
+ end
41
+ else
42
+ if key.to_s == prefix.to_s
43
+ new[key] = hash.delete key
44
+ end
45
+ end
46
+ end
47
+
48
+ IndiferentHash.setup(new)
49
+ end
50
+
51
+ def self.zip2hash(list1, list2)
52
+ hash = {}
53
+ list1.each_with_index do |e,i|
54
+ hash[e] = list2[i]
55
+ end
56
+ IndiferentHash.setup(hash)
57
+ end
58
+
59
+ def self.positional2hash(keys, *values)
60
+ if Hash === values.last
61
+ extra = values.pop
62
+ inputs = IndiferentHash.zip2hash(keys, values)
63
+ inputs.delete_if{|k,v| v.nil? or (String === v and v.empty?)}
64
+ inputs = IndiferentHash.add_defaults inputs, extra
65
+ inputs.delete_if{|k,v| not keys.include?(k) and not (Symbol === k ? keys.include?(k.to_s) : keys.include?(k.to_sym))}
66
+ inputs
67
+ else
68
+ IndiferentHash.zip2hash(keys, values)
69
+ end
70
+ end
71
+
72
+ def self.array2hash(array, default = nil)
73
+ hash = {}
74
+ array.each do |key, value|
75
+ value = default.dup if value.nil? and not default.nil?
76
+ hash[key] = value
77
+ end
78
+ IndiferentHash.setup(hash)
79
+ end
80
+
81
+ def self.process_to_hash(list)
82
+ result = yield list
83
+ zip2hash(list, result)
84
+ end
85
+
86
+ def self.hash2string(hash)
87
+ hash.sort_by{|k,v| k.to_s}.collect{|k,v|
88
+ next unless %w(Symbol String Float Fixnum Integer Numeric TrueClass FalseClass Module Class Object).include? v.class.to_s
89
+ [ Symbol === k ? ":" << k.to_s : k.to_s.chomp,
90
+ Symbol === v ? ":" << v.to_s : v.to_s.chomp] * "="
91
+ }.compact * "#"
92
+ end
93
+
94
+ def self.string2hash(string)
95
+ options = {}
96
+
97
+ string.split('#').each do |str|
98
+ key, _, value = str.partition "="
99
+
100
+ key = key[1..-1].to_sym if key[0] == ":"
101
+
102
+ options[key] = true and next if value.empty?
103
+ options[key] = value[1..-1].to_sym and next if value[0] == ":"
104
+ options[key] = Regexp.new(/#{value[1..-2]}/) and next if value[0] == "/" and value[-1] == "/"
105
+ options[key] = value[1..-2] and next if value =~ /^['"].*['"]$/
106
+ options[key] = value.to_i and next if value =~ /^\d+$/
107
+ options[key] = value.to_f and next if value =~ /^\d*\.\d+$/
108
+ options[key] = true and next if value == "true"
109
+ options[key] = false and next if value == "false"
110
+ options[key] = value
111
+ end
112
+
113
+ IndiferentHash.setup(options)
114
+ end
115
+ end