scout-gear 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.vimproject +45 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +63 -0
- data/VERSION +1 -0
- data/bin/scout +0 -0
- data/lib/scout/exceptions.rb +112 -0
- data/lib/scout/indiferent_hash/case_insensitive.rb +30 -0
- data/lib/scout/indiferent_hash/options.rb +132 -0
- data/lib/scout/indiferent_hash.rb +107 -0
- data/lib/scout/log/color.rb +169 -0
- data/lib/scout/log/color_class.rb +269 -0
- data/lib/scout/log/fingerprint.rb +59 -0
- data/lib/scout/log/progress/report.rb +240 -0
- data/lib/scout/log/progress/util.rb +100 -0
- data/lib/scout/log/progress.rb +102 -0
- data/lib/scout/log.rb +362 -0
- data/lib/scout/meta_extension.rb +29 -0
- data/lib/scout/path/find.rb +65 -0
- data/lib/scout/path.rb +62 -0
- data/lib/scout/tmpfile.rb +96 -0
- data/lib/scout-gear.rb +3 -0
- data/scout-gear.gemspec +78 -0
- data/test/scout/indiferent_hash/test_options.rb +36 -0
- data/test/scout/log/test_progress.rb +110 -0
- data/test/scout/path/test_find.rb +34 -0
- data/test/scout/test_indiferent_hash.rb +26 -0
- data/test/scout/test_log.rb +32 -0
- data/test/scout/test_meta_extension.rb +22 -0
- data/test/scout/test_path.rb +36 -0
- data/test/scout/test_tmpfile.rb +53 -0
- data/test/test_helper.rb +27 -0
- metadata +134 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ede50b3180404ca069e07dce767799d3b2c38c79c40ef952ac384571bf252e50
|
4
|
+
data.tar.gz: 9bf5db695bcd2ac0a4436d3995c2ad71a76dd51168c82f3382b66fe3258ee7bc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ff2ad51cc4e556fcfb11c515bc28d26ffa3daf7183de7b23fc47798d9c0d79c7a6763957707a9cc6fb5629f5f2f8b27b689290604647a4f288412ceacd94123e
|
7
|
+
data.tar.gz: 609c9256ecb3e5b900db3635abf63d3d88be9d4a8d8832405446cdb8f15c543443bb45bd6375563b3881c3e4682143fd22573a21ba6877f380ac1167dcc33e68
|
data/.document
ADDED
data/.vimproject
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
scout-gear=/$PWD filter="*.rb *.yaml" {
|
2
|
+
Rakefile
|
3
|
+
bin=bin {
|
4
|
+
}
|
5
|
+
lib=lib {
|
6
|
+
scout-gear.rb
|
7
|
+
scout=scout{
|
8
|
+
exceptions.rb
|
9
|
+
meta_extension.rb
|
10
|
+
tmpfile.rb
|
11
|
+
indiferent_hash.rb
|
12
|
+
indiferent_hash=indiferent_hash{
|
13
|
+
case_insensitive.rb
|
14
|
+
options.rb
|
15
|
+
}
|
16
|
+
log.rb
|
17
|
+
log=log{
|
18
|
+
color.rb
|
19
|
+
color_class.rb
|
20
|
+
fingerprint.rb
|
21
|
+
progress.rb
|
22
|
+
progress=progress{
|
23
|
+
report.rb
|
24
|
+
util.rb
|
25
|
+
}
|
26
|
+
}
|
27
|
+
path.rb
|
28
|
+
path=path{
|
29
|
+
find.rb
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
33
|
+
test=test {
|
34
|
+
test_helper.rb
|
35
|
+
scout=scout{
|
36
|
+
test_indiferent_hash.rb
|
37
|
+
indiferent_hash=indiferent_hash{
|
38
|
+
test_options.rb
|
39
|
+
}
|
40
|
+
test_log.rb
|
41
|
+
test_tmpfile.rb
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2023 Miguel Vazquez
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
= scout-gear
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Contributing to scout-gear
|
6
|
+
|
7
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
8
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
9
|
+
* Fork the project.
|
10
|
+
* Start a feature/bugfix branch.
|
11
|
+
* Commit and push until you are happy with your contribution.
|
12
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
13
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2023 Miguel Vazquez. See LICENSE.txt for
|
18
|
+
further details.
|
19
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rake'
|
5
|
+
|
6
|
+
require 'juwelier'
|
7
|
+
Juwelier::Tasks.new do |gem|
|
8
|
+
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
9
|
+
gem.name = "scout-gear"
|
10
|
+
gem.homepage = "http://github.com/mikisvaz/scout-gear"
|
11
|
+
gem.license = "MIT"
|
12
|
+
gem.summary = %Q{basic gear for scouts}
|
13
|
+
gem.description = %Q{Temporary files, logs, etc.}
|
14
|
+
gem.email = "mikisvaz@gmail.com"
|
15
|
+
gem.authors = ["Miguel Vazquez"]
|
16
|
+
|
17
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
18
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
19
|
+
# gem.add_runtime_dependency 'jabber4r', '> 0.1'
|
20
|
+
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
21
|
+
gem.add_development_dependency "rdoc", "~> 3.12"
|
22
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
23
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
24
|
+
# gem.add_runtime_dependency 'jabber4r', '> 0.1'
|
25
|
+
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
26
|
+
gem.add_development_dependency "bundler", "~> 1.0"
|
27
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
28
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
29
|
+
# gem.add_runtime_dependency 'jabber4r', '> 0.1'
|
30
|
+
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
31
|
+
gem.add_development_dependency "juwelier", "~> 2.1.0"
|
32
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
33
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
34
|
+
# gem.add_runtime_dependency 'jabber4r', '> 0.1'
|
35
|
+
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
36
|
+
gem.add_development_dependency "simplecov", ">= 0"
|
37
|
+
end
|
38
|
+
Juwelier::RubygemsDotOrgTasks.new
|
39
|
+
|
40
|
+
require 'rake/testtask'
|
41
|
+
Rake::TestTask.new(:test) do |test|
|
42
|
+
test.libs << 'lib' << 'test'
|
43
|
+
test.pattern = 'test/**/test_*.rb'
|
44
|
+
test.verbose = true
|
45
|
+
end
|
46
|
+
|
47
|
+
desc "Code coverage detail"
|
48
|
+
task :simplecov do
|
49
|
+
ENV['COVERAGE'] = "true"
|
50
|
+
Rake::Task['test'].execute
|
51
|
+
end
|
52
|
+
|
53
|
+
task :default => :test
|
54
|
+
|
55
|
+
require 'rdoc/task'
|
56
|
+
Rake::RDocTask.new do |rdoc|
|
57
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
58
|
+
|
59
|
+
rdoc.rdoc_dir = 'rdoc'
|
60
|
+
rdoc.title = "scout-gear #{version}"
|
61
|
+
rdoc.rdoc_files.include('README*')
|
62
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
63
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.1.0
|
data/bin/scout
ADDED
File without changes
|
@@ -0,0 +1,112 @@
|
|
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 ProcessFailed < StandardError;
|
17
|
+
attr_accessor :pid, :msg
|
18
|
+
def initialize(pid = Process.pid, msg = nil)
|
19
|
+
@pid = pid
|
20
|
+
@msg = msg
|
21
|
+
if @pid
|
22
|
+
if @msg
|
23
|
+
message = "Process #{@pid} failed - #{@msg}"
|
24
|
+
else
|
25
|
+
message = "Process #{@pid} failed"
|
26
|
+
end
|
27
|
+
else
|
28
|
+
message = "Failed to run #{@msg}"
|
29
|
+
end
|
30
|
+
super(message)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class ConcurrentStreamProcessFailed < ProcessFailed
|
35
|
+
attr_accessor :concurrent_stream
|
36
|
+
def initialize(pid = Process.pid, msg = nil, concurrent_stream = nil)
|
37
|
+
super(pid, msg)
|
38
|
+
@concurrent_stream = concurrent_stream
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class OpenURLError < StandardError; end
|
43
|
+
|
44
|
+
class DontClose < Exception; end
|
45
|
+
|
46
|
+
class KeepLocked < Exception
|
47
|
+
attr_accessor :payload
|
48
|
+
def initialize(payload)
|
49
|
+
@payload = payload
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class KeepBar < Exception
|
54
|
+
attr_accessor :payload
|
55
|
+
def initialize(payload)
|
56
|
+
@payload = payload
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
#class ParameterException < ScoutException; end
|
61
|
+
#
|
62
|
+
#class MissingParameterException < ParameterException
|
63
|
+
# def initialize(parameter)
|
64
|
+
# super("Missing parameter '#{parameter}'")
|
65
|
+
# end
|
66
|
+
#end
|
67
|
+
#class ClosedStream < StandardError; end
|
68
|
+
#class OpenGzipError < StandardError; end
|
69
|
+
#
|
70
|
+
#
|
71
|
+
#class TryThis < StandardError
|
72
|
+
# attr_accessor :payload
|
73
|
+
# def initialize(payload = nil)
|
74
|
+
# @payload = payload
|
75
|
+
# end
|
76
|
+
#end
|
77
|
+
#
|
78
|
+
#class SemaphoreInterrupted < TryAgain; end
|
79
|
+
#class LockInterrupted < TryAgain; end
|
80
|
+
#
|
81
|
+
#class RemoteServerError < StandardError; end
|
82
|
+
#
|
83
|
+
#class DependencyError < Aborted
|
84
|
+
# def initialize(msg)
|
85
|
+
# if defined? Step and Step === msg
|
86
|
+
# step = msg
|
87
|
+
# new_msg = [step.path, step.messages.last] * ": "
|
88
|
+
# super(new_msg)
|
89
|
+
# else
|
90
|
+
# super(msg)
|
91
|
+
# end
|
92
|
+
# end
|
93
|
+
#end
|
94
|
+
#
|
95
|
+
#class DependencyScoutException < ScoutException
|
96
|
+
# def initialize(msg)
|
97
|
+
# if defined? Step and Step === msg
|
98
|
+
# step = msg
|
99
|
+
#
|
100
|
+
# new_msg = nil
|
101
|
+
# new_msg = [step.path, step.messages.last] * ": "
|
102
|
+
#
|
103
|
+
# super(new_msg)
|
104
|
+
# else
|
105
|
+
# super(msg)
|
106
|
+
# end
|
107
|
+
# end
|
108
|
+
#end
|
109
|
+
#
|
110
|
+
#
|
111
|
+
#
|
112
|
+
#
|
@@ -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,132 @@
|
|
1
|
+
module IndiferentHash
|
2
|
+
def self.add_defaults(options, defaults = {})
|
3
|
+
options ||= {}
|
4
|
+
IndiferentHash.setup(options)
|
5
|
+
case
|
6
|
+
when Hash === options
|
7
|
+
new_options = options.dup
|
8
|
+
when String === options
|
9
|
+
new_options = string2hash options
|
10
|
+
else
|
11
|
+
raise "Format of '#{options.inspect}' not understood. It should be a hash"
|
12
|
+
end
|
13
|
+
|
14
|
+
defaults.each do |key, value|
|
15
|
+
next if options.include? key
|
16
|
+
|
17
|
+
new_options[key] = value
|
18
|
+
end
|
19
|
+
|
20
|
+
new_options
|
21
|
+
|
22
|
+
options.replace new_options
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.process_options(hash, *keys)
|
26
|
+
IndiferentHash.setup(hash)
|
27
|
+
|
28
|
+
defaults = keys.pop if Hash === keys.last
|
29
|
+
hahs = IndiferentHash.add_defaults hash, defaults if defaults
|
30
|
+
|
31
|
+
if keys.length == 1
|
32
|
+
hash.include?(keys.first.to_sym) ? hash.delete(keys.first.to_sym) : hash.delete(keys.first.to_s)
|
33
|
+
else
|
34
|
+
keys.collect do |key| hash.include?(key.to_sym) ? hash.delete(key.to_sym) : hash.delete(key.to_s) end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.pull_keys(hash, prefix)
|
39
|
+
new = {}
|
40
|
+
hash.keys.each do |key|
|
41
|
+
if key.to_s =~ /#{ prefix }_(.*)/
|
42
|
+
case
|
43
|
+
when String === key
|
44
|
+
new[$1] = hash.delete key
|
45
|
+
when Symbol === key
|
46
|
+
new[$1.to_sym] = hash.delete key
|
47
|
+
end
|
48
|
+
else
|
49
|
+
if key.to_s == prefix.to_s
|
50
|
+
new[key] = hash.delete key
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
IndiferentHash.setup(new)
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.zip2hash(list1, list2)
|
59
|
+
hash = {}
|
60
|
+
list1.each_with_index do |e,i|
|
61
|
+
hash[e] = list2[i]
|
62
|
+
end
|
63
|
+
IndiferentHash.setup(hash)
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.positional2hash(keys, *values)
|
67
|
+
if Hash === values.last
|
68
|
+
extra = values.pop
|
69
|
+
inputs = IndiferentHash.zip2hash(keys, values)
|
70
|
+
inputs.delete_if{|k,v| v.nil? or (String === v and v.empty?)}
|
71
|
+
inputs = IndiferentHash.add_defaults inputs, extra
|
72
|
+
inputs.delete_if{|k,v| not keys.include?(k) and not (Symbol === k ? keys.include?(k.to_s) : keys.include?(k.to_sym))}
|
73
|
+
inputs
|
74
|
+
else
|
75
|
+
IndiferentHash.zip2hash(keys, values)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.array2hash(array, default = nil)
|
80
|
+
hash = {}
|
81
|
+
array.each do |key, value|
|
82
|
+
value = default.dup if value.nil? and not default.nil?
|
83
|
+
hash[key] = value
|
84
|
+
end
|
85
|
+
IndiferentHash.setup(hash)
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.process_to_hash(list)
|
89
|
+
result = yield list
|
90
|
+
zip2hash(list, result)
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.hash2string(hash)
|
94
|
+
hash.sort_by{|k,v| k.to_s}.collect{|k,v|
|
95
|
+
next unless %w(Symbol String Float Fixnum Integer Numeric TrueClass FalseClass Module Class Object).include? v.class.to_s
|
96
|
+
[ Symbol === k ? ":" << k.to_s : k.to_s.chomp,
|
97
|
+
Symbol === v ? ":" << v.to_s : v.to_s.chomp] * "="
|
98
|
+
}.compact * "#"
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.string2hash(string)
|
102
|
+
options = {}
|
103
|
+
|
104
|
+
string.split('#').each do |str|
|
105
|
+
key, sep, value = str.partition "="
|
106
|
+
|
107
|
+
key = key[1..-1].to_sym if key[0] == ":"
|
108
|
+
|
109
|
+
options[key] = true and next if value.empty?
|
110
|
+
options[key] = value[1..-1].to_sym and next if value[0] == ":"
|
111
|
+
options[key] = Regexp.new(/#{value[1..-2]}/) and next if value[0] == "/" and value[-1] == "/"
|
112
|
+
options[key] = value[1..-2] and next if value =~ /^['"].*['"]$/
|
113
|
+
options[key] = value.to_i and next if value =~ /^\d+$/
|
114
|
+
options[key] = value.to_f and next if value =~ /^\d*\.\d+$/
|
115
|
+
options[key] = true and next if value == "true"
|
116
|
+
options[key] = false and next if value == "false"
|
117
|
+
options[key] = value and next
|
118
|
+
|
119
|
+
options[key] = begin
|
120
|
+
saved_safe = $SAFE
|
121
|
+
$SAFE = 0
|
122
|
+
eval(value)
|
123
|
+
rescue Exception
|
124
|
+
value
|
125
|
+
ensure
|
126
|
+
$SAFE = saved_safe
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
IndiferentHash.setup(options)
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require_relative 'indiferent_hash/options'
|
2
|
+
require_relative 'indiferent_hash/case_insensitive'
|
3
|
+
|
4
|
+
module IndiferentHash
|
5
|
+
|
6
|
+
def self.setup(hash)
|
7
|
+
hash.extend IndiferentHash
|
8
|
+
hash
|
9
|
+
end
|
10
|
+
|
11
|
+
def merge(other)
|
12
|
+
new = self.dup
|
13
|
+
IndiferentHash.setup(new)
|
14
|
+
other.each do |k,value|
|
15
|
+
new[k] = value
|
16
|
+
end
|
17
|
+
new
|
18
|
+
end
|
19
|
+
|
20
|
+
def []=(key,value)
|
21
|
+
delete(key)
|
22
|
+
super(key,value)
|
23
|
+
end
|
24
|
+
|
25
|
+
def _default?
|
26
|
+
@_default ||= self.default or self.default_proc
|
27
|
+
end
|
28
|
+
|
29
|
+
def [](key)
|
30
|
+
res = super(key)
|
31
|
+
return res unless res.nil? or (_default? and not keys.include? key)
|
32
|
+
|
33
|
+
case key
|
34
|
+
when Symbol, Module
|
35
|
+
super(key.to_s)
|
36
|
+
when String
|
37
|
+
super(key.to_sym)
|
38
|
+
else
|
39
|
+
res
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def values_at(*key_list)
|
44
|
+
key_list.inject([]){|acc,key| acc << self[key]}
|
45
|
+
end
|
46
|
+
|
47
|
+
def include?(key)
|
48
|
+
case key
|
49
|
+
when Symbol, Module
|
50
|
+
super(key) || super(key.to_s)
|
51
|
+
when String
|
52
|
+
super(key) || super(key.to_sym)
|
53
|
+
else
|
54
|
+
super(key)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def delete(key)
|
59
|
+
case key
|
60
|
+
when Symbol, Module
|
61
|
+
super(key) || super(key.to_s)
|
62
|
+
when String
|
63
|
+
super(key) || super(key.to_sym)
|
64
|
+
else
|
65
|
+
super(key)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def clean_version
|
70
|
+
clean = {}
|
71
|
+
each do |k,v|
|
72
|
+
clean[k.to_s] = v unless clean.include? k.to_s
|
73
|
+
end
|
74
|
+
clean
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
module CaseInsensitiveHash
|
79
|
+
|
80
|
+
def self.setup(hash)
|
81
|
+
hash.extend CaseInsensitiveHash
|
82
|
+
end
|
83
|
+
|
84
|
+
def downcase_keys
|
85
|
+
@downcase_keys ||= begin
|
86
|
+
down = {}
|
87
|
+
keys.collect{|key|
|
88
|
+
down[key.to_s.downcase] = key
|
89
|
+
}
|
90
|
+
down
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def [](key, *rest)
|
95
|
+
value = super(key, *rest)
|
96
|
+
return value unless value.nil?
|
97
|
+
key_downcase = key.to_s.downcase
|
98
|
+
super(downcase_keys[key_downcase])
|
99
|
+
end
|
100
|
+
|
101
|
+
def values_at(*keys)
|
102
|
+
keys.collect do |key|
|
103
|
+
self[key]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|