tainted_hash 0.2.0 → 0.3.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 +7 -0
- data/lib/tainted_hash.rb +55 -17
- data/tainted_hash.gemspec +2 -2
- data/test/tainted_hash_test.rb +47 -4
- metadata +8 -12
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ea0d328f383629e28c37a106bc53f7f320fdb827
|
4
|
+
data.tar.gz: 2099a31bf32527f818449a86a9b5774cc24fa24a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 78e0d10bc3b4247e96e172672f1e6f625e7539c298910317ba4ba8bec9f6e88bcf64c2eef690ffe4fa3b025c9e202f819eafa28df1c8a7fcb877ed540288b522
|
7
|
+
data.tar.gz: fd2e58e7e2548c5fc1cdc2c2770219c445f4d4a0663e7e84812e5e0aea7ea02df868b5bfc106d0fa54d307b76805c19ad65a83990e9eb20d5773201e2c9ef89c
|
data/lib/tainted_hash.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
1
|
class TaintedHash < Hash
|
4
|
-
VERSION = "0.
|
2
|
+
VERSION = "0.3.0"
|
5
3
|
|
6
4
|
class UnexposedError < StandardError
|
7
5
|
# Builds an exception when a TaintedHash has some unexposed keys. Useful
|
@@ -30,7 +28,9 @@ class TaintedHash < Hash
|
|
30
28
|
# Public: Gets the original hash that is being wrapped.
|
31
29
|
#
|
32
30
|
# Returns a Hash.
|
33
|
-
|
31
|
+
def original_hash
|
32
|
+
untaint_original_hash(@original_hash)
|
33
|
+
end
|
34
34
|
|
35
35
|
# A Tainted Hash only exposes expected keys. You can either expose them
|
36
36
|
# manually, or through common Hash methods like #values_at or #slice. Once
|
@@ -41,7 +41,7 @@ class TaintedHash < Hash
|
|
41
41
|
#
|
42
42
|
def initialize(hash = nil, new_class = nil)
|
43
43
|
@new_class = new_class || (hash && hash.class) || self.class.default_hash_class
|
44
|
-
@original_hash = hash || @new_class.new
|
44
|
+
@original_hash = (hash && hash.dup) || @new_class.new
|
45
45
|
@exposed_nothing = true
|
46
46
|
|
47
47
|
@original_hash.keys.each do |key|
|
@@ -89,12 +89,22 @@ class TaintedHash < Hash
|
|
89
89
|
# default - A sensible default.
|
90
90
|
#
|
91
91
|
# Returns the value of the key, or the default.
|
92
|
-
def fetch(key, default
|
92
|
+
def fetch(key, *default)
|
93
|
+
raise ArgumentError, "wrong number of arguments (#{default.size + 1} for 1..2)" if default.size > 1
|
94
|
+
|
93
95
|
key_s = key.to_s
|
94
|
-
@original_hash.
|
96
|
+
if @original_hash.key?(key_s)
|
97
|
+
self[key_s]
|
98
|
+
elsif block_given?
|
99
|
+
yield
|
100
|
+
elsif !default.empty?
|
101
|
+
default[0]
|
102
|
+
else
|
103
|
+
raise KeyError, "key not found: #{key}"
|
104
|
+
end
|
95
105
|
end
|
96
106
|
|
97
|
-
# Public: Gets the value for the key
|
107
|
+
# Public: Gets the value for the key but does not expose the key for the Hash.
|
98
108
|
#
|
99
109
|
# key - A String key to retrieve.
|
100
110
|
#
|
@@ -102,7 +112,6 @@ class TaintedHash < Hash
|
|
102
112
|
def [](key)
|
103
113
|
key_s = key.to_s
|
104
114
|
return if !@original_hash.key?(key_s)
|
105
|
-
|
106
115
|
get_original_hash_value(key_s)
|
107
116
|
end
|
108
117
|
|
@@ -138,6 +147,7 @@ class TaintedHash < Hash
|
|
138
147
|
end
|
139
148
|
|
140
149
|
alias key? include?
|
150
|
+
alias has_key? include?
|
141
151
|
|
142
152
|
# Public: Returns the values for the given keys, and exposes the keys.
|
143
153
|
#
|
@@ -145,7 +155,17 @@ class TaintedHash < Hash
|
|
145
155
|
#
|
146
156
|
# Returns an Array of the values (or nil if there is no value) for the keys.
|
147
157
|
def values_at(*keys)
|
148
|
-
|
158
|
+
keys.map { |k| self[k] }
|
159
|
+
end
|
160
|
+
|
161
|
+
# Public: Produces a copy of the current Hash with the same set of exposed
|
162
|
+
# keys as the original Hash.
|
163
|
+
#
|
164
|
+
# Returns a dup of this TaintedHash.
|
165
|
+
def dup
|
166
|
+
super.tap do |duplicate|
|
167
|
+
duplicate.instance_variable_set :@original_hash, @original_hash.dup
|
168
|
+
end
|
149
169
|
end
|
150
170
|
|
151
171
|
# Public: Merges the given hash with the internal and a dup of the current
|
@@ -165,7 +185,7 @@ class TaintedHash < Hash
|
|
165
185
|
# Returns this TaintedHash.
|
166
186
|
def update(hash)
|
167
187
|
hash.each do |key, value|
|
168
|
-
|
188
|
+
self[key.to_s] = value
|
169
189
|
end
|
170
190
|
self
|
171
191
|
end
|
@@ -218,6 +238,24 @@ private
|
|
218
238
|
@original_hash[key_s] = value
|
219
239
|
end
|
220
240
|
|
241
|
+
# Private: Returns a regular Hash, transforming all embedded TaintedHash
|
242
|
+
# objects into regular Hash objects with all keys exposed.
|
243
|
+
#
|
244
|
+
# original_hash - The @original_hash you want to untaint
|
245
|
+
#
|
246
|
+
#
|
247
|
+
# Returns a Hash
|
248
|
+
def untaint_original_hash(original_hash)
|
249
|
+
hash = @new_class.new
|
250
|
+
original_hash.each do |key, value|
|
251
|
+
hash[key] = case value
|
252
|
+
when TaintedHash then untaint_original_hash(value.instance_variable_get :@original_hash)
|
253
|
+
else value
|
254
|
+
end
|
255
|
+
end
|
256
|
+
hash
|
257
|
+
end
|
258
|
+
|
221
259
|
module RailsMethods
|
222
260
|
def self.included(base)
|
223
261
|
base.send :alias_method, :stringify_keys!, :stringify_keys
|
@@ -229,16 +267,16 @@ private
|
|
229
267
|
#
|
230
268
|
# Returns a Hash of the requested keys and values.
|
231
269
|
def slice(*keys)
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
hash[key] = @original_hash[key]
|
270
|
+
keys.each_with_object(self.class.new) do |key, hash|
|
271
|
+
key_s = key.to_s
|
272
|
+
hash[key_s] = @original_hash[key_s] if @original_hash.key?(key_s)
|
236
273
|
end
|
237
|
-
hash
|
238
274
|
end
|
239
275
|
|
240
276
|
def slice!(*keys)
|
241
|
-
|
277
|
+
str_keys = keys.map { |k| k.to_s }
|
278
|
+
(@original_hash.keys - str_keys).each { |key| delete(key) }
|
279
|
+
expose(*str_keys)
|
242
280
|
end
|
243
281
|
|
244
282
|
def stringify_keys
|
data/tainted_hash.gemspec
CHANGED
@@ -12,8 +12,8 @@ Gem::Specification.new do |s|
|
|
12
12
|
## If your rubyforge_project name is different, then edit it and comment out
|
13
13
|
## the sub! line in the Rakefile
|
14
14
|
s.name = 'tainted_hash'
|
15
|
-
s.version = '0.
|
16
|
-
s.date = '2013-
|
15
|
+
s.version = '0.3.0'
|
16
|
+
s.date = '2013-10-09'
|
17
17
|
s.rubyforge_project = 'tainted_hash'
|
18
18
|
|
19
19
|
## Make sure your summary is short. The description may be as long
|
data/test/tainted_hash_test.rb
CHANGED
@@ -29,12 +29,36 @@ class TaintedHashTest < Test::Unit::TestCase
|
|
29
29
|
assert @hash.include?('c')
|
30
30
|
end
|
31
31
|
|
32
|
+
def test_merge
|
33
|
+
@tainted.expose(:a)
|
34
|
+
merged = @tainted.merge('d' => 3)
|
35
|
+
assert_equal %w(a), @tainted.keys.sort
|
36
|
+
assert_equal %w(a d), merged.keys.sort
|
37
|
+
assert_equal %w(a b c), @tainted.original_hash.keys.sort
|
38
|
+
assert_equal %w(a b c d), merged.original_hash.keys.sort
|
39
|
+
end
|
40
|
+
|
32
41
|
def test_dup
|
33
|
-
@tainted[:c].expose :name
|
34
42
|
@tainted.expose :a
|
35
|
-
dup = @tainted.dup
|
43
|
+
dup = @tainted.dup
|
44
|
+
dup.expose :b
|
36
45
|
assert_equal %w(a), @tainted.keys.sort
|
37
46
|
assert_equal %w(a b), dup.keys.sort
|
47
|
+
@tainted[:d] = 3
|
48
|
+
dup[:e] = 4
|
49
|
+
assert_equal %w(a d), @tainted.keys.sort
|
50
|
+
assert_equal %w(a b e), dup.keys.sort
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_expose_all
|
54
|
+
@tainted.expose_all
|
55
|
+
assert_equal %w(a b c), @tainted.keys.sort
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_original_hash
|
59
|
+
assert_equal @hash, @tainted.original_hash
|
60
|
+
assert_equal @hash.merge('d' => 3), @tainted.merge('d' => 3).original_hash
|
61
|
+
assert_equal @hash, @tainted.expose_all.original_hash
|
38
62
|
end
|
39
63
|
|
40
64
|
def test_expose_keys
|
@@ -50,6 +74,10 @@ class TaintedHashTest < Test::Unit::TestCase
|
|
50
74
|
assert !@tainted.include?(:d)
|
51
75
|
assert_equal 1, @tainted.fetch(:a, :default)
|
52
76
|
assert_equal :default, @tainted.fetch(:d, :default)
|
77
|
+
assert_raises KeyError do
|
78
|
+
@tainted.fetch(:d)
|
79
|
+
end
|
80
|
+
assert_equal :default, @tainted.fetch(:d) { :default }
|
53
81
|
assert !@tainted.include?(:a)
|
54
82
|
assert !@tainted.include?(:d)
|
55
83
|
end
|
@@ -137,8 +165,8 @@ class TaintedHashTest < Test::Unit::TestCase
|
|
137
165
|
assert !@tainted.include?(:a)
|
138
166
|
assert !@tainted.include?(:d)
|
139
167
|
@tainted.update :a => 2, :d => 1
|
140
|
-
assert
|
141
|
-
assert
|
168
|
+
assert @tainted.include?(:a)
|
169
|
+
assert @tainted.include?(:d)
|
142
170
|
assert_equal 2, @tainted[:a]
|
143
171
|
assert_equal 1, @tainted[:d]
|
144
172
|
end
|
@@ -188,4 +216,19 @@ class TaintedHashTest < Test::Unit::TestCase
|
|
188
216
|
slice = @tainted.slice :a, :d
|
189
217
|
assert_equal({'a' => 1}, slice.to_hash)
|
190
218
|
end
|
219
|
+
|
220
|
+
def test_slice_bang_modifies_self
|
221
|
+
@tainted.slice! :a, :d
|
222
|
+
assert_equal({'a' => 1}, @tainted.to_hash)
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_include_aliases
|
226
|
+
assert !@tainted.include?(:a)
|
227
|
+
assert !@tainted.has_key?(:a)
|
228
|
+
assert !@tainted.key?(:a)
|
229
|
+
@tainted[:a] = 2
|
230
|
+
assert @tainted.include?(:a)
|
231
|
+
assert @tainted.has_key?(:a)
|
232
|
+
assert @tainted.key?(:a)
|
233
|
+
end
|
191
234
|
end
|
metadata
CHANGED
@@ -1,30 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tainted_hash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.3.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Rick Olson
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-10-09 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: test-unit
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
30
27
|
description: Hash wrapper.
|
@@ -42,25 +39,24 @@ files:
|
|
42
39
|
- test/tainted_hash_test.rb
|
43
40
|
homepage: https://github.com/technoweenie/tainted_hash
|
44
41
|
licenses: []
|
42
|
+
metadata: {}
|
45
43
|
post_install_message:
|
46
44
|
rdoc_options: []
|
47
45
|
require_paths:
|
48
46
|
- lib
|
49
47
|
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
-
none: false
|
51
48
|
requirements:
|
52
|
-
- -
|
49
|
+
- - '>='
|
53
50
|
- !ruby/object:Gem::Version
|
54
51
|
version: '0'
|
55
52
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
-
none: false
|
57
53
|
requirements:
|
58
|
-
- -
|
54
|
+
- - '>='
|
59
55
|
- !ruby/object:Gem::Version
|
60
56
|
version: 1.3.5
|
61
57
|
requirements: []
|
62
58
|
rubyforge_project: tainted_hash
|
63
|
-
rubygems_version:
|
59
|
+
rubygems_version: 2.0.3
|
64
60
|
signing_key:
|
65
61
|
specification_version: 2
|
66
62
|
summary: Hash wrapper.
|