tainted_hash 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -1,7 +1,5 @@
1
- require 'set'
2
-
3
1
  class TaintedHash < Hash
4
- VERSION = "0.2.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
- attr_reader :original_hash
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 = nil)
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.fetch key_s, default
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, and exposes the key for the Hash.
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
- @original_hash.values_at *keys.map { |k| k.to_s }
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
- @original_hash[key.to_s] = value
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
- str_keys = @original_hash.keys & keys.map { |k| k.to_s }
233
- hash = self.class.new
234
- str_keys.each do |key|
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
- raise NotImplementedError
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
@@ -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.2.0'
16
- s.date = '2013-07-16'
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
@@ -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.expose :b
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 !@tainted.include?(:a)
141
- assert !@tainted.include?(:d)
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.2.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-07-16 00:00:00.000000000 Z
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: 1.8.23
59
+ rubygems_version: 2.0.3
64
60
  signing_key:
65
61
  specification_version: 2
66
62
  summary: Hash wrapper.