tofuhash 0.1.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.
- data/lib/tofuhash/tofuhash.rb +159 -0
- data/lib/tofuhash/tofukey.rb +90 -0
- data/lib/tofuhash.rb +44 -0
- data/readme.txt +100 -0
- data/test/test-tofuhash.rb +285 -0
- metadata +53 -0
@@ -0,0 +1,159 @@
|
|
1
|
+
# TofuHash
|
2
|
+
#
|
3
|
+
# Links:
|
4
|
+
# * readme.txt[link:files/readme_txt.html]
|
5
|
+
# * source: http://github.com/ghouston/tofuhash/tree/master
|
6
|
+
#
|
7
|
+
# A varient of Hash which can change the lookup behavior of keys.
|
8
|
+
# The default TofuHash will match Symbol and String without reguard
|
9
|
+
# to case. By subclassing TofuKey, this behavior can be changed.
|
10
|
+
#
|
11
|
+
#
|
12
|
+
# License:
|
13
|
+
#
|
14
|
+
# (The MIT License + Free Software Foundation Advertising Prohibition)
|
15
|
+
#
|
16
|
+
# Copyright (c) 2007 Gregory N. Houston
|
17
|
+
#
|
18
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
19
|
+
# of this software and associated documentation files (the "Software"), to deal
|
20
|
+
# in the Software without restriction, including without limitation the rights
|
21
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
22
|
+
# copies of the Software, and to permit persons to whom the Software is
|
23
|
+
# furnished to do so, subject to the following conditions:
|
24
|
+
#
|
25
|
+
# The above copyright notice and this permission notice shall be included in
|
26
|
+
# all copies or substantial portions of the Software.
|
27
|
+
#
|
28
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
29
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
30
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
31
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
32
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
33
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
34
|
+
# THE SOFTWARE.
|
35
|
+
#
|
36
|
+
# Except as contained in this notice, the name(s) of the above copyright holders
|
37
|
+
# shall not be used in advertising or otherwise to promote the sale, use or other
|
38
|
+
# dealings in this Software without prior written authorization.
|
39
|
+
#
|
40
|
+
class TofuHash < Hash
|
41
|
+
module Version
|
42
|
+
MAJOR = 0
|
43
|
+
MINOR = 1
|
44
|
+
REVISION = 0
|
45
|
+
STRING = [MAJOR, MINOR, REVISION].join('.')
|
46
|
+
end
|
47
|
+
|
48
|
+
# see Hash.new
|
49
|
+
def initialize ( default = nil )
|
50
|
+
if block_given?
|
51
|
+
if default
|
52
|
+
raise ArgumentError, "Can't initialize Hash with both a default value and a block"
|
53
|
+
end
|
54
|
+
super() { |hash,key| yield(hash, decode(key)) }
|
55
|
+
else
|
56
|
+
super
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# see Hash#encode
|
61
|
+
def encode( key )
|
62
|
+
TofuKey.new(key)
|
63
|
+
end
|
64
|
+
|
65
|
+
# see Hash#decode
|
66
|
+
def decode( key )
|
67
|
+
key.decode
|
68
|
+
end
|
69
|
+
|
70
|
+
class << self
|
71
|
+
# see Hash.[]
|
72
|
+
def [](*args)
|
73
|
+
if args.size == 1 && args[0].instance_of?( Object::Hash )
|
74
|
+
h = TofuHash.new
|
75
|
+
args[0].each { |k,v| h.store( k,v ) }
|
76
|
+
h
|
77
|
+
elsif (args.size % 2 != 0)
|
78
|
+
raise ArgumentError, "odd number of arguments for TofuHash"
|
79
|
+
else
|
80
|
+
h = TofuHash.new
|
81
|
+
1.step( args.size, 2 ) { |i| h.store(args[i-1],args[i]) }
|
82
|
+
h
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# see Hash#[]=
|
88
|
+
def []= key,value
|
89
|
+
super( encode(key), value )
|
90
|
+
end
|
91
|
+
|
92
|
+
alias :regular_each :each unless method_defined?(:regular_each)
|
93
|
+
|
94
|
+
# see Hash#each
|
95
|
+
def each &block
|
96
|
+
self.regular_each do |key, value|
|
97
|
+
block.call( decode(key), value )
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# see Hash#store
|
102
|
+
def store key, value
|
103
|
+
super( encode(key), value )
|
104
|
+
end
|
105
|
+
|
106
|
+
# see Hash#[]
|
107
|
+
def [] key
|
108
|
+
super( encode(key) )
|
109
|
+
end
|
110
|
+
|
111
|
+
# see Hash#has_key?
|
112
|
+
def has_key? key
|
113
|
+
super( encode(key) )
|
114
|
+
end
|
115
|
+
|
116
|
+
# see Hash#keys
|
117
|
+
def keys
|
118
|
+
# collect will call each which decodes the key
|
119
|
+
self.collect { |k,v| k }
|
120
|
+
end
|
121
|
+
|
122
|
+
alias_method :regular_inspect, :inspect unless method_defined?(:regular_inspect)
|
123
|
+
|
124
|
+
# see Hash#values_at
|
125
|
+
def values_at( *args )
|
126
|
+
values = Array.new
|
127
|
+
args.each { |key| values << self[key] }
|
128
|
+
values
|
129
|
+
end
|
130
|
+
|
131
|
+
# see Hash#to_a
|
132
|
+
def to_a
|
133
|
+
aux = []
|
134
|
+
self.each do |key,value|
|
135
|
+
aux << [ key, value ]
|
136
|
+
end
|
137
|
+
aux
|
138
|
+
end
|
139
|
+
|
140
|
+
# see Hash#include?
|
141
|
+
def include?(key)
|
142
|
+
super(encode(key))
|
143
|
+
end
|
144
|
+
|
145
|
+
alias :regular_delete_if :delete_if
|
146
|
+
|
147
|
+
# see Hash#delete_if
|
148
|
+
def delete_if(&block)
|
149
|
+
self.regular_delete_if do |key, value|
|
150
|
+
block.call( decode(key), value)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Deletes every key-value pair for which block evaluates to false.
|
155
|
+
def delete_unless #:yield:
|
156
|
+
delete_if{ |key, value| ! yield(key, value) }
|
157
|
+
end
|
158
|
+
|
159
|
+
end # class TofuHash
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# TofuKey
|
2
|
+
#
|
3
|
+
# Links:
|
4
|
+
# * readme.txt[link:files/readme_txt.html]
|
5
|
+
# * source: http://github.com/ghouston/tofuhash/tree/master
|
6
|
+
#
|
7
|
+
# For use with TofuHash. A wrapper for the key of a Hash which will alter the behavior of keys.
|
8
|
+
# The behavior provided by default is case-insensitive, and indifferent access for strings and symbols.
|
9
|
+
# By subclassing TofuHash, you can create your own behavior.
|
10
|
+
#
|
11
|
+
# License:
|
12
|
+
#
|
13
|
+
# (The MIT License + Free Software Foundation Advertising Prohibition)
|
14
|
+
#
|
15
|
+
# Copyright (c) 2007 Gregory N. Houston
|
16
|
+
#
|
17
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
18
|
+
# of this software and associated documentation files (the "Software"), to deal
|
19
|
+
# in the Software without restriction, including without limitation the rights
|
20
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
21
|
+
# copies of the Software, and to permit persons to whom the Software is
|
22
|
+
# furnished to do so, subject to the following conditions:
|
23
|
+
#
|
24
|
+
# The above copyright notice and this permission notice shall be included in
|
25
|
+
# all copies or substantial portions of the Software.
|
26
|
+
#
|
27
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
28
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
29
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
30
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
31
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
32
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
33
|
+
# THE SOFTWARE.
|
34
|
+
#
|
35
|
+
# Except as contained in this notice, the name(s) of the above copyright holders
|
36
|
+
# shall not be used in advertising or otherwise to promote the sale, use or other
|
37
|
+
# dealings in this Software without prior written authorization.
|
38
|
+
#
|
39
|
+
class TofuKey
|
40
|
+
attr_reader :original_key, :coded_key
|
41
|
+
|
42
|
+
# preserve the key (Strings are cloned and frozen just like Hash's behavior); then encodes the key for fast comparison
|
43
|
+
def initialize( key )
|
44
|
+
if key.instance_of? String
|
45
|
+
@original_key = key.clone.freeze
|
46
|
+
else
|
47
|
+
@original_key = key
|
48
|
+
end
|
49
|
+
encode
|
50
|
+
end
|
51
|
+
|
52
|
+
# stores a @coded_key which is used for quick comparison and as the hash key. the default encoding will
|
53
|
+
# convert Symbols to downcased strings; anything responding to downcase is converted via downcase.
|
54
|
+
def encode
|
55
|
+
if @original_key.instance_of? Symbol
|
56
|
+
@coded_key = @original_key.to_s.downcase
|
57
|
+
elsif @original_key.respond_to? :downcase
|
58
|
+
@coded_key = @original_key.downcase
|
59
|
+
else
|
60
|
+
@coded_key = @original_key
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# returns the preserved key
|
65
|
+
def decode
|
66
|
+
@original_key
|
67
|
+
end
|
68
|
+
|
69
|
+
# get the hash of the key, which calls #hash on the encoded key.
|
70
|
+
def hash
|
71
|
+
@coded_key.hash
|
72
|
+
end
|
73
|
+
|
74
|
+
# compares the encoded key to another object.
|
75
|
+
#
|
76
|
+
# given symbols are converted to downcase strings before comparison.
|
77
|
+
# given objects which respond to downcase are downcased before comparison.
|
78
|
+
# given TofuKey will compare the encoded keys.
|
79
|
+
def eql? obj
|
80
|
+
if obj.instance_of? Symbol
|
81
|
+
@coded_key.eql?( obj.to_s.downcase )
|
82
|
+
elsif obj.instance_of? TofuKey
|
83
|
+
@coded_key.eql?( obj.coded_key )
|
84
|
+
elsif obj.respond_to? :downcase
|
85
|
+
@coded_key.eql?( obj.downcase )
|
86
|
+
else
|
87
|
+
@coded_key.eql?( obj )
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/tofuhash.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# TofuHash
|
2
|
+
#
|
3
|
+
# Links:
|
4
|
+
# * readme.txt[link:files/readme_txt.html]
|
5
|
+
# * source: http://github.com/ghouston/tofuhash/tree/master
|
6
|
+
#
|
7
|
+
# A varient of Hash which can change the lookup behavior of keys.
|
8
|
+
# The default TofuHash will match Symbol and String without reguard
|
9
|
+
# to case. By subclassing TofuKey, this behavior can be changed.
|
10
|
+
#
|
11
|
+
# License:
|
12
|
+
#
|
13
|
+
# (The MIT License + Free Software Foundation Advertising Prohibition)
|
14
|
+
#
|
15
|
+
# Copyright (c) 2007 Gregory N. Houston
|
16
|
+
#
|
17
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
18
|
+
# of this software and associated documentation files (the "Software"), to deal
|
19
|
+
# in the Software without restriction, including without limitation the rights
|
20
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
21
|
+
# copies of the Software, and to permit persons to whom the Software is
|
22
|
+
# furnished to do so, subject to the following conditions:
|
23
|
+
#
|
24
|
+
# The above copyright notice and this permission notice shall be included in
|
25
|
+
# all copies or substantial portions of the Software.
|
26
|
+
#
|
27
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
28
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
29
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
30
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
31
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
32
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
33
|
+
# THE SOFTWARE.
|
34
|
+
#
|
35
|
+
# Except as contained in this notice, the name(s) of the above copyright holders
|
36
|
+
# shall not be used in advertising or otherwise to promote the sale, use or other
|
37
|
+
# dealings in this Software without prior written authorization.
|
38
|
+
#
|
39
|
+
unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
40
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__)))
|
41
|
+
end
|
42
|
+
|
43
|
+
require 'tofuhash/tofukey'
|
44
|
+
require 'tofuhash/tofuhash'
|
data/readme.txt
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
= TofuHash
|
2
|
+
by Gregory N. Houston
|
3
|
+
|
4
|
+
TofuHash makes it possible to use a Hash without having to
|
5
|
+
worry about the differences between using String, Symbol,
|
6
|
+
uppercase and downcase for the keys.
|
7
|
+
TofuHash is both a case-insensitive Hash, and indifferent
|
8
|
+
to access by String or Symbol.
|
9
|
+
|
10
|
+
for Example:
|
11
|
+
|
12
|
+
require 'tofuhash'
|
13
|
+
h = TofuHash[ :aSymbol => "symbol", "MixedCaseString" => "string", 11 => "number" ]
|
14
|
+
puts h["asymbol"] #=> "symbol"
|
15
|
+
puts h[:mixedCaseString] #=> "string"
|
16
|
+
puts h[11] #=> "number"
|
17
|
+
|
18
|
+
Version:: 0.1.0 A useful and well tested subset of Hash methods is available.
|
19
|
+
|
20
|
+
Tested to work with:
|
21
|
+
Ruby 1.8.6
|
22
|
+
Ruby 1.9.1
|
23
|
+
|
24
|
+
How is TofuHash differenct than Hash?
|
25
|
+
* TofuHash wraps the key into a TofuKey which is used internally inside TofuHash.
|
26
|
+
The TofuKey defines new behavior for handling the key. By
|
27
|
+
default it will treat Symbol, String, and uppercase vs downcase as the same. This
|
28
|
+
behavior can be changed by creating TofuHash and providing an alternative
|
29
|
+
version of TofuKey.
|
30
|
+
|
31
|
+
* TofuHash adds the method TofuHash#delete_unless
|
32
|
+
|
33
|
+
== Links:
|
34
|
+
|
35
|
+
Start Here:: http://tofuhash.rubyforge.org
|
36
|
+
|
37
|
+
Project:: http://rubyforge.org/projects/tofuhash
|
38
|
+
Documents:: http://tofuhash.rubyforge.org
|
39
|
+
RubyGems:: Install with: <b>gem install tofuhash</b>
|
40
|
+
Download:: Download from RubyForge at http://rubyforge.org/projects/tofuhash/
|
41
|
+
Authors Blog:: http://ghouston.blogspot.com
|
42
|
+
Browse Source:: link:rcov/index.html
|
43
|
+
Source code is hosted on Github at: http://github.com/ghouston/tofuhash/tree/master
|
44
|
+
|
45
|
+
== LICENSE:
|
46
|
+
|
47
|
+
(The MIT License + Free Software Foundation Advertising Prohibition)
|
48
|
+
|
49
|
+
Copyright (c) 2007 Gregory N. Houston
|
50
|
+
|
51
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
52
|
+
of this software and associated documentation files (the "Software"), to deal
|
53
|
+
in the Software without restriction, including without limitation the rights
|
54
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
55
|
+
copies of the Software, and to permit persons to whom the Software is
|
56
|
+
furnished to do so, subject to the following conditions:
|
57
|
+
|
58
|
+
The above copyright notice and this permission notice shall be included in
|
59
|
+
all copies or substantial portions of the Software.
|
60
|
+
|
61
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
62
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
63
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
64
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
65
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
66
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
67
|
+
THE SOFTWARE.
|
68
|
+
|
69
|
+
Except as contained in this notice, the name(s) of the above copyright holders
|
70
|
+
shall not be used in advertising or otherwise to promote the sale, use or other
|
71
|
+
dealings in this Software without prior written authorization.
|
72
|
+
|
73
|
+
The file test-tofuhash.rb is released under the Ruby License since it
|
74
|
+
contains source code based on Ruby's released source.
|
75
|
+
|
76
|
+
== Credits:
|
77
|
+
|
78
|
+
Inspired by:
|
79
|
+
* http://pastie.caboo.se/154304 and used with Stefan Rusterholz's permission;
|
80
|
+
* HashWithIndifferentAccess in Rail's ActiveSupport.
|
81
|
+
|
82
|
+
Contributors:
|
83
|
+
* Greg Houston (http://ghouston.blogspot.com) original release and project maintainer
|
84
|
+
* Nacho Caballero (http://github.com/nachocab/) added #to_a, #delete_if, #delete_unless, #include?
|
85
|
+
|
86
|
+
== Release History:
|
87
|
+
|
88
|
+
Feb 28 2009 - 0.1.0 release on rubyforge. Added gem, rdoc, rcov output.
|
89
|
+
Added TofuHash::Version module
|
90
|
+
|
91
|
+
Feb 15 2009 - 0.0.2 released on git hub. Merged in pull request from
|
92
|
+
http://github.com/nachocab/tofuhash/tree/master [Thanks nachocab!]
|
93
|
+
nachocab added to_a, delete_if, delete_unless, include? methods. nachocab also
|
94
|
+
updated the exception raised when TofuHash#initialize is called with both
|
95
|
+
a default value and default block. It now raises "wrong number of arguments"
|
96
|
+
which matches the behavior of Hash. I (ghouston) tweaked the test cases to match
|
97
|
+
the examples from Hash's ri documentation.
|
98
|
+
|
99
|
+
Dec 12 2008 - 0.0.1 released on git hub. Working solution, only more complete
|
100
|
+
testing is needed. Know issues: a) Hash doesn't know how to compare with TofuHash.
|
@@ -0,0 +1,285 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'pp'
|
3
|
+
require 'lib/tofuhash'
|
4
|
+
|
5
|
+
=begin rdoc
|
6
|
+
test-tofuhash.rb
|
7
|
+
|
8
|
+
Test cases for TofuHash. This includes modified versions of Ruby's unit tests
|
9
|
+
for Hash, and Ruby's Hash examples in the ri documentation. Plus some custom
|
10
|
+
tests to validate similarities between Hash and TofuHash.
|
11
|
+
|
12
|
+
Version: see readme.txt for details.
|
13
|
+
|
14
|
+
License:
|
15
|
+
|
16
|
+
tofuhash.rb is released under the MIT License + Free Software Foundation
|
17
|
+
Advertising Prohibition. see readme.txt file for details.
|
18
|
+
|
19
|
+
test-tofuhash.rb (this file) is released under the Ruby License since it
|
20
|
+
contains source code based on Ruby's released source.
|
21
|
+
=end
|
22
|
+
|
23
|
+
module TofuHashTesting
|
24
|
+
class Test_TofuHash < Test::Unit::TestCase
|
25
|
+
def test_new
|
26
|
+
assert_raise ArgumentError do
|
27
|
+
h = TofuHash.new( :default ) { |hash,key| key }
|
28
|
+
end
|
29
|
+
|
30
|
+
h = TofuHash.new
|
31
|
+
assert_equal( 0, h.size )
|
32
|
+
assert_equal( nil, h[:missing] )
|
33
|
+
|
34
|
+
h = TofuHash.new( :default )
|
35
|
+
assert_equal( 0, h.size )
|
36
|
+
assert_equal( :default, h[:missing] )
|
37
|
+
|
38
|
+
h = TofuHash.new do |hash,key|
|
39
|
+
assert_equal( :missing, key )
|
40
|
+
assert_same( h, hash )
|
41
|
+
hash[key] = :default_block
|
42
|
+
end
|
43
|
+
assert_equal( 0, h.size )
|
44
|
+
assert_equal( :default_block, h[:missing] )
|
45
|
+
assert_equal( 1, h.size )
|
46
|
+
assert_equal( [:missing], h.keys )
|
47
|
+
assert_equal( [:default_block], h.values )
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_values_at
|
51
|
+
h = TofuHash[21=>22,22=>24,23=>26,24=>28]
|
52
|
+
assert_equal([24,26], h.values_at( 22, 23 ))
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_keys
|
56
|
+
h = TofuHash["Alpha"=>2,:betA=>4,"gAmmA"=>6]
|
57
|
+
assert_equal( ["Alpha",:betA,"gAmmA"], h.keys.sort { |a,b| a.to_s <=> b.to_s } )
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_square_bracket_initializer
|
61
|
+
h = TofuHash[:a=>:b, :c=>:d]
|
62
|
+
assert_equal( TofuHash, h.class )
|
63
|
+
assert_equal( :b, h[:a] )
|
64
|
+
assert_equal( :d, h[:c] )
|
65
|
+
assert_equal( 2, h.size )
|
66
|
+
|
67
|
+
assert_raise ArgumentError do
|
68
|
+
h = TofuHash[1,2,3]
|
69
|
+
end
|
70
|
+
|
71
|
+
h = TofuHash[:happy, :sad, :rich, :poor]
|
72
|
+
assert_equal( TofuHash, h.class )
|
73
|
+
assert_equal( :sad, h[:happy] )
|
74
|
+
assert_equal( :poor, h[:rich] )
|
75
|
+
assert_equal( 2, h.size )
|
76
|
+
h = TofuHash[]
|
77
|
+
assert_equal( 0, h.size )
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_store
|
81
|
+
h = TofuHash.new
|
82
|
+
h.store('Alpha',1)
|
83
|
+
h.store(1,'ALPHA')
|
84
|
+
assert_equal( 1, h['AlPhA'] )
|
85
|
+
assert_equal( 'ALPHA', h[1] )
|
86
|
+
|
87
|
+
h['Beta']=2
|
88
|
+
h[2] = 'Beta'
|
89
|
+
assert_equal( 2, h['bEtA'] )
|
90
|
+
assert_equal( 'Beta', h[2] )
|
91
|
+
|
92
|
+
h[:Gamma]=3
|
93
|
+
h[3] = 'Gamma'
|
94
|
+
assert_equal( 3, h[:Gamma] )
|
95
|
+
assert_equal( 3, h['Gamma'] )
|
96
|
+
assert_equal( 3, h['gAmMA'] )
|
97
|
+
assert_equal( 3, h[:gAMMA] )
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_each
|
101
|
+
h = TofuHash[15,16, 11,12, 19,20, 17,18, 13,14]
|
102
|
+
h.each { |k,v| assert_equal( k+1, v ) }
|
103
|
+
end
|
104
|
+
end # class Test_TofuHash
|
105
|
+
|
106
|
+
# copied from /ruby/src/ruby-1.8.6/test/ruby/test_hash.rb
|
107
|
+
# modified to use TofuHash instead of Hash
|
108
|
+
class TestHash < Test::Unit::TestCase
|
109
|
+
def test_hash
|
110
|
+
x = TofuHash[1=>2, 2=>4, 3=>6]
|
111
|
+
y = TofuHash[1, 2, 2, 4, 3, 6]
|
112
|
+
assert_equal(2, x[1])
|
113
|
+
|
114
|
+
assert(begin
|
115
|
+
for k,v in y
|
116
|
+
raise if k*2 != v
|
117
|
+
end
|
118
|
+
true
|
119
|
+
rescue
|
120
|
+
false
|
121
|
+
end)
|
122
|
+
|
123
|
+
assert_equal(3, x.length)
|
124
|
+
assert(x.has_key?(1))
|
125
|
+
assert(x.has_value?(4))
|
126
|
+
assert_equal([4,6], x.values_at(2,3))
|
127
|
+
assert_equal(TofuHash[1=>2, 2=>4, 3=>6], x)
|
128
|
+
|
129
|
+
z = y.keys.join(":")
|
130
|
+
assert_equal("1:2:3", z)
|
131
|
+
|
132
|
+
z = y.values.join(":")
|
133
|
+
assert_equal("2:4:6", z)
|
134
|
+
assert_equal(x, y)
|
135
|
+
|
136
|
+
y.shift
|
137
|
+
assert_equal(2, y.length)
|
138
|
+
|
139
|
+
z = [1,2]
|
140
|
+
y[z] = 256
|
141
|
+
assert_equal(256, y[z])
|
142
|
+
|
143
|
+
x = TofuHash.new(0)
|
144
|
+
x[1] = 1
|
145
|
+
assert_equal(1, x[1])
|
146
|
+
assert_equal(0, x[2])
|
147
|
+
|
148
|
+
x = TofuHash.new([])
|
149
|
+
assert_equal([], x[22])
|
150
|
+
assert_same(x[22], x[22])
|
151
|
+
|
152
|
+
x = TofuHash.new{[]}
|
153
|
+
assert_equal([], x[22])
|
154
|
+
assert_not_same(x[22], x[22])
|
155
|
+
|
156
|
+
x = TofuHash.new{|h,k| z = k; h[k] = k*2}
|
157
|
+
z = 0
|
158
|
+
assert_equal(44, x[22])
|
159
|
+
assert_equal(22, z)
|
160
|
+
z = 0
|
161
|
+
assert_equal(44, x[22])
|
162
|
+
assert_equal(0, z)
|
163
|
+
x.default = 5
|
164
|
+
assert_equal(5, x[23])
|
165
|
+
|
166
|
+
x = TofuHash.new
|
167
|
+
def x.default(k)
|
168
|
+
k = decode(k)
|
169
|
+
$z = k
|
170
|
+
self[k] = k*2
|
171
|
+
end
|
172
|
+
$z = 0
|
173
|
+
assert_equal(44, x[22])
|
174
|
+
assert_equal(22, $z)
|
175
|
+
$z = 0
|
176
|
+
assert_equal(44, x[22])
|
177
|
+
assert_equal(0, $z)
|
178
|
+
end
|
179
|
+
|
180
|
+
class MyClass
|
181
|
+
attr_reader :str
|
182
|
+
def initialize(str)
|
183
|
+
@str = str
|
184
|
+
end
|
185
|
+
def eql?(o)
|
186
|
+
o.is_a?(MyClass) && str == o.str
|
187
|
+
end
|
188
|
+
def hash
|
189
|
+
@str.hash
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def test_ri_hash_code
|
194
|
+
a = MyClass.new("some string")
|
195
|
+
b = MyClass.new("some string")
|
196
|
+
assert( a.eql?( b ) ) #=> true
|
197
|
+
|
198
|
+
h = TofuHash.new #was: h={}
|
199
|
+
|
200
|
+
h[a] = 1
|
201
|
+
assert_equal( h[a],1 ) #=> 1
|
202
|
+
assert_equal( h[b],1 ) #=> 1
|
203
|
+
|
204
|
+
h[b] = 2
|
205
|
+
assert_equal( h[a],2 ) #=> 2
|
206
|
+
assert_equal( h[b],2 ) #=> 2
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_ri_hash_new_code
|
210
|
+
h = TofuHash.new("Go Fish")
|
211
|
+
h["a"] = 100
|
212
|
+
h["b"] = 200
|
213
|
+
assert_equal( h["a"], 100 ) #=> 100
|
214
|
+
assert_equal( h["c"], "Go Fish" ) #=> "Go Fish"
|
215
|
+
# The following alters the single default object
|
216
|
+
assert_equal( h["c"].upcase!, "GO FISH" ) #=> "GO FISH"
|
217
|
+
assert_equal( h["d"], "GO FISH" ) #=> "GO FISH"
|
218
|
+
assert_equal( h.keys, ["a","b"] ) #=> ["a", "b"]
|
219
|
+
|
220
|
+
# While this creates a new default object each time
|
221
|
+
h = TofuHash.new { |hash, key| hash[key] = "Go Fish: #{key}" }
|
222
|
+
assert_equal( h["c"], "Go Fish: c" ) #=> "Go Fish: c"
|
223
|
+
assert_equal( h["c"].upcase!, "GO FISH: C" ) #=> "GO FISH: C"
|
224
|
+
assert_equal( h["d"], "Go Fish: d" ) #=> "Go Fish: d"
|
225
|
+
assert_equal( h.keys, ["c","d"] ) #=> ["c", "d"]
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_ri_hash_square_bracket_code
|
229
|
+
assert_equal( TofuHash["a", 100, "b", 200], {"a"=>100, "b"=>200} ) #=> {"a"=>100, "b"=>200}
|
230
|
+
assert_equal( TofuHash["a" => 100, "b" => 200], {"a"=>100, "b"=>200} ) #=> {"a"=>100, "b"=>200}
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_to_a
|
234
|
+
hash = TofuHash["a" => 2, "b" => 1]
|
235
|
+
assert_equal [["a",2],["b",1]], hash.to_a
|
236
|
+
end
|
237
|
+
|
238
|
+
def test_ri_to_a
|
239
|
+
h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300 }
|
240
|
+
result = h.to_a
|
241
|
+
sorted = h.to_a.sort { |a,b| a[0] <=> b[0] }
|
242
|
+
assert_equal( [['a',100],['c',300],['d',400]], sorted )
|
243
|
+
end
|
244
|
+
|
245
|
+
def test_include?
|
246
|
+
hash = TofuHash["a" => 2, "b" => 1]
|
247
|
+
assert( hash.include?( 'a' ))
|
248
|
+
end
|
249
|
+
|
250
|
+
def test_ri_include?
|
251
|
+
h = { "a" => 100, "b" => 200 }
|
252
|
+
assert( h.has_key?("a") )
|
253
|
+
assert_equal( false, h.has_key?("z"))
|
254
|
+
end
|
255
|
+
|
256
|
+
def test_ri_delete_if
|
257
|
+
h = TofuHash["a" => 100, "b" => 200, "c" => 300]
|
258
|
+
h.delete_if { |key,value| key >= 'b' }
|
259
|
+
assert_equal TofuHash['a' => 100], h
|
260
|
+
end
|
261
|
+
|
262
|
+
def test_delete_unless
|
263
|
+
hash = TofuHash["a" => 2, "b" => 1]
|
264
|
+
hash.delete_unless { |k,v| k == 'b' }
|
265
|
+
assert_equal TofuHash['b' => 1], hash
|
266
|
+
end
|
267
|
+
|
268
|
+
def test_ri_hash_equality
|
269
|
+
=begin
|
270
|
+
TODO: KNOWN ISSUE, Hash doesn't know how to compare to TofuHash.
|
271
|
+
|
272
|
+
h1 = TofuHash[ "a" => 1, "c" => 2 ]
|
273
|
+
h2 = { 7 => 35, "c" => 2, "a" => 1 }
|
274
|
+
h3 = TofuHash[ "a" => 1, "c" => 2, 7 => 35 ]
|
275
|
+
h4 = TofuHash[ "a" => 1, "d" => 2, "f" => 35 ]
|
276
|
+
puts "h1"
|
277
|
+
assert_equal( h1 == h2, false ) #=> false
|
278
|
+
puts "h2"
|
279
|
+
assert_equal( h2 == h3, true ) #=>
|
280
|
+
puts "h3"
|
281
|
+
assert_equal( h3 == h4, false ) #=> false
|
282
|
+
=end
|
283
|
+
end
|
284
|
+
end # class TestHash
|
285
|
+
end # module TofuHash
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.4
|
3
|
+
specification_version: 1
|
4
|
+
name: tofuhash
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2009-02-28 00:00:00 -06:00
|
8
|
+
summary: TofuHash, a Hash that is case-insensitive and treats symbols and strings as equals (customizable); always preserving the original key.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email:
|
12
|
+
homepage: http://tofuhash.rubyforge.org/
|
13
|
+
rubyforge_project: tofuhash
|
14
|
+
description: TofuHash, a Hash that is case-insensitive and treats symbols and strings as equals (customizable); always preserving the original key.
|
15
|
+
autorequire: tofuhash
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Gregory N. Houston
|
31
|
+
files:
|
32
|
+
- lib/tofuhash/tofuhash.rb
|
33
|
+
- lib/tofuhash/tofukey.rb
|
34
|
+
- lib/tofuhash.rb
|
35
|
+
- test/test-tofuhash.rb
|
36
|
+
- readme.txt
|
37
|
+
test_files:
|
38
|
+
- test/test-tofuhash.rb
|
39
|
+
rdoc_options:
|
40
|
+
- --main
|
41
|
+
- readme.txt
|
42
|
+
- --title
|
43
|
+
- TofuHash (rdoc)
|
44
|
+
extra_rdoc_files:
|
45
|
+
- readme.txt
|
46
|
+
executables: []
|
47
|
+
|
48
|
+
extensions: []
|
49
|
+
|
50
|
+
requirements: []
|
51
|
+
|
52
|
+
dependencies: []
|
53
|
+
|